[RFC,1/1] lib: add pdcp protocol

Message ID 20221027052140.155-2-anoobj@marvell.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series lib: add pdcp protocol |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS

Commit Message

Anoob Joseph Oct. 27, 2022, 5:21 a.m. UTC
  Add Packet Data Convergence Protocol (PDCP) processing library.

The library is similar to lib_ipsec which provides IPsec processing
capabilities in DPDK.

PDCP would involve roughly the following options,
1. Transfer of user plane data
2. Transfer of control plane data
3. Header compression
4. Uplink data compression
5. Ciphering and integrity protection

PDCP library provides following control path APIs that is used to
configure various PDCP entities,
1. rte_pdcp_establish()
2. rte_pdcp_suspend()
3. rte_pdcp_release()

PDCP process is split into 2 parts. One before crypto processing
(rte_pdcp_pkt_pre_process()) and one after crypto processing
(rte_pdcp_pkt_post_process()). Since cryptodev dequeue can return crypto
operations belonging to multiple entities, rte_pdcp_pkt_crypto_group()
is added to help grouping crypto operations beloning to same entity.

Signed-off-by: Anoob Joseph <anoobj@marvell.com>
Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
Signed-off-by: Volodymyr Fialko <vfialko@marvell.com>
---
 doc/api/doxy-api-index.md |   3 +-
 doc/api/doxy-api.conf.in  |   1 +
 lib/meson.build           |   1 +
 lib/pdcp/meson.build      |   7 ++
 lib/pdcp/rte_pdcp.h       | 244 ++++++++++++++++++++++++++++++++++++++
 lib/pdcp/rte_pdcp_group.h | 134 +++++++++++++++++++++
 lib/pdcp/version.map      |  13 ++
 7 files changed, 402 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
  

Patch

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index de488c7abf..42bcef9a17 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -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),
diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index f0886c3bd1..01314b087e 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -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 \
diff --git a/lib/meson.build b/lib/meson.build
index c51cdc24fa..15b7f77c68 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -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 = [
diff --git a/lib/pdcp/meson.build b/lib/pdcp/meson.build
new file mode 100644
index 0000000000..4c329cf57d
--- /dev/null
+++ b/lib/pdcp/meson.build
@@ -0,0 +1,7 @@ 
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#
+
+headers = files('rte_pdcp.h')
+
+deps += ['security']
diff --git a/lib/pdcp/rte_pdcp.h b/lib/pdcp/rte_pdcp.h
new file mode 100644
index 0000000000..3d2640240a
--- /dev/null
+++ b/lib/pdcp/rte_pdcp.h
@@ -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_ */
diff --git a/lib/pdcp/rte_pdcp_group.h b/lib/pdcp/rte_pdcp_group.h
new file mode 100644
index 0000000000..234d41e0a3
--- /dev/null
+++ b/lib/pdcp/rte_pdcp_group.h
@@ -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
diff --git a/lib/pdcp/version.map b/lib/pdcp/version.map
new file mode 100644
index 0000000000..b62361b47e
--- /dev/null
+++ b/lib/pdcp/version.map
@@ -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: *;
+};