@@ -125,7 +125,8 @@ The public API headers are grouped by topics:
[Geneve](@ref rte_geneve.h),
[eCPRI](@ref rte_ecpri.h),
[L2TPv2](@ref rte_l2tpv2.h),
- [PPP](@ref rte_ppp.h)
+ [PPP](@ref rte_ppp.h),
+ [PDCP](@ref rte_pdcp.h)
- **QoS**:
[metering](@ref rte_meter.h),
@@ -61,6 +61,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \
@TOPDIR@/lib/net \
@TOPDIR@/lib/pcapng \
@TOPDIR@/lib/pci \
+ @TOPDIR@/lib/pdcp \
@TOPDIR@/lib/pdump \
@TOPDIR@/lib/pipeline \
@TOPDIR@/lib/port \
@@ -63,6 +63,7 @@ libraries = [
'flow_classify', # flow_classify lib depends on pkt framework table lib
'graph',
'node',
+ 'pdcp', # pdcp lib depends on crypto and security
]
optional_libs = [
new file mode 100644
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#
+
+headers = files('rte_pdcp.h')
+
+deps += ['security']
new file mode 100644
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_H_
+#define _RTE_PDCP_H_
+
+/**
+ * @file rte_pdcp.h
+ *
+ * RTE PDCP support.
+ *
+ * librte_pdcp provides a framework for PDCP protocol processing.
+ */
+
+#include <rte_compat.h>
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_mempool.h>
+#include <rte_security.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declarations */
+
+struct rte_pdcp_entity;
+
+/* PDCP pre-process function based on entity configuration */
+typedef uint16_t (*rte_pdcp_pre_p_t)(const struct rte_pdcp_entity *entity,
+ struct rte_mbuf *mb[],
+ struct rte_crypto_op *cop[],
+ uint16_t num, uint16_t *nb_err);
+
+/* PDCP post-process function based on entity configuration */
+typedef uint16_t (*rte_pdcp_post_p_t)(const struct rte_pdcp_entity *entity,
+ struct rte_mbuf *in_mb[],
+ struct rte_mbuf *out_mb[],
+ uint16_t num, uint16_t *nb_err);
+
+/**
+ * PDCP entity.
+ */
+struct rte_pdcp_entity {
+ /** Entity specific pre-process handle */
+ rte_pdcp_pre_p_t pre_process;
+ /** Entity specific post-process handle */
+ rte_pdcp_post_p_t post_process;
+ /**
+ * PDCP entities may hold packets for purposes of in-order delivery (in
+ * case of receiving PDCP entity) and re-transmission (in case of
+ * transmitting PDCP entity).
+ *
+ * For receiving PDCP entity, it may hold packets when in-order
+ * delivery is enabled. The packets would be cached until either a
+ * packet that completes the sequence arrives or when discard timer
+ * expires.
+ *
+ * When post-processing of PDCP packet which completes a sequence is
+ * done, the API may return more packets than enqueued. Application is
+ * expected to provide @see rte_pdcp_pkt_post_process() with *out_mb*
+ * which can hold maximum number of packets which may be returned.
+ *
+ * For transmitting PDCP entity, during re-establishment (5.1.2),
+ * entity may be required to perform re-transmission of the buffers
+ * after applying new ciphering & integrity algorithms. For performing
+ * crypto operation, @see rte_pdcp_entity_re_establish() would return as
+ * many crypto_ops as the ones cached.
+ *
+ */
+ uint16_t max_pkt_cache;
+ /** User area for saving application data */
+ uint64_t user_area[2];
+} __rte_cache_aligned;
+
+struct rte_pdcp_entity_conf {
+ /** PDCP transform for the entity */
+ struct rte_security_pdcp_xform pdcp_xfrm;
+ /** Crypto transform applicable for the entity */
+ struct rte_crypto_sym_xform *crypto_xfrm;
+ /** Mempool for crypto symmetric session */
+ struct rte_mempool *sess_mpool;
+ /** Mempool for crypto symmetric session private part */
+ struct rte_mempool *sess_priv_mpool;
+ /** Crypto op pool*/
+ struct rte_mempool *cop_pool;
+ /**
+ * 32 bit count value (HFN + SN) to be used for the first packet.
+ * pdcp_xfrm.hfn would be ignored as the HFN would be derived from this value.
+ */
+ uint32_t count;
+ /** Indicate whether the PDCP entity belongs to Side Link Radio Bearer */
+ bool is_slrb;
+ /** Enable security offload on the device specified */
+ bool en_sec_offload;
+ /** Enable non-atomic usage of entity */
+ bool en_non_atomic;
+ /** Device on which security/crypto session need to be created */
+ uint8_t dev_id;
+};
+
+/**
+ * 5.1.1 PDCP entity establishment
+ *
+ * Establish PDCP entity based on provided input configuration.
+ *
+ * @param conf
+ * Parameters to be used for initializing PDCP entity object.
+ * @return
+ * - Valid handle if success
+ * - NULL in case of failure. rte_errno will be set to error code
+ */
+__rte_experimental
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf);
+
+/**
+ * 5.1.3 PDCP entity release
+ *
+ * Release PDCP entity.
+ *
+ * For UL/transmitting PDCP entity, all stored PDCP SDUs would be dropped.
+ * For DL/receiving PDCP entity, the stored PDCP SDUs would be returned in
+ * *out_mb* buffer. The buffer should be large enough to hold all cached
+ * packets in the entity.
+ *
+ * @param pdcp_entity
+ * Pointer to the PDCP entity to be released.
+ * @param[out] out_mb
+ * The address of an array that can hold up to *rte_pdcp_entity.max_pkt_cache*
+ * pointers to *rte_mbuf* structures.
+ * @return
+ * - 0: Success and no cached packets to return
+ * - >0: Success and the number of packets returned in out_mb
+ * - <0: Error code in case of failures
+ */
+__rte_experimental
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity,
+ struct rte_mbuf *out_mb[]);
+
+/**
+ * 5.1.4 PDCP entity suspend
+ *
+ * Suspend PDCP entity.
+ *
+ * For DL/receiving PDCP entity, the stored PDCP SDUs would be returned in
+ * *out_mb* buffer. The buffer should be large enough to hold all cached
+ * packets in the entity.
+ *
+ * @param pdcp_entity
+ * Pointer to the PDCP entity to be suspended.
+ * @param[out] out_mb
+ * The address of an array that can hold up to *rte_pdcp_entity.max_pkt_cache*
+ * pointers to *rte_mbuf* structures.
+ * @return
+ * - 0: Success and no cached packets to return
+ * - >0: Success and the number of packets returned in out_mb
+ * - <0: Error code in case of failures
+ */
+
+__rte_experimental
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+ struct rte_mbuf *out_mb[]);
+
+/**
+ * For input mbufs and given PDCP entity pre-process the mbufs and prepare
+ * crypto ops that can be enqueued to the cryptodev associated with given
+ * session. Only error packets would be moved returned in the input buffer,
+ * *mb*, and it is the responsibility of the application to free the same.
+ *
+ *
+ * @param entity
+ * Pointer to the *rte_pdcp_entity* object the packets belong to.
+ * @param[out] mb
+ * The address of an array of *num* pointers to *rte_mbuf* structures
+ * which contain the input packets. Any error packets would be returned in the
+ * same buffer.
+ * @param[out] cop
+ * The address of an array that can hold up to *num* pointers to
+ * *rte_crypto_op* structures.
+ * @param num
+ * The maximum number of packets to process.
+ * @param[out] nb_err
+ * Pointer to return the number of error packets returned in *mb*
+ * @return
+ * Count of crypto_ops prepared
+ */
+static inline uint16_t
+rte_pdcp_pkt_pre_process(const struct rte_pdcp_entity *entity,
+ struct rte_mbuf *mb[], struct rte_crypto_op *cop[],
+ uint16_t num, uint16_t *nb_err)
+{
+ return entity->pre_process(entity, mb, cop, num, nb_err);
+}
+
+/**
+ * For input mbufs and given PDCP entity, perform PDCP post-processing of the
+ * mbufs.
+ *
+ * Input mbufs are the ones retrieved from crypto_ops dequeued from cryptodev
+ * and grouped by @see rte_pdcp_pkt_crypto_group().
+ *
+ * The post-processed packets would be returned in the *out_mb* buffer.
+ * The resultant mbufs would be grouped into success packets and error packets.
+ * Error packets would be grouped in the end of the array and it is the
+ * responsibility of the application to handle the same.
+ *
+ * When in-order delivery is enabled, PDCP entity may buffer packets and would
+ * deliver packets only when all prior packets have been post-processed. That
+ * would result in returning more/less packets than enqueued.
+ *
+ * @param entity
+ * Pointer to the *rte_pdcp_entity* object the packets belong to.
+ * @param in_mb
+ * The address of an array of *num* pointers to *rte_mbuf* structures.
+ * @param[out] out_mb
+ * The address of an array of *num* pointers to *rte_mbuf* structures
+ * to output packets after PDCP post-processing.
+ * @param num
+ * The maximum number of packets to process.
+ * @param[out] nb_err
+ * The number of error packets returned in *out_mb* buffer.
+ * @return
+ * Count of packets returned in *out_mb* buffer.
+ */
+static inline uint16_t
+rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,
+ struct rte_mbuf *in_mb[],
+ struct rte_mbuf *out_mb[],
+ uint16_t num, uint16_t *nb_err)
+{
+ return entity->post_process(entity, in_mb, out_mb, num, nb_err);
+}
+
+#include <rte_pdcp_group.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDCP_H_ */
new file mode 100644
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_GROUP_H_
+#define _RTE_PDCP_GROUP_H_
+
+/**
+ * @file rte_pdcp_group.h
+ *
+ * RTE PDCP grouping support.
+ * It is not recommended to include this file directly, include <rte_pdcp.h>
+ * instead.
+ * Provides helper functions to process completed crypto-ops and group related
+ * packets by sessions they belong to.
+ */
+
+#include <rte_common.h>
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+#include <rte_security.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Group packets belonging to same PDCP entity.
+ */
+struct rte_pdcp_group {
+ union {
+ uint64_t val;
+ void *ptr;
+ } id; /**< Grouped by value */
+ struct rte_mbuf **m; /**< Start of the group */
+ uint32_t cnt; /**< Number of entries in the group */
+ int32_t rc; /**< Status code associated with the group */
+};
+
+/**
+ * Take crypto-op as an input and extract pointer to related PDCP entity.
+ * @param cop
+ * The address of an input *rte_crypto_op* structure.
+ * @return
+ * The pointer to the related *rte_pdcp_entity* structure.
+ */
+static inline struct rte_pdcp_entity *
+rte_pdcp_en_from_cop(const struct rte_crypto_op *cop)
+{
+ void *ses;
+
+ if (cop->sess_type == RTE_CRYPTO_OP_SECURITY_SESSION) {
+ ses = cop->sym[0].session;
+ return (struct rte_pdcp_entity *)(uintptr_t)
+ rte_security_session_opaque_data_get(ses);
+ } else if (cop->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
+ ses = cop->sym[0].session;
+ return (struct rte_pdcp_entity *)(uintptr_t)
+ rte_cryptodev_sym_session_opaque_data_get(ses);
+ }
+ return NULL;
+}
+
+/**
+ * Take as input completed crypto ops, extract related mbufs and group them by
+ * *rte_pdcp_entity* they belong to. Mbuf for which the crypto operation has
+ * failed would be flagged using *RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED* flag
+ * in rte_mbuf.ol_flags. The crypto_ops would be freed after the grouping.
+ *
+ * Note that application must ensure only crypto-ops prepared by lib_pdcp is
+ * provided back to *rte_pdcp_pkt_crypto_group()*.
+ *
+ * @param cop
+ * The address of an array of *num* pointers to the input *rte_crypto_op*
+ * structures.
+ * @param[out] mb
+ * The address of an array of *num* pointers to output *rte_mbuf* structures.
+ * @param[out] grp
+ * The address of an array of *num* to output *rte_pdcp_group* structures.
+ * @param num
+ * The maximum number of crypto-ops to process.
+ * @return
+ * Number of filled elements in *grp* array.
+ *
+ */
+static inline uint16_t
+rte_pdcp_pkt_crypto_group(struct rte_crypto_op *cop[], struct rte_mbuf *mb[],
+ struct rte_pdcp_group grp[], uint16_t num)
+{
+ uint32_t i, j = 0, n = 0;
+ void *ns, *ps = NULL;
+ struct rte_mbuf *m;
+
+ for (i = 0; i != num; i++) {
+ m = cop[i]->sym[0].m_src;
+ ns = cop[i]->sym[0].session;
+
+ m->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD;
+ if (cop[i]->status != RTE_CRYPTO_OP_STATUS_SUCCESS)
+ m->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
+
+ /* Different entity */
+ if (ps != ns) {
+
+ /* Finalize open group and start a new one */
+ if (ps != NULL) {
+ grp[n].cnt = mb + j - grp[n].m;
+ n++;
+ }
+
+ /* Start new group */
+ grp[n].m = mb + j;
+ ps = ns;
+ grp[n].id.ptr = rte_pdcp_en_from_cop(cop[i]);
+ }
+
+ mb[j++] = m;
+ rte_crypto_op_free(cop[i]);
+ }
+
+ /* Finalize last group */
+ if (ps != NULL) {
+ grp[n].cnt = mb + j - grp[n].m;
+ n++;
+ }
+
+ return n;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDCP_GROUP_H_ */
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,13 @@
+EXPERIMENTAL {
+ global:
+
+ # added in 23.03
+ rte_pdcp_entity_establish;
+ rte_pdcp_entity_release;
+ rte_pdcp_entity_suspend;
+
+ rte_pdcp_pkt_post_process;
+ rte_pdcp_pkt_pre_process;
+
+ local: *;
+};