Skip to contentSkip to conversation

lib: add pdcp protocol

RFC In review Anoob Joseph 5 participants 192 messages Oct 27, 2022 – Jun 12, 2023 Page 1 of 3

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover lib: add pdcp protocol

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 belonging to same entity.

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for *pre_process* and *post_process* based on features enabled in the entity.

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

Changes planned for next version
- Add APIs for rte_pdcp_entity_re_establish, rte_pdcp_entity_reconfigure
- Implementation for all APIs covering basic control plane & user plane packets
- Framework to handle control PDUs
- Unit test leveraging existing PDCP vectors available in test_cryptodev
- Eventdev based timer integration for t-Reordering & discardTimer
- Integration with reorder library to handle in-order delivery

Sample application sequence:

	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
	struct rte_crypto_op *cop[MAX_BURST_SIZE];
	struct rte_pdcp_group grp[MAX_BURST_SIZE];
	struct rte_pdcp_entity *pdcp_entity;
	int nb_max_out_mb, ret, nb_grp;

	/* Create PDCP entity */
	pdcp_entity = rte_pdcp_entity_establish(&conf);

	/**
	 * Allocate buffer for holding mbufs returned during PDCP suspend,
	 * release & post-process APIs.
	 */

	/* Max packets that can be cached in entity + burst size */
	nb_max_out_mb = pdcp_entity->max_pkt_cache + 1;
	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
	if (out_mb == NULL) {
		/* Handle error */
	}

	while (1) {
		/* Receive packet and form mbuf */

		/**
		 * Prepare packets for crypto operation. Following operations
		 * would be done,
		 *
		 * Transmiting entity/UL (only data PDUs):
		 *  - Perform compression
		 *  - Assign sequence number
		 *  - Add PDCP header
		 *  - Create & prepare crypto_op
		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
		 *  - Save original PDCP SDU (during PDCP re-establishment,
		 *    unconfirmed PDCP SDUs need to crypto processed again and
		 *    transmitted/re-transmitted)
		 *
		 *  Receiving entity/DL:
		 *  - Any control PDUs received would be processed and
		 *    appropriate actions taken. If data PDU, continue.
		 *  - Determine sequence number (based on HFN & per packet SN)
		 *  - Prepare crypto_op
		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
		 */
		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts, cop,
						      nb_rx, &nb_err);
		if (nb_err != 0) {
			/* Handle error packets */
		}

		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop, nb_success)
				!= nb_success) {
			/* Retry for enqueue failure packets */
		}

		...

		ret = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
						  MAX_BURST_SIZE);
		if (ret == 0)
			continue;

		/**
		 * Received a burst of completed crypto ops from cryptodev. It
		 * may belong to various entities. Group similar ones together
		 * for entity specific post-processing.
		 */

		/**
		 * Groups similar entities together. Frees crypto op and based
		 * on crypto_op status, set mbuf->ol_flags which would be
		 * checked in rte_pdcp_pkt_post_process().
		 */
		nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);

		for (i = 0; i != nb_grp; i++) {

			/**
			 * Post process packets after crypto completion.
			 * Following operations would be done,
			 *
			 *  Transmiting entity/UL:
			 *  - Check crypto result
			 *
			 *  Receiving entity/DL:
			 *  - Check crypto operation status
			 *  - Check for duplication (if yes, drop duplicate)
			 *  - Perform decompression
			 *  - Trim PDCP header
			 *  - Hold packet (SDU) for in-order delivery (return
			 *    completed packets as and when sequence is
			 *    completed)
			 *  - If not in sequence, cache the packet and start
			 *    t-Reordering timer. When timer expires, the
			 *    packets need to delivered to upper layers (not
			 *    treated as error packets).
			 */
			nb_success = rte_pdcp_pkt_post_process(grp[i].id.ptr,
							       grp[i].m, out_mb,
							       grp[i].cnt,
							       &nb_err);
			if (nb_err != 0) {
				/* Handle error packets */
			}

			/* Perform additional operations */

			/**
			 * Tranmitting entity/UL
			 * - If duplication is enabled, duplicate PDCP PDUs
			 * - When lower layers confirm reception of a PDCP PDU,
			 *   it should be communicated to PDCP layer so that
			 *   PDCP can drop the corresponding SDU
			 */
		}
	}

Anoob Joseph (1):
lib: add pdcp protocol

 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

--
2.28.0

#1 lore raw

RFC 1/1 lib: add pdcp protocol

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.

---
 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
doc/api/doxy-api-index.md +2 -1
index de488c7abf..42bcef9a17 100644
@@ -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),
doc/api/doxy-api.conf.in +1 -0
index f0886c3bd1..01314b087e 100644
@@ -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 \
lib/meson.build +1 -0
index c51cdc24fa..15b7f77c68 100644
@@ -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 = [
lib/pdcp/meson.build new file +7 -0
new file mode 100644
index 0000000000..4c329cf57d
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#
+
+headers = files('rte_pdcp.h')
+
+deps += ['security']
lib/pdcp/rte_pdcp.h new file +244 -0

244 lines not on this page · raw message

lib/pdcp/rte_pdcp_group.h new file +134 -0

135 lines not on this page · raw message

lib/pdcp/version.map new file +13 -0
new file mode 100644
index 0000000000..b62361b47e
@@ -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: *;
+};
Signature · 1 line
2.28.0
#2 lore raw
In reply to Anoob Joseph
Quoted 39 lines

Subject: [RFC 0/1] lib: add pdcp protocol

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 belonging to same entity.

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for *pre_process* and *post_process* based on features enabled in the entity.

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are
received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

Quoted 8 lines

Changes planned for next version
- Add APIs for rte_pdcp_entity_re_establish, rte_pdcp_entity_reconfigure
- Implementation for all APIs covering basic control plane & user plane packets
- Framework to handle control PDUs
- Unit test leveraging existing PDCP vectors available in test_cryptodev
- Eventdev based timer integration for t-Reordering & discardTimer
- Integration with reorder library to handle in-order delivery

Can you send the next version rebased over v22.11?
Also add documentation (pdcp.rst) file explaining about the new library. Add sample sequence also in that.

Do you also plan to add, header compression? I see that it is mentioned above, But there is no API as of now?

Quoted 142 lines

Sample application sequence:

	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
	struct rte_crypto_op *cop[MAX_BURST_SIZE];
	struct rte_pdcp_group grp[MAX_BURST_SIZE];
	struct rte_pdcp_entity *pdcp_entity;
	int nb_max_out_mb, ret, nb_grp;

	/* Create PDCP entity */
	pdcp_entity = rte_pdcp_entity_establish(&conf);

	/**
	 * Allocate buffer for holding mbufs returned during PDCP suspend,
	 * release & post-process APIs.
	 */

	/* Max packets that can be cached in entity + burst size */
	nb_max_out_mb = pdcp_entity->max_pkt_cache + 1;
	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
	if (out_mb == NULL) {
		/* Handle error */
	}

	while (1) {
		/* Receive packet and form mbuf */

		/**
		 * Prepare packets for crypto operation. Following operations
		 * would be done,
		 *
		 * Transmiting entity/UL (only data PDUs):
		 *  - Perform compression
		 *  - Assign sequence number
		 *  - Add PDCP header
		 *  - Create & prepare crypto_op
		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
		 *  - Save original PDCP SDU (during PDCP re-establishment,
		 *    unconfirmed PDCP SDUs need to crypto processed again

and
* transmitted/re-transmitted)
*
* Receiving entity/DL:
* - Any control PDUs received would be processed and
* appropriate actions taken. If data PDU, continue.
* - Determine sequence number (based on HFN & per packet
SN)

		 *  - Prepare crypto_op
		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
		 */
		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts, cop,
						      nb_rx, &nb_err);
		if (nb_err != 0) {
			/* Handle error packets */
		}

		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop,

nb_success)
!= nb_success) {
/* Retry for enqueue failure packets */
}

...

ret = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
MAX_BURST_SIZE);
if (ret == 0)
continue;

/**
* Received a burst of completed crypto ops from cryptodev. It
* may belong to various entities. Group similar ones together
* for entity specific post-processing.
*/

/**
* Groups similar entities together. Frees crypto op and based
* on crypto_op status, set mbuf->ol_flags which would be
* checked in rte_pdcp_pkt_post_process().
*/
nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);

for (i = 0; i != nb_grp; i++) {

/**
* Post process packets after crypto completion.
* Following operations would be done,
*
* Transmiting entity/UL:
* - Check crypto result
*
* Receiving entity/DL:
* - Check crypto operation status
* - Check for duplication (if yes, drop duplicate)
* - Perform decompression
* - Trim PDCP header
* - Hold packet (SDU) for in-order delivery (return
* completed packets as and when sequence is
* completed)
* - If not in sequence, cache the packet and start
* t-Reordering timer. When timer expires, the
* packets need to delivered to upper layers (not
* treated as error packets).
*/
nb_success = rte_pdcp_pkt_post_process(grp[i].id.ptr,
grp[i].m, out_mb, grp[i].cnt, &nb_err);
if (nb_err != 0) {
/* Handle error packets */
}

/* Perform additional operations */

/**
* Tranmitting entity/UL
* - If duplication is enabled, duplicate PDCP PDUs
* - When lower layers confirm reception of a PDCP
PDU,

			 *   it should be communicated to PDCP layer so that
			 *   PDCP can drop the corresponding SDU
			 */
		}
	}

Anoob Joseph (1):
lib: add pdcp protocol

 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

--
2.28.0

#3 lore raw

Hi Akhil,

Thanks for the review. Please see inline.

Thanks
Anoob

Quoted 62 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Tuesday, December 13, 2022 12:32 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]
Subject: RE: [RFC 0/1] lib: add pdcp protocol

Quoted 15 lines

Subject: [RFC 0/1] lib: add pdcp protocol

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()

Quoted 5 lines

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

belonging to same entity.

Quoted 6 lines

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for
*pre_process* and *post_process* based on features enabled in the

entity.

Quoted 9 lines

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

Quoted 11 lines

Changes planned for next version
- Add APIs for rte_pdcp_entity_re_establish, rte_pdcp_entity_reconfigure
- Implementation for all APIs covering basic control plane & user plane packets
- Framework to handle control PDUs
- Unit test leveraging existing PDCP vectors available in test_cryptodev
- Eventdev based timer integration for t-Reordering & discardTimer
- Integration with reorder library to handle in-order delivery

Quoted 3 lines

Can you send the next version rebased over v22.11?
Also add documentation (pdcp.rst) file explaining about the new library. Add sample sequence also in that.

[Anoob] Sure. Will send v1 with test application in another couple of days.

Quoted 3 lines

Do you also plan to add, header compression? I see that it is mentioned above, But there is no API as of now?

There are 2 kinds of compression when dealing with PDCP.
1. Header compression (which is more like a dictionary lookup)
2. UDC compression (which uses standard compression methods).

[Anoob] We have plans to support Item 1, ie, header compression. For item 2, we are evaluating the practical usage requirements to decide on whether PDCP lib would need to natively support it. Adding an interface to compressdev would increase the API requirements, but since it would come outside (& before) any of the proposed APIs, the feature can be added as a standalone item.

Quoted 150 lines
Quoted 40 lines

Sample application sequence:

	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
	struct rte_crypto_op *cop[MAX_BURST_SIZE];
	struct rte_pdcp_group grp[MAX_BURST_SIZE];
	struct rte_pdcp_entity *pdcp_entity;
	int nb_max_out_mb, ret, nb_grp;

	/* Create PDCP entity */
	pdcp_entity = rte_pdcp_entity_establish(&conf);

	/**
	 * Allocate buffer for holding mbufs returned during PDCP suspend,
	 * release & post-process APIs.
	 */

	/* Max packets that can be cached in entity + burst size */
	nb_max_out_mb = pdcp_entity->max_pkt_cache + 1;
	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
	if (out_mb == NULL) {
		/* Handle error */
	}

	while (1) {
		/* Receive packet and form mbuf */

		/**
		 * Prepare packets for crypto operation. Following operations
		 * would be done,
		 *
		 * Transmiting entity/UL (only data PDUs):
		 *  - Perform compression
		 *  - Assign sequence number
		 *  - Add PDCP header
		 *  - Create & prepare crypto_op
		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
		 *  - Save original PDCP SDU (during PDCP re-establishment,
		 *    unconfirmed PDCP SDUs need to crypto processed again
Quoted 7 lines

and
* transmitted/re-transmitted)
*
* Receiving entity/DL:
* - Any control PDUs received would be processed and
* appropriate actions taken. If data PDU, continue.
* - Determine sequence number (based on HFN & per

packet

Quoted 5 lines

SN)
* - Prepare crypto_op
* - Prepare IV for crypto operation (decrypt, auth_verify) */
nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts,

cop,

Quoted 13 lines
						      nb_rx, &nb_err);
		if (nb_err != 0) {
			/* Handle error packets */
		}

		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop,
nb_success)
				!= nb_success) {
			/* Retry for enqueue failure packets */
		}

		...
Quoted 7 lines
		ret = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
						  MAX_BURST_SIZE);
		if (ret == 0)
			continue;

		/**
		 * Received a burst of completed crypto ops from cryptodev.

It

Quoted 1 line

* may belong to various entities. Group similar ones

together

Quoted 5 lines
		 * for entity specific post-processing.
		 */

		/**
		 * Groups similar entities together. Frees crypto op and

based

Quoted 20 lines

* on crypto_op status, set mbuf->ol_flags which would be
* checked in rte_pdcp_pkt_post_process().
*/
nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);

for (i = 0; i != nb_grp; i++) {

/**
* Post process packets after crypto completion.
* Following operations would be done,
*
* Transmiting entity/UL:
* - Check crypto result
*
* Receiving entity/DL:
* - Check crypto operation status
* - Check for duplication (if yes, drop duplicate)
* - Perform decompression
* - Trim PDCP header
* - Hold packet (SDU) for in-order delivery (return

Quoted 8 lines

* completed packets as and when sequence is
* completed)
* - If not in sequence, cache the packet and start
* t-Reordering timer. When timer expires, the
* packets need to delivered to upper layers (not
* treated as error packets).
*/
nb_success =

rte_pdcp_pkt_post_process(grp[i].id.ptr,

Quoted 5 lines
							       grp[i].m, out_mb,
							       grp[i].cnt,
							       &nb_err);
			if (nb_err != 0) {
				/* Handle error packets */
Quoted 8 lines
			}

			/* Perform additional operations */

			/**
			 * Tranmitting entity/UL
			 * - If duplication is enabled, duplicate PDCP PDUs
			 * - When lower layers confirm reception of a PDCP

PDU,

Quoted 6 lines
			 *   it should be communicated to PDCP layer so that
			 *   PDCP can drop the corresponding SDU
			 */
		}
	}
Quoted 8 lines

Anoob Joseph (1):
lib: add pdcp protocol

 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

++++++++++++++++++++++++++++++++++++++

Quoted 9 lines
 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

--
2.28.0

#4 lore raw

cover lib: add pdcp protocol

In reply to Anoob Joseph

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_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 belonging to same entity.

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for *pre_process* and *post_process* based on features enabled in the entity.

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

Changes from RFC
- Implementation for all APIs covering basic control plane & user plane packets
- Unit test leveraging existing PDCP vectors available in test_cryptodev
- Unit test performing both UL & DL operations to verify various protocol features
- Updated documentation

Changes planned for next version
- Add APIs for rte_pdcp_entity_re_establish, rte_pdcp_entity_reconfigure
- Framework to handle control PDUs
- Eventdev based timer integration for t-Reordering & discardTimer
- Integration with reorder library to handle in-order delivery

Sample application sequence:

	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
	struct rte_crypto_op *cop[MAX_BURST_SIZE];
	struct rte_pdcp_group grp[MAX_BURST_SIZE];
	struct rte_pdcp_entity *pdcp_entity;
	int nb_max_out_mb, ret, nb_grp;

	/* Create PDCP entity */
	pdcp_entity = rte_pdcp_entity_establish(&conf);

	/**
	 * Allocate buffer for holding mbufs returned during PDCP suspend,
	 * release & post-process APIs.
	 */

	/* Max packets that can be cached in entity + burst size */
	nb_max_out_mb = pdcp_entity->max_pkt_cache + 1;
	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
	if (out_mb == NULL) {
		/* Handle error */
	}

	while (1) {
		/* Receive packet and form mbuf */

		/**
		 * Prepare packets for crypto operation. Following operations
		 * would be done,
		 *
		 * Transmitting entity/UL (only data PDUs):
		 *  - Perform compression
		 *  - Assign sequence number
		 *  - Add PDCP header
		 *  - Create & prepare crypto_op
		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
		 *  - Save original PDCP SDU (during PDCP re-establishment,
		 *    unconfirmed PDCP SDUs need to crypto processed again and
		 *    transmitted/re-transmitted)
		 *
		 *  Receiving entity/DL:
		 *  - Any control PDUs received would be processed and
		 *    appropriate actions taken. If data PDU, continue.
		 *  - Determine sequence number (based on HFN & per packet SN)
		 *  - Prepare crypto_op
		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
		 */
		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts, cop,
						      nb_rx, &nb_err);
		if (nb_err != 0) {
			/* Handle error packets */
		}

		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop, nb_success)
				!= nb_success) {
			/* Retry for enqueue failure packets */
		}

		...

		ret = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
						  MAX_BURST_SIZE);
		if (ret == 0)
			continue;

		/**
		 * Received a burst of completed crypto ops from cryptodev. It
		 * may belong to various entities. Group similar ones together
		 * for entity specific post-processing.
		 */

		/**
		 * Groups similar entities together. Frees crypto op and based
		 * on crypto_op status, set mbuf->ol_flags which would be
		 * checked in rte_pdcp_pkt_post_process().
		 */
		nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);

		for (i = 0; i != nb_grp; i++) {

			/**
			 * Post process packets after crypto completion.
			 * Following operations would be done,
			 *
			 *  Transmitting entity/UL:
			 *  - Check crypto result
			 *
			 *  Receiving entity/DL:
			 *  - Check crypto operation status
			 *  - Check for duplication (if yes, drop duplicate)
			 *  - Perform decompression
			 *  - Trim PDCP header
			 *  - Hold packet (SDU) for in-order delivery (return
			 *    completed packets as and when sequence is
			 *    completed)
			 *  - If not in sequence, cache the packet and start
			 *    t-Reordering timer. When timer expires, the
			 *    packets need to delivered to upper layers (not
			 *    treated as error packets).
			 */
			nb_success = rte_pdcp_pkt_post_process(grp[i].id.ptr,
							       grp[i].m, out_mb,
							       grp[i].cnt,
							       &nb_err);
			if (nb_err != 0) {
				/* Handle error packets */
			}

			/* Perform additional operations */

			/**
			 * Tranmitting entity/UL
			 * - If duplication is enabled, duplicate PDCP PDUs
			 * - When lower layers confirm reception of a PDCP PDU,
			 *   it should be communicated to PDCP layer so that
			 *   PDCP can drop the corresponding SDU
			 */
		}
	}

Anoob Joseph (3):
lib: add pdcp protocol
app/test: add lib pdcp tests
doc: add PDCP library guide

Volodymyr Fialko (2):
net: add PDCP header
app/test: pdcp HFN tests in combined mode

 app/test/meson.build                          |    1 +
 app/test/test_cryptodev.h                     |    3 +
 app/test/test_pdcp.c                          |  999 ++++++++++++++
 doc/api/doxy-api-index.md                     |    4 +-
 doc/api/doxy-api.conf.in                      |    1 +
 .../img/pdcp_functional_overview.svg          |    1 +
 doc/guides/prog_guide/index.rst               |    1 +
 doc/guides/prog_guide/pdcp_lib.rst            |  211 +++
 lib/meson.build                               |    1 +
 lib/net/meson.build                           |    1 +
 lib/net/rte_pdcp_hdr.h                        |   93 ++
 lib/pdcp/meson.build                          |    8 +
 lib/pdcp/pdcp_crypto.c                        |  240 ++++
 lib/pdcp/pdcp_crypto.h                        |   20 +
 lib/pdcp/pdcp_entity.h                        |  218 +++
 lib/pdcp/pdcp_process.c                       | 1195 +++++++++++++++++
 lib/pdcp/pdcp_process.h                       |   13 +
 lib/pdcp/rte_pdcp.c                           |  136 ++
 lib/pdcp/rte_pdcp.h                           |  263 ++++
 lib/pdcp/rte_pdcp_group.h                     |  133 ++
 lib/pdcp/version.map                          |   13 +
 21 files changed, 3554 insertions(+), 1 deletion(-)
 create mode 100644 app/test/test_pdcp.c
 create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg
 create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
 create mode 100644 lib/net/rte_pdcp_hdr.h
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
Signature · 1 line
2.25.1
#5 lore raw

PATCH 1/5 net: add PDCP header

From: Volodymyr Fialko <[email protected]>

Added PDCP protocol header to be used for supporting PDCP protocol processing.

---
 doc/api/doxy-api-index.md |  3 +-
 lib/net/meson.build       |  1 +
 lib/net/rte_pdcp_hdr.h    | 93 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 1 deletion(-)
 create mode 100644 lib/net/rte_pdcp_hdr.h
doc/api/doxy-api-index.md +2 -1
index de488c7abf..ae4b107240 100644
@@ -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 hdr](@ref rte_pdcp_hdr.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
lib/net/meson.build +1 -0
index 379d161ee0..bd56f91c22 100644
@@ -22,6 +22,7 @@ headers = files(
         'rte_geneve.h',
         'rte_l2tpv2.h',
         'rte_ppp.h',
+        'rte_pdcp_hdr.h',
 )
 
 sources = files(
lib/net/rte_pdcp_hdr.h new file +93 -0

93 lines not on this page · raw message

Signature · 1 line
2.25.1
#6 lore raw

Re: [PATCH 1/5] net: add PDCP header

22/12/2022 10:25, Anoob Joseph:

lib/net/rte_pdcp_hdr.h line 6

Quoted 9 lines
lib/net/rte_pdcp_hdr.h new file +6 -0
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_HDR_H_
+#define _RTE_PDCP_HDR_H_

No need of extra underscores before and after.

Sorry I cannot review the rest of this, it is out of my knowledge :)

#7 lore raw

RE: [EXT] Re: [PATCH 1/5] net: add PDCP header

Hi Thomas,

Please see inline.

Thanks,
Anoob

Quoted 6 lines

Subject: [EXT] Re: [PATCH 1/5] net: add PDCP header

External Email

----------------------------------------------------------------------
22/12/2022 10:25, Anoob Joseph:

Quoted 11 lines

lib/net/rte_pdcp_hdr.h line 6

Quoted 9 lines
lib/net/rte_pdcp_hdr.h new file +6 -0
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_HDR_H_
+#define _RTE_PDCP_HDR_H_

No need of extra underscores before and after.

[Anoob] I was following the example quoted in https://doc.dpdk.org/guides/contributing/coding_style.html. Also, other files such as rte_esp.h, rte_udp.h, etc. follow the same.

Isn't it better to have a uniform coding style?

#8 lore raw

Re: [EXT] Re: [PATCH 1/5] net: add PDCP header

18/01/2023 18:39, Anoob Joseph:

Quoted 13 lines
Quoted 12 lines

22/12/2022 10:25, Anoob Joseph:

lib/net/rte_pdcp_hdr.h line 6

Quoted 9 lines
lib/net/rte_pdcp_hdr.h new file +6 -0
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_HDR_H_
+#define _RTE_PDCP_HDR_H_

No need of extra underscores before and after.

Quoted 1 line

[Anoob] I was following the example quoted in https://doc.dpdk.org/guides/contributing/coding_style.html.

Oh thanks for the reference, I will fix it.

Quoted 1 line

Also, other files such as rte_esp.h, rte_udp.h, etc. follow the same.

Some other files don't have underscores.

Quoted 1 line

Isn't it better to have a uniform coding style?

No really I prefer no underscores,
they are supposed to be used for standard libraries.

#9 lore raw

RE: [EXT] Re: [PATCH 1/5] net: add PDCP header

Hi Thomas,

Please see inline.

Thanks,
Anoob

Quoted 26 lines

Subject: Re: [EXT] Re: [PATCH 1/5] net: add PDCP header

18/01/2023 18:39, Anoob Joseph:

Quoted 13 lines
Quoted 12 lines

22/12/2022 10:25, Anoob Joseph:

lib/net/rte_pdcp_hdr.h line 6

Quoted 9 lines
lib/net/rte_pdcp_hdr.h new file +6 -0
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_HDR_H_
+#define _RTE_PDCP_HDR_H_

No need of extra underscores before and after.

Quoted 1 line

[Anoob] I was following the example quoted in

https://urldefense.proofpoint.com/v2/url?u=https-
3A__doc.dpdk.org_guides_contributing_coding- 5Fstyle.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=jPfB8rwwviRSxyL Ws2n6B-WYLn1v9SyTMrT5EQqh2TU&m=Btr0wWqHo_dHGchyRWTnjO6xY- 7p33pUSKSBLIXtL4DOAv-GsZmL2lZ2OHyJWoiZ&s=- AQhSWF0bWFXTyxL0rPCW6fz6I7GYhwyQ9qjYG3FFn0&e= .

Oh thanks for the reference, I will fix it.

Quoted 8 lines
Quoted 1 line

Also, other files such as rte_esp.h, rte_udp.h, etc. follow the same.

Some other files don't have underscores.

Quoted 1 line

Isn't it better to have a uniform coding style?

No really I prefer no underscores,
they are supposed to be used for standard libraries.

[Anoob] I see that most of the files do have underscores. While I do not have any personal preference, I would really prefer new code to not stand out from the rest. If you have considered this already, then I'll make the change in next version. Please confirm.

#10 lore raw

Re: [EXT] Re: [PATCH 1/5] net: add PDCP header

23/01/2023 10:21, Anoob Joseph:

Quoted 35 lines

Hi Thomas,

Please see inline.

Thanks,
Anoob

Quoted 28 lines

Subject: Re: [EXT] Re: [PATCH 1/5] net: add PDCP header

18/01/2023 18:39, Anoob Joseph:

Quoted 13 lines
Quoted 12 lines

22/12/2022 10:25, Anoob Joseph:

lib/net/rte_pdcp_hdr.h line 6

Quoted 9 lines
lib/net/rte_pdcp_hdr.h new file +6 -0
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_HDR_H_
+#define _RTE_PDCP_HDR_H_

No need of extra underscores before and after.

Quoted 1 line

[Anoob] I was following the example quoted in

https://urldefense.proofpoint.com/v2/url?u=https-
3A__doc.dpdk.org_guides_contributing_coding- 5Fstyle.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=jPfB8rwwviRSxyL Ws2n6B-WYLn1v9SyTMrT5EQqh2TU&m=Btr0wWqHo_dHGchyRWTnjO6xY- 7p33pUSKSBLIXtL4DOAv-GsZmL2lZ2OHyJWoiZ&s=- AQhSWF0bWFXTyxL0rPCW6fz6I7GYhwyQ9qjYG3FFn0&e= .

Oh thanks for the reference, I will fix it.

Quoted 1 line

Also, other files such as rte_esp.h, rte_udp.h, etc. follow the same.

Quoted 8 lines
Quoted 6 lines

Some other files don't have underscores.

Quoted 1 line

Isn't it better to have a uniform coding style?

No really I prefer no underscores,
they are supposed to be used for standard libraries.

[Anoob] I see that most of the files do have underscores. While I do not have any personal preference, I would really prefer new code to not stand out from the rest. If you have considered this already, then I'll make the change in next version. Please confirm.

I prefer no underscore, and I will probably propose to change all files while updating the contributing guide.
For new patch, I gave my opinion, now you can choose it is not a big deal.

#11 lore raw

PATCH 2/5 lib: add pdcp protocol

In reply to Anoob Joseph

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_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 belonging to same entity.

---
 doc/api/doxy-api-index.md |    3 +-
 doc/api/doxy-api.conf.in  |    1 +
 lib/meson.build           |    1 +
 lib/pdcp/meson.build      |    8 +
 lib/pdcp/pdcp_crypto.c    |  240 ++++++++
 lib/pdcp/pdcp_crypto.h    |   20 +
 lib/pdcp/pdcp_entity.h    |  218 +++++++
 lib/pdcp/pdcp_process.c   | 1195 +++++++++++++++++++++++++++++++++++++
 lib/pdcp/pdcp_process.h   |   13 +
 lib/pdcp/rte_pdcp.c       |  136 +++++
 lib/pdcp/rte_pdcp.h       |  263 ++++++++
 lib/pdcp/rte_pdcp_group.h |  133 +++++
 lib/pdcp/version.map      |   13 +
 13 files changed, 2243 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
doc/api/doxy-api-index.md +2 -1
index ae4b107240..6014bee079 100644
@@ -126,7 +126,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h),
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in +1 -0
index f0886c3bd1..01314b087e 100644
@@ -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 \
lib/meson.build +1 -0
index fd55925340..a827006d29 100644
@@ -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 = [
lib/pdcp/meson.build new file +8 -0
new file mode 100644
index 0000000000..a7f5a408cf
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#
+
+sources = files('pdcp_crypto.c', 'pdcp_process.c', 'rte_pdcp.c')
+headers = files('rte_pdcp.h')
+
+deps += ['security']
lib/pdcp/pdcp_crypto.c new file +240 -0

240 lines not on this page · raw message

lib/pdcp/pdcp_crypto.h new file +20 -0
new file mode 100644
index 0000000000..dc625b35d0
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_CRYPTO_H_
+#define _PDCP_CRYPTO_H_
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_pdcp.h>
+
+#define PDCP_IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op))
+#define PDCP_IV_LENGTH 16
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+int pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* _PDCP_CRYPTO_H_ */
lib/pdcp/pdcp_entity.h new file +218 -0

218 lines not on this page · raw message

lib/pdcp/pdcp_process.c new file +1195 -0

1,195 lines not on this page · raw message

lib/pdcp/pdcp_process.h new file +13 -0
new file mode 100644
index 0000000000..c92ab34c40
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_PROCESS_H_
+#define _PDCP_PROCESS_H_
+
+#include <rte_pdcp.h>
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf);
+
+#endif /* _PDCP_PROCESS_H_ */
lib/pdcp/rte_pdcp.c new file +136 -0

136 lines not on this page · raw message

lib/pdcp/rte_pdcp.h new file +263 -0

263 lines not on this page · raw message

lib/pdcp/rte_pdcp_group.h new file +133 -0

133 lines not on this page · raw message

lib/pdcp/version.map new file +13 -0
new file mode 100644
index 0000000000..8fa9d5d7cc
@@ -0,0 +1,13 @@
+EXPERIMENTAL {
+	global:
+
+	# added in 22.11
+	rte_pdcp_entity_establish;
+	rte_pdcp_entity_release;
+	rte_pdcp_entity_suspend;
+
+	rte_pdcp_pkt_post_process;
+	rte_pdcp_pkt_pre_process;
+
+	local: *;
+};
Signature · 1 line
2.25.1
#12 lore raw

Hi Anoob,

Please see inline comments.

Quoted 100 lines

Subject: [PATCH 2/5] lib: add pdcp protocol

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_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 belonging to same entity.

---
 doc/api/doxy-api-index.md |    3 +-
 doc/api/doxy-api.conf.in  |    1 +
 lib/meson.build           |    1 +
 lib/pdcp/meson.build      |    8 +
 lib/pdcp/pdcp_crypto.c    |  240 ++++++++
 lib/pdcp/pdcp_crypto.h    |   20 +
 lib/pdcp/pdcp_entity.h    |  218 +++++++
 lib/pdcp/pdcp_process.c   | 1195 +++++++++++++++++++++++++++++++++++++
 lib/pdcp/pdcp_process.h   |   13 +
 lib/pdcp/rte_pdcp.c       |  136 +++++
 lib/pdcp/rte_pdcp.h       |  263 ++++++++
 lib/pdcp/rte_pdcp_group.h |  133 +++++
 lib/pdcp/version.map      |   13 +
 13 files changed, 2243 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
doc/api/doxy-api-index.md +2 -1
index ae4b107240..6014bee079 100644
@@ -126,7 +126,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h),
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in +1 -0
index f0886c3bd1..01314b087e 100644
@@ -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 \
lib/meson.build +1 -0
index fd55925340..a827006d29 100644
@@ -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 = [
lib/pdcp/meson.build new file +0 -0
new file mode 100644
index 0000000000..a7f5a408cf

lib/pdcp/meson.build line 3

Quoted 3 lines
lib/pdcp/meson.build new file +3 -0
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#

Extra # here.

Do we support compilation on Windows as well?
Check missing here.

lib/pdcp/meson.build line 6

Quoted 3 lines
lib/pdcp/meson.build new file +3 -0
+
+sources = files('pdcp_crypto.c', 'pdcp_process.c', 'rte_pdcp.c')
+headers = files('rte_pdcp.h')

Do we need to add the indirect header as well for lib/pdcp/rte_pdcp_group.h?

lib/pdcp/meson.build line 8

Quoted 2 lines
lib/pdcp/meson.build new file +2 -0
+
+deps += ['security']

Crypto not needed as dependency?

Quoted 143 lines
lib/pdcp/pdcp_crypto.c new file +14 -0
new file mode 100644
index 0000000000..7ffb8a07a7
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_pdcp.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+
+static int
+pdcp_crypto_caps_cipher_verify(uint8_t dev_id, const struct

rte_crypto_sym_xform *c_xfrm)

lib/pdcp/pdcp_crypto.c new file +13 -0
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+	cap_idx.algo.cipher = c_xfrm->cipher.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_cipher(cap, c_xfrm-
Quoted 1 line

cipher.key.length,

lib/pdcp/pdcp_crypto.c new file +1 -0
+							c_xfrm-
Quoted 1 line

cipher.iv.length);

lib/pdcp/pdcp_crypto.c new file +6 -0
+
+	return ret;
+}
+
+static int
+pdcp_crypto_caps_auth_verify(uint8_t dev_id, const struct

rte_crypto_sym_xform *a_xfrm)

lib/pdcp/pdcp_crypto.c new file +13 -0
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+	cap_idx.algo.auth = a_xfrm->auth.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_auth(cap, a_xfrm-
Quoted 1 line

auth.key.length,

lib/pdcp/pdcp_crypto.c new file +1 -0
+						      a_xfrm-
Quoted 1 line

auth.digest_length,

lib/pdcp/pdcp_crypto.c new file +16 -0
+						      a_xfrm->auth.iv.length);
+
+	return ret;
+}
+
+static int
+pdcp_crypto_xfrm_validate(const struct rte_pdcp_entity_conf *conf,
+				 const struct rte_crypto_sym_xform *c_xfrm,
+				 const struct rte_crypto_sym_xform *a_xfrm,
+				 bool is_auth_then_cipher)
+{
+	uint16_t ciph_iv_len, auth_digest_len, auth_iv_len;
+	int ret;
+
+	/*
+	 * Uplink means PDCP entity is configured for transmit. Downlink means

PDCP entity is

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * configured for receive. When integrity protection is enabled, PDCP

always performs

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * digest-encrypted or auth-gen-encrypt for uplink (and decrypt-auth-

verify for downlink).

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * So for uplink, crypto chain would be auth-cipher while for downlink it

would be

lib/pdcp/pdcp_crypto.c new file +20 -0
+	 * cipher-auth.
+	 *
+	 * When integrity protection is not required, xform would be cipher only.
+	 */
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK) {
+
+		/* With UPLINK, if auth is enabled, it should be before cipher */
+		if (a_xfrm != NULL && !is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With UPLINK, cipher operation must be encrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_ENCRYPT)
+			return -EINVAL;
+
+		/* With UPLINK, auth operation (if present) must be generate */
+		if (a_xfrm != NULL && a_xfrm->auth.op !=

RTE_CRYPTO_AUTH_OP_GENERATE)

lib/pdcp/pdcp_crypto.c new file +3 -0
+			return -EINVAL;
+
+	} else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)

{

lib/pdcp/pdcp_crypto.c new file +2 -0
+
+		/* With DOWNLINK, if auth is enabled, it should be after cipher

*/

lib/pdcp/pdcp_crypto.c new file +8 -0
+		if (a_xfrm != NULL && is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With DOWNLINK, cipher operation must be decrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_DECRYPT)
+			return -EINVAL;
+
+		/* With DOWNLINK, auth operation (if present) must be verify

*/

lib/pdcp/pdcp_crypto.c new file +1 -0
+		if (a_xfrm != NULL && a_xfrm->auth.op !=

RTE_CRYPTO_AUTH_OP_VERIFY)

lib/pdcp/pdcp_crypto.c new file +21 -0
+			return -EINVAL;
+
+	} else {
+		return -EINVAL;
+	}
+
+	if ((c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_NULL) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_AES_CTR) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_ZUC_EEA3) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2))
+		return -EINVAL;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
+		ciph_iv_len = 0;
+	else
+		ciph_iv_len = PDCP_IV_LENGTH;
+
+	if (ciph_iv_len != c_xfrm->cipher.iv.length)
+		return -EINVAL;
+
+	if (a_xfrm != NULL) {

lib/pdcp/pdcp_crypto.c line 132

Quoted 10 lines
lib/pdcp/pdcp_crypto.c new file +10 -0
+		if ((a_xfrm->auth.algo != RTE_CRYPTO_AUTH_NULL) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_AES_CMAC) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_ZUC_EIA3) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2))
+			return -EINVAL;
+
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			auth_digest_len = 0;
+		else
+			auth_digest_len = 4;

If we have a macro for IV length, why not for digest also?
Moreover, for NULL integrity, digest length is also 4 with all 0s.
Refer Annex D.1 in https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/15.04.00_60/ts_133501v150400p.pdf

Digest len would be 0 only in case of a_xfrm == NULL

Quoted 177 lines
lib/pdcp/pdcp_crypto.c new file +32 -0
+
+		if (auth_digest_len != a_xfrm->auth.digest_length)
+			return -EINVAL;
+
+		if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2))
+			auth_iv_len = PDCP_IV_LENGTH;
+		else
+			auth_iv_len = 0;
+
+		if (a_xfrm->auth.iv.length != auth_iv_len)
+			return -EINVAL;
+	}
+
+	if (!rte_cryptodev_is_valid_dev(conf->dev_id))
+		return -EINVAL;
+
+	ret = pdcp_crypto_caps_cipher_verify(conf->dev_id, c_xfrm);
+	if (ret)
+		return -ENOTSUP;
+
+	if (a_xfrm != NULL) {
+		ret = pdcp_crypto_caps_auth_verify(conf->dev_id, a_xfrm);
+		if (ret)
+			return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+int
+pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_crypto.c new file +18 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	struct entity_priv *en_priv;
+	bool is_auth_then_cipher;
+	int ret;
+
+	if (entity == NULL || conf == NULL || conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->dev_id = conf->dev_id;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		c_xfrm = conf->crypto_xfrm;
+		a_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = false;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_crypto.c new file +8 -0
+		a_xfrm = conf->crypto_xfrm;
+		c_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = true;
+	} else {
+		return -EINVAL;
+	}
+
+	ret = pdcp_crypto_xfrm_validate(conf, c_xfrm, a_xfrm,

is_auth_then_cipher);

lib/pdcp/pdcp_crypto.c new file +14 -0
+	if (ret)
+		return ret;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
+		c_xfrm->cipher.iv.offset = 0;
+	else
+		c_xfrm->cipher.iv.offset = PDCP_IV_OFFSET;
+
+	if (a_xfrm != NULL) {
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm->auth.iv.offset = 0;
+		else
+			if (c_xfrm->cipher.iv.offset)
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET +

PDCP_IV_LENGTH;

lib/pdcp/pdcp_crypto.c new file +8 -0
+			else
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET;
+	}
+
+	if (conf->sess_mpool == NULL)
+		return -EINVAL;
+
+	en_priv->crypto_sess = rte_cryptodev_sym_session_create(conf-
Quoted 1 line

dev_id, conf->crypto_xfrm,

lib/pdcp/pdcp_crypto.c new file +1 -0
+								conf-
Quoted 1 line

sess_mpool);

lib/pdcp/pdcp_crypto.c new file +6 -0
+	if (en_priv->crypto_sess == NULL) {
+		/* API returns positive values as error codes */
+		return -rte_errno;
+	}
+
+	rte_cryptodev_sym_session_opaque_data_set(en_priv->crypto_sess,

(uint64_t)entity);

lib/pdcp/pdcp_crypto.c new file +16 -0
+
+	return 0;
+}
+
+int
+pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
+{
+	struct entity_priv *en_priv;
+
+	if (entity == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	if (en_priv->crypto_sess != NULL) {
+		rte_cryptodev_sym_session_free(en_priv->dev_id, en_priv-
Quoted 1 line

crypto_sess);

lib/pdcp/pdcp_crypto.c new file +5 -0
+		en_priv->crypto_sess = NULL;
+	}
+
+	return 0;
+}
lib/pdcp/pdcp_crypto.h new file +12 -0
new file mode 100644
index 0000000000..dc625b35d0
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_CRYPTO_H_
+#define _PDCP_CRYPTO_H_
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_pdcp.h>
+
+#define PDCP_IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct

rte_crypto_sym_op))

lib/pdcp/pdcp_crypto.h new file +8 -0
+#define PDCP_IV_LENGTH 16
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+int pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* _PDCP_CRYPTO_H_ */
lib/pdcp/pdcp_entity.h new file +25 -0
new file mode 100644
index 0000000000..e312fd4a8c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_ENTITY_H_
+#define _PDCP_ENTITY_H_
+
+#include <rte_common.h>
+#include <rte_crypto_sym.h>
+#include <rte_mempool.h>
+#include <rte_pdcp.h>
+#include <rte_security.h>
+
+struct entity_priv;
+
+#define PDCP_PDU_HDR_SIZE_SN_12 (RTE_ALIGN_MUL_CEIL(12, 8) / 8)
+#define PDCP_PDU_HDR_SIZE_SN_18 (RTE_ALIGN_MUL_CEIL(18, 8) / 8)
+
+#define PDCP_GET_SN_12_FROM_COUNT(c) ((c) & 0xfff)
+#define PDCP_GET_SN_18_FROM_COUNT(c) ((c) & 0x3ffff)
+
+#define PDCP_GET_HFN_SN_12_FROM_COUNT(c) (((c) >> 12) & 0xfffff)
+#define PDCP_GET_HFN_SN_18_FROM_COUNT(c) (((c) >> 18) & 0x3fff)
+
+#define PDCP_SET_COUNT_FROM_HFN_SN_12(h, s) ((((h) & 0xfffff) << 12) | ((s)

& 0xfff))
+#define PDCP_SET_COUNT_FROM_HFN_SN_18(h, s) ((((h) & 0x3fff) << 18) | ((s) & 0x3ffff))

lib/pdcp/pdcp_entity.h line 35

Quoted 9 lines
lib/pdcp/pdcp_entity.h new file +9 -0
+
+#define PDCP_SN_12_WINDOW_SZ 0x800
+#define PDCP_SN_18_WINDOW_SZ 0x20000
+
+#define PDCP_SN_12_HFN_MAX ((1 << (32 - 12)) - 1)
+#define PDCP_SN_12_HFN_MIN 0
+#define PDCP_SN_18_HFN_MAX ((1 << (32 - 18)) - 1)
+#define PDCP_SN_18_HFN_MIN 0
+

Can we have common defines for SN-12 and SN-18 and take SN as parameter? We can have something like this.

#define PDCP_PDU_HDR_SIZE(sn_size) (RTE_ALIGN_MUL_CEIL((sn_size), 8) / 8)
#define PDCP_GET_SN_FROM_COUNT(c, sn_size) ((c) & ((1<<sn_size)-1))
#define PDCP_GET_HFN_FROM_COUNT(c, sn_size) (((c) >> sn_size) & ((1 << (32 - sn_size)) - 1))
#define PDCP_SET_COUNT_FROM_HFN_SN(h, s, sn_size) ((((h) & ((1 << (32 - sn_size)) - 1)) << sn_size) | ((s) & ((1<<sn_size)-1))) #define PDCP_HFN_MAX(sn_size) ((1 << (32 - (sn_size))) - 1)
#define PDCP_HFN_MIN 0

Quoted 79 lines
lib/pdcp/pdcp_entity.h new file +2 -0
+/* IV generation function based on the entity configuration */
+typedef void (*iv_gen_t)(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_entity.h new file +76 -0
+			 uint32_t count);
+
+enum pdcp_pdu_type {
+	PDCP_PDU_TYPE_CTRL = 0,
+	PDCP_PDU_TYPE_DATA = 1,
+};
+
+enum pdcp_up_ctrl_pdu_type {
+	PDCP_UP_CTRL_PDU_TYPE_STATUS_REPORT,
+	PDCP_UP_CTRL_PDU_TYPE_ROHC_FEEDBACK,
+	PDCP_UP_CTRL_PDU_TYPE_EHC_FEEDBACK,
+	PDCP_UP_CRTL_PDU_TYPE_UDC_FEEDBACK
+};
+
+struct entity_state {
+	uint32_t rx_next;
+	uint32_t tx_next;
+	uint32_t rx_deliv;
+	uint32_t rx_reord;
+};
+
+union auth_iv_partial {
+	/* For AES-CMAC, there is no IV, but message gets prepended */
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+	} aes_cmac;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_37_39 : 3;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_65_71 : 7;
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_120_127 : 8;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t zero_37_39 : 3;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_65_71 : 7;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t rsvd_120_127 : 8;
+#endif
+	} zs;
+	uint64_t u64[2];
+};
+
+union cipher_iv_partial {
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;

lib/pdcp/pdcp_entity.h line 123

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+
+		uint64_t zero_64_127;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t zero_64_127;

Can we take zero_64_127 out of #if-else

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+#endif
+	} aes_ctr;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+

lib/pdcp/pdcp_entity.h line 143

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+		uint64_t rsvd_64_127;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_64_127;
+#endif

rsvd_64_127 can also be out of #if-else

lib/pdcp/pdcp_entity.h line 149

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+	} zs;
+	uint64_t u64[2];
+};
+
+/*
+ * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]

If the layout is fixed, can we have 0 length array in rte_pdcp_entity for entity_priv and in entity_priv for entity_dl/ul. I see that entity_dl/ul are not completely defined. You can define them later when they are supported.

Quoted 2 lines

+ */
+

Extra line

Quoted 62 lines
lib/pdcp/pdcp_entity.h new file +27 -0
+struct entity_priv {
+	/** Crypto sym session. */
+	struct rte_cryptodev_sym_session *crypto_sess;
+	/** Entity specific IV generation function. */
+	iv_gen_t iv_gen;
+	/** Pre-prepared auth IV. */
+	union auth_iv_partial auth_iv_part;
+	/** Pre-prepared cipher IV. */
+	union cipher_iv_partial cipher_iv_part;
+	/** Entity state variables. */
+	struct entity_state state;
+	/** Flags. */
+	struct {
+		/** PDCP PDU has 4 byte MAC-I. */
+		uint64_t is_authenticated : 1;
+		/** Cipher offset & length in bits. */
+		uint64_t is_ciph_in_bits : 1;
+		/** Auth offset & length in bits. */
+		uint64_t is_auth_in_bits : 1;
+		/** Is UL/transmitting PDCP entity */
+		uint64_t is_ul_entity : 1;
+	} flags;
+	/** Crypto op pool. */
+	struct rte_mempool *cop_pool;
+	/** PDCP header size. */
+	uint8_t hdr_sz;
+	/** PDCP AAD size. For AES-CMAC, additional message is prepended for

the operation. */

lib/pdcp/pdcp_entity.h new file +7 -0
+	uint8_t aad_sz;
+	/** Device ID of the device to be used for offload. */
+	uint8_t dev_id;
+};
+
+struct entity_priv_dl_part {
+	/* TODO - when in-order-delivery is supported, post PDCP packets

would need to cached. */

lib/pdcp/pdcp_entity.h new file +6 -0
+	uint8_t dummy;
+};
+
+struct entity_priv_ul_part {
+	/*
+	 * TODO - when re-establish is supported, both plain & post PDCP

packets would need to be

lib/pdcp/pdcp_entity.h new file +13 -0
+	 * cached.
+	 */
+	uint8_t dummy;
+};
+
+static inline struct entity_priv *
+entity_priv_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+}
+
+static inline struct entity_priv_dl_part *
+entity_dl_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +5 -0
+}
+
+static inline struct entity_priv_ul_part *
+entity_ul_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +
Quoted 2 lines

sizeof(struct entity_priv));
+}

Above inline functions may not be needed also if we have 0 len arrays.

lib/pdcp/pdcp_entity.h line 216

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+
+static inline int
+pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
+}

PDCP_PDU_HDR_SIZE is same as this inline function. Can we get away with this one?

Quoted 14 lines
lib/pdcp/pdcp_entity.h new file +2 -0
+
+#endif /* _PDCP_ENTITY_H_ */
lib/pdcp/pdcp_process.c new file +6 -0
new file mode 100644
index 0000000000..282cf38ec4
@@ -0,0 +1,1195 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>

lib/pdcp/pdcp_process.c line 16

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +10 -0
+#include <rte_cryptodev.h>
+#include <rte_memcpy.h>
+#include <rte_pdcp.h>
+#include <rte_pdcp_hdr.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+#define PDCP_MAC_I_LEN 4

Can you define it at same place where PDCP_IV_LENGTH is defined and use this in xform validate.

Quoted 1,531 lines
lib/pdcp/pdcp_process.c new file +23 -0
+
+/* Enum of supported algorithms for ciphering */
+enum pdcp_cipher_algo {
+	PDCP_CIPHER_ALGO_NULL,
+	PDCP_CIPHER_ALGO_AES,
+	PDCP_CIPHER_ALGO_ZUC,
+	PDCP_CIPHER_ALGO_SNOW3G,
+	PDCP_CIPHER_ALGO_MAX
+};
+
+/* Enum of supported algorithms for integrity */
+enum pdcp_auth_algo {
+	PDCP_AUTH_ALGO_NULL,
+	PDCP_AUTH_ALGO_AES,
+	PDCP_AUTH_ALGO_ZUC,
+	PDCP_AUTH_ALGO_SNOW3G,
+	PDCP_AUTH_ALGO_MAX
+};
+
+/* IV generation functions based on type of operation (cipher - auth) */
+
+static void
+pdcp_iv_gen_null_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	/* No IV required for NULL cipher + NULL auth */
+	RTE_SET_USED(cop);
+	RTE_SET_USED(en_priv);
+	RTE_SET_USED(count);
+}
+
+static void
+pdcp_iv_gen_null_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv *en_priv,

lib/pdcp/pdcp_process.c new file +8 -0
+			  uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr;
+	uint64_t m;
+
+	/* AES-CMAC requires message to be prepended with info on count etc

*/

lib/pdcp/pdcp_process.c new file +5 -0
+
+	/* Prepend by 8 bytes to add custom message */
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_null_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_process.c new file +8 -0
+			 uint32_t count)
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, 16);
+}
+
+static void
+pdcp_iv_gen_zs_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64;
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64 = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	rte_memcpy(iv, &iv_u64, 8);
+	rte_memcpy(iv + 8, &iv_u64, 8);
+}
+
+static void
+pdcp_iv_gen_zs_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	/* Generating cipher IV */
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +7 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	iv += PDCP_IV_LENGTH;
+
+	/* Generating auth IV */
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_zs_aes_cmac(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_process.c new file +10 -0
+			uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv *en_priv,

lib/pdcp/pdcp_process.c new file +11 -0
+			    uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LENGTH);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LENGTH);
+
+	iv += PDCP_IV_LENGTH;
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static int
+pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct

rte_crypto_sym_xform **c_xfrm,

lib/pdcp/pdcp_process.c new file +12 -0
+		     struct rte_crypto_sym_xform **a_xfrm)
+{
+	*c_xfrm = NULL;
+	*a_xfrm = NULL;
+
+	if (conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		*c_xfrm = conf->crypto_xfrm;
+		*a_xfrm = conf->crypto_xfrm->next;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_process.c new file +11 -0
+		*a_xfrm = conf->crypto_xfrm;
+		*c_xfrm = conf->crypto_xfrm->next;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+pdcp_iv_gen_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +31 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	enum rte_security_pdcp_direction direction;
+	enum pdcp_cipher_algo ciph_algo;
+	enum pdcp_auth_algo auth_algo;
+	struct entity_priv *en_priv;
+	int ret;
+
+	en_priv = entity_priv_get(entity);
+
+	direction = conf->pdcp_xfrm.pkt_dir;
+	if (conf->reverse_iv_direction)
+		direction = !direction;
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	memset(&en_priv->auth_iv_part, 0, sizeof(en_priv->auth_iv_part));
+	memset(&en_priv->cipher_iv_part, 0, sizeof(en_priv->cipher_iv_part));
+
+	switch (c_xfrm->cipher.algo) {
+	case RTE_CRYPTO_CIPHER_NULL:
+		ciph_algo = PDCP_CIPHER_ALGO_NULL;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		ciph_algo = PDCP_CIPHER_ALGO_AES;
+		en_priv->cipher_iv_part.aes_ctr.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +24 -0
+		en_priv->cipher_iv_part.aes_ctr.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		ciph_algo = PDCP_CIPHER_ALGO_SNOW3G;
+		en_priv->cipher_iv_part.zs.bearer = conf->pdcp_xfrm.bearer;
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		ciph_algo = PDCP_CIPHER_ALGO_ZUC;
+		en_priv->cipher_iv_part.zs.bearer = conf->pdcp_xfrm.bearer;
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	if (a_xfrm != NULL) {
+		switch (a_xfrm->auth.algo) {
+		case RTE_CRYPTO_AUTH_NULL:
+			auth_algo = PDCP_AUTH_ALGO_NULL;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			auth_algo = PDCP_AUTH_ALGO_AES;
+			en_priv->auth_iv_part.aes_cmac.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +5 -0
+			en_priv->auth_iv_part.aes_cmac.direction = direction;
+			break;
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			auth_algo = PDCP_AUTH_ALGO_SNOW3G;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +6 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			auth_algo = PDCP_AUTH_ALGO_ZUC;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +11 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		default:
+			return -ENOTSUP;
+		}
+	} else {
+		auth_algo = PDCP_AUTH_ALGO_NULL;
+	}
+
+	static const iv_gen_t

iv_gen_map[PDCP_CIPHER_ALGO_MAX][PDCP_AUTH_ALGO_MAX] = {

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_null_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_null_aes_cmac,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_aes_ctr_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_aes_ctr_aes_cmac,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,
+

	[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +9 -0
+	};
+
+	en_priv->iv_gen = iv_gen_map[ciph_algo][auth_algo];
+
+	return 0;
+}
+
+static inline void
+cop_prepare(const struct entity_priv *en_priv, struct rte_mbuf *mb, struct

rte_crypto_op *cop,

lib/pdcp/pdcp_process.c new file +29 -0
+	    uint8_t data_offset, uint32_t count, const bool is_auth)
+{
+	const struct rte_crypto_op cop_init = {
+		.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED,
+		.sess_type = RTE_CRYPTO_OP_WITH_SESSION,
+	};
+	struct rte_crypto_sym_op *op;
+	uint32_t pkt_len;
+
+	const uint8_t ciph_shift = 3 * en_priv->flags.is_ciph_in_bits;
+	const uint8_t auth_shift = 3 * en_priv->flags.is_auth_in_bits;
+
+	op = cop->sym;
+	cop->raw = cop_init.raw;
+	op->m_src = mb;
+	op->m_dst = mb;
+
+	/* Set IV */
+	en_priv->iv_gen(cop, en_priv, count);
+
+	/* Prepare op */
+	pkt_len = rte_pktmbuf_pkt_len(mb);
+	op->cipher.data.offset = data_offset << ciph_shift;
+	op->cipher.data.length = (pkt_len - data_offset) << ciph_shift;
+
+	if (is_auth) {
+		op->auth.data.offset = 0;
+		op->auth.data.length = (pkt_len - PDCP_MAC_I_LEN) <<

auth_shift;

lib/pdcp/pdcp_process.c new file +1 -0
+		op->auth.digest.data = rte_pktmbuf_mtod_offset(mb, uint8_t

*,

lib/pdcp/pdcp_process.c new file +1 -0
+							       (pkt_len -

PDCP_MAC_I_LEN));

lib/pdcp/pdcp_process.c new file +7 -0
+	}
+
+	__rte_crypto_sym_op_attach_sym_session(op, en_priv->crypto_sess);
+}
+
+static inline bool
+pdcp_pre_process_uplane_sn_12_ul_set_sn(struct entity_priv *en_priv, struct

rte_mbuf *mb,

lib/pdcp/pdcp_process.c new file +8 -0
+					uint32_t *count)
+{
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	uint32_t sn;
+
+	/* Prepend PDU header */
+	pdu_hdr = (struct rte_pdcp_up_data_pdu_sn_12_hdr

*)rte_pktmbuf_prepend(mb, hdr_sz);

lib/pdcp/pdcp_process.c new file +5 -0
+	if (unlikely(pdu_hdr == NULL))
+		return false;
+
+	/* Update sequence num in the PDU header */
+	*count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +11 -0
+	sn = PDCP_GET_SN_12_FROM_COUNT(*count);
+
+	pdu_hdr->d_c = PDCP_PDU_TYPE_DATA;
+	pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+	pdu_hdr->sn_7_0 = (sn & 0xff);
+	pdu_hdr->r = 0;
+	return true;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_ul(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint16_t nb_cop;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	if (en_priv->flags.is_authenticated) {
+		for (i = 0; i < nb_cop; i++) {
+			if (unlikely(rte_pktmbuf_append(mb[i],

PDCP_MAC_I_LEN) == NULL))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			if

(unlikely(!pdcp_pre_process_uplane_sn_12_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

true);

lib/pdcp/pdcp_process.c new file +4 -0
+		}
+	} else {
+		for (i = 0; i < nb_cop; i++) {
+			if

(unlikely(!pdcp_pre_process_uplane_sn_12_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

false);

lib/pdcp/pdcp_process.c new file +14 -0
+		}
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop - i);
+	*nb_err = num - i;
+	return i;
+}
+
+static inline bool
+pdcp_pre_process_uplane_sn_18_ul_set_sn(struct entity_priv *en_priv, struct

rte_mbuf *mb,

lib/pdcp/pdcp_process.c new file +8 -0
+					uint32_t *count)
+{
+	struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr;
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	uint32_t sn;
+
+	/* Prepend PDU header */
+	pdu_hdr = (struct rte_pdcp_up_data_pdu_sn_18_hdr

*)rte_pktmbuf_prepend(mb, hdr_sz);

lib/pdcp/pdcp_process.c new file +5 -0
+	if (unlikely(pdu_hdr == NULL))
+		return false;
+
+	/* Update sequence num in the PDU header */
+	*count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +13 -0
+	sn = PDCP_GET_SN_18_FROM_COUNT(*count);
+
+	pdu_hdr->d_c = PDCP_PDU_TYPE_DATA;
+	pdu_hdr->sn_17_16 = ((sn & 0x30000) >> 16);
+	pdu_hdr->sn_15_8 = ((sn & 0xff00) >> 8);
+	pdu_hdr->sn_7_0 = (sn & 0xff);
+	pdu_hdr->r = 0;
+
+	return true;
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_18_ul(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint16_t nb_cop;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	if (en_priv->flags.is_authenticated) {
+		for (i = 0; i < nb_cop; i++) {
+			if (unlikely(rte_pktmbuf_append(mb[i],

PDCP_MAC_I_LEN) == NULL))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			if

(unlikely(!pdcp_pre_process_uplane_sn_18_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

true);

lib/pdcp/pdcp_process.c new file +4 -0
+		}
+	} else {
+		for (i = 0; i < nb_cop; i++) {
+			if

(unlikely(!pdcp_pre_process_uplane_sn_18_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

false);

lib/pdcp/pdcp_process.c new file +15 -0
+		}
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop - i);
+	*nb_err = num - i;
+	return i;
+}
+
+static uint16_t
+pdcp_pre_process_cplane_sn_12_ul(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +11 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_cp_data_pdu_sn_12_hdr *pdu_hdr;
+	uint32_t count, sn;
+	uint16_t nb_cop;
+	int i;
+
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	const uint8_t data_offset = hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		/* Prepend PDU header */
+		pdu_hdr = (struct rte_pdcp_cp_data_pdu_sn_12_hdr

*)rte_pktmbuf_prepend(mb[i],
+

	       hdr_sz);
lib/pdcp/pdcp_process.c new file +3 -0
+		if (unlikely(pdu_hdr == NULL))
+			goto cop_free;
+		if (unlikely(rte_pktmbuf_append(mb[i], PDCP_MAC_I_LEN) ==

NULL))

lib/pdcp/pdcp_process.c new file +4 -0
+			goto cop_free;
+
+		/* Update sequence number in the PDU header */
+		count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +34 -0
+		sn = PDCP_GET_SN_12_FROM_COUNT(count);
+
+		pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+		pdu_hdr->r = 0;
+
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count, true);
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop - i);
+	*nb_err = num - i;
+	return i;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_12_ul(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +20 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_18_ul(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +19 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_cplane_sn_12_ul(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *mb, *err_mb[num];
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +7 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static inline int
+pdcp_sn_18_count_get(const struct rte_pdcp_entity *entity, int32_t rsn,

uint32_t *count)

lib/pdcp/pdcp_process.c new file +5 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint32_t rhfn, rx_deliv;
+
+	rx_deliv = __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +3 -0
+	rhfn = PDCP_GET_HFN_SN_18_FROM_COUNT(rx_deliv);
+
+	if (rsn < (int32_t)(PDCP_GET_SN_18_FROM_COUNT(rx_deliv) -

PDCP_SN_18_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +4 -0
+		if (unlikely(rhfn == PDCP_SN_18_HFN_MAX))
+			return -ERANGE;
+		rhfn += 1;
+	} else if ((uint32_t)rsn >= (PDCP_GET_SN_18_FROM_COUNT(rx_deliv) +

PDCP_SN_18_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +12 -0
+		if (unlikely(rhfn == PDCP_SN_18_HFN_MIN))
+			return -ERANGE;
+		rhfn -= 1;
+	}
+
+	*count = PDCP_SET_COUNT_FROM_HFN_SN_18(rhfn, rsn);
+
+	return 0;
+}
+
+static inline int
+pdcp_sn_12_count_get(const struct rte_pdcp_entity *entity, int32_t rsn,

uint32_t *count)

lib/pdcp/pdcp_process.c new file +5 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint32_t rhfn, rx_deliv;
+
+	rx_deliv = __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +3 -0
+	rhfn = PDCP_GET_HFN_SN_12_FROM_COUNT(rx_deliv);
+
+	if (rsn < (int32_t)(PDCP_GET_SN_12_FROM_COUNT(rx_deliv) -

PDCP_SN_12_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +4 -0
+		if (unlikely(rhfn == PDCP_SN_12_HFN_MAX))
+			return -ERANGE;
+		rhfn += 1;
+	} else if ((uint32_t)rsn >= (PDCP_GET_SN_12_FROM_COUNT(rx_deliv) +

PDCP_SN_12_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +12 -0
+		if (unlikely(rhfn == PDCP_SN_12_HFN_MIN))
+			return -ERANGE;
+		rhfn -= 1;
+	}
+
+	*count = PDCP_SET_COUNT_FROM_HFN_SN_12(rhfn, rsn);
+
+	return 0;
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity

*entity, struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				       struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err,

lib/pdcp/pdcp_process.c new file +12 -0
+				       const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	int32_t rsn = 0;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_up_data_pdu_sn_12_hdr *);

lib/pdcp/pdcp_process.c new file +10 -0
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr->sn_7_0));
+		else
+			rte_panic("TODO: Control PDU not handled");
+
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

is_integ_protected);

lib/pdcp/pdcp_process.c new file +9 -0
+	}
+
+	*nb_err = num - nb_cop;
+
+	return nb_cop;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_dl_ip(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				    struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_12_dl_flags(entity, mb, cop, num,

nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_dl(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_12_dl_flags(entity, mb, cop, num,

nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity

*entity, struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				       struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err,

lib/pdcp/pdcp_process.c new file +11 -0
+				       const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	int32_t rsn = 0;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +4 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_up_data_pdu_sn_18_hdr *);

lib/pdcp/pdcp_process.c new file +4 -0
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_17_16 << 16) | (pdu_hdr->sn_15_8

<< 8) |

lib/pdcp/pdcp_process.c new file +7 -0
+			       (pdu_hdr->sn_7_0));
+		else
+			rte_panic("TODO: Control PDU not handled");
+
+		if (unlikely(pdcp_sn_18_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

is_integ_protected);

lib/pdcp/pdcp_process.c new file +9 -0
+	}
+
+	*nb_err = num - nb_cop;
+
+	return nb_cop;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_18_dl_ip(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				    struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_18_dl_flags(entity, mb, cop, num,

nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_18_dl(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_18_dl_flags(entity, mb, cop, num,

nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity,

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +11 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_cp_data_pdu_sn_12_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	uint32_t count;
+	int32_t rsn;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +4 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_cp_data_pdu_sn_12_hdr *);

lib/pdcp/pdcp_process.c new file +17 -0
+		rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr->sn_7_0));
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count, true);
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+}
+
+static inline bool
+pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,
+				      const uint32_t count)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+
+	if (count < __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED))

lib/pdcp/pdcp_process.c new file +3 -0
+		return false;
+
+	/* t-Reordering timer is not supported - SDU will be delivered

immediately.

lib/pdcp/pdcp_process.c new file +1 -0
+	 * Update RX_DELIV to the COUNT value of the first PDCP SDU which

has not

lib/pdcp/pdcp_process.c new file +3 -0
+	 * been delivered to upper layers
+	 */
+	__atomic_store_n(&en_priv->state.rx_deliv, (count + 1),

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +2 -0
+
+	if (count >= __atomic_load_n(&en_priv->state.rx_next,

__ATOMIC_RELAXED))

lib/pdcp/pdcp_process.c new file +1 -0
+		__atomic_store_n(&en_priv->state.rx_next, (count + 1),

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +6 -0
+
+	return true;
+}
+
+static inline uint16_t
+pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c new file +18 -0
+					struct rte_mbuf *in_mb[],
+					struct rte_mbuf *out_mb[],
+					uint16_t num, uint16_t *nb_err_ret,
+					const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	int i, nb_success = 0, nb_err = 0, rsn = 0;
+	const uint32_t aad_sz = en_priv->aad_sz;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+	uint32_t count;
+
+	const uint32_t hdr_trim_sz = en_priv->hdr_sz + aad_sz;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +2 -0
+			goto error;
+		pdu_hdr = rte_pktmbuf_mtod_offset(mb, struct

rte_pdcp_up_data_pdu_sn_12_hdr *,

lib/pdcp/pdcp_process.c new file +12 -0
+						  aad_sz);
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr->sn_7_0));
+		else
+			rte_panic("Control PDU should not be received");
+
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			goto error;
+
+		if (unlikely(!pdcp_post_process_update_entity_state(entity,

count)))

lib/pdcp/pdcp_process.c new file +14 -0
+			goto error;
+
+		rte_pktmbuf_adj(mb, hdr_trim_sz);
+		if (is_integ_protected)
+			rte_pktmbuf_trim(mb, PDCP_MAC_I_LEN);
+		out_mb[nb_success++] = mb;
+		continue;
+
+error:
+		err_mb[nb_err++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +12 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_12_dl_ip(const struct rte_pdcp_entity *entity,
+				     struct rte_mbuf *in_mb[],
+				     struct rte_mbuf *out_mb[],
+				     uint16_t num, uint16_t *nb_err)
+{
+	return pdcp_post_process_uplane_sn_12_dl_flags(entity, in_mb,

out_mb, num, nb_err, true);

lib/pdcp/pdcp_process.c new file +9 -0
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_12_dl(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err)
+{
+	return pdcp_post_process_uplane_sn_12_dl_flags(entity, in_mb,

out_mb, num, nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static inline uint16_t
+pdcp_post_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c new file +18 -0
+					struct rte_mbuf *in_mb[],
+					struct rte_mbuf *out_mb[],
+					uint16_t num, uint16_t *nb_err_ret,
+					const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr;
+	const uint32_t aad_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *mb, *err_mb[num];
+	int32_t rsn = 0;
+	uint32_t count;
+
+	const uint32_t hdr_trim_sz = en_priv->hdr_sz + aad_sz;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +3 -0
+			goto error;
+
+		pdu_hdr = rte_pktmbuf_mtod_offset(mb, struct

rte_pdcp_up_data_pdu_sn_18_hdr *,

lib/pdcp/pdcp_process.c new file +5 -0
+						  aad_sz);
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_17_16 << 16) | (pdu_hdr->sn_15_8

<< 8) |

lib/pdcp/pdcp_process.c new file +8 -0
+			       (pdu_hdr->sn_7_0));
+		else
+			rte_panic("Control PDU should not be received");
+
+		if (unlikely(pdcp_sn_18_count_get(entity, rsn, &count)))
+			goto error;
+
+		if (unlikely(!pdcp_post_process_update_entity_state(entity,

count)))

lib/pdcp/pdcp_process.c new file +14 -0
+			goto error;
+
+		rte_pktmbuf_adj(mb, hdr_trim_sz);
+		if (is_integ_protected)
+			rte_pktmbuf_trim(mb, PDCP_MAC_I_LEN);
+		out_mb[nb_success++] = mb;
+		continue;
+
+error:
+		err_mb[nb_err++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +12 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_18_dl_ip(const struct rte_pdcp_entity *entity,
+				     struct rte_mbuf *in_mb[],
+				     struct rte_mbuf *out_mb[],
+				     uint16_t num, uint16_t *nb_err)
+{
+	return pdcp_post_process_uplane_sn_18_dl_flags(entity, in_mb,

out_mb, num, nb_err, true);

lib/pdcp/pdcp_process.c new file +9 -0
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_18_dl(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err)
+{
+	return pdcp_post_process_uplane_sn_18_dl_flags(entity, in_mb,

out_mb, num, nb_err, false);

lib/pdcp/pdcp_process.c new file +22 -0
+}
+
+static uint16_t
+pdcp_post_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity,
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_cp_data_pdu_sn_12_hdr *pdu_hdr;
+	const uint32_t aad_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+	uint32_t count;
+	int32_t rsn;
+
+	const uint32_t hdr_trim_sz = en_priv->hdr_sz + aad_sz;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +3 -0
+			goto error;
+
+		pdu_hdr = rte_pktmbuf_mtod_offset(mb, struct

rte_pdcp_cp_data_pdu_sn_12_hdr *,

lib/pdcp/pdcp_process.c new file +7 -0
+						  aad_sz);
+		rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr->sn_7_0));
+
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			goto error;
+
+		if (unlikely(!pdcp_post_process_update_entity_state(entity,

count)))

lib/pdcp/pdcp_process.c new file +13 -0
+			goto error;
+
+		rte_pktmbuf_adj(mb, hdr_trim_sz);
+		rte_pktmbuf_trim(mb, PDCP_MAC_I_LEN);
+		out_mb[nb_success++] = mb;
+		continue;
+
+error:
+		err_mb[nb_err++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +7 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static int
+pdcp_pre_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+
+	entity->pre_process = NULL;
+	entity->post_process = NULL;
+
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL) &&

lib/pdcp/pdcp_process.c new file +7 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)) {
+		entity->pre_process = pdcp_pre_process_cplane_sn_12_ul;
+		entity->post_process = pdcp_post_process_cplane_sn_12_ul;
+	}
+
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL) &&

lib/pdcp/pdcp_process.c new file +7 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)) {
+		entity->pre_process = pdcp_pre_process_cplane_sn_12_dl;
+		entity->post_process = pdcp_post_process_cplane_sn_12_dl;
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +7 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_ul;
+		entity->post_process = pdcp_post_process_uplane_sn_12_ul;
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +7 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_ul;
+		entity->post_process = pdcp_post_process_uplane_sn_18_ul;
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +5 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_dl_ip;
+		entity->post_process =

pdcp_post_process_uplane_sn_12_dl_ip;

lib/pdcp/pdcp_process.c new file +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +8 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_dl;
+		entity->post_process = pdcp_post_process_uplane_sn_12_dl;
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +5 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_dl_ip;
+		entity->post_process =

pdcp_post_process_uplane_sn_18_dl_ip;

lib/pdcp/pdcp_process.c new file +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c new file +15 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_dl;
+		entity->post_process = pdcp_post_process_uplane_sn_18_dl;
+	}
+
+	if (entity->pre_process == NULL || entity->post_process == NULL)
+		return -ENOTSUP;
+
+	return 0;
+}
+
+static int
+pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	int ret;
+
+	/**
+	 * flags.is_authenticated
+	 *
+	 * MAC-I would be added in case of control plane packets and when

authentication

lib/pdcp/pdcp_process.c new file +4 -0
+	 * transform is not NULL.
+	 */
+
+	if (conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL)

lib/pdcp/pdcp_process.c new file +13 -0
+		en_priv->flags.is_authenticated = 1;
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (a_xfrm != NULL)
+		en_priv->flags.is_authenticated = 1;
+
+	/**
+	 * flags.is_ciph_in_bits
+	 *
+	 * For ZUC & SNOW3G cipher algos, offset & length need to be provided

in bits.

lib/pdcp/pdcp_process.c new file +10 -0
+	 */
+
+	if ((c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2) ||
+	    (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3))
+		en_priv->flags.is_ciph_in_bits = 1;
+
+	/**
+	 * flags.is_auth_in_bits
+	 *
+	 * For ZUC & SNOW3G authentication algos, offset & length need to be

provided in bits.

lib/pdcp/pdcp_process.c new file +4 -0
+	 */
+
+	if (a_xfrm != NULL) {
+		if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2)

||

lib/pdcp/pdcp_process.c new file +23 -0
+		    (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3))
+			en_priv->flags.is_auth_in_bits = 1;
+	}
+
+	/**
+	 * flags.is_ul_entity
+	 *
+	 * Indicate whether the entity is UL/transmitting PDCP entity.
+	 */
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		en_priv->flags.is_ul_entity = 1;
+
+	/**
+	 * hdr_sz
+	 *
+	 * PDCP header size of the entity
+	 */
+	en_priv->hdr_sz = pdcp_hdr_size_get(conf->pdcp_xfrm.sn_size);
+
+	/**
+	 * aad_sz
+	 *
+	 * For AES-CMAC, additional message is prepended for processing. Need

to be trimmed after

lib/pdcp/pdcp_process.c new file +3 -0
+	 * crypto processing is done.
+	 */
+	if (a_xfrm != NULL && a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_AES_CMAC)

lib/pdcp/pdcp_process.c new file +9 -0
+		en_priv->aad_sz = 8;
+	else
+		en_priv->aad_sz = 0;
+
+	return 0;
+}
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +23 -0
+{
+	struct entity_priv *en_priv;
+	int ret;
+
+	if (entity == NULL || conf == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	ret = pdcp_iv_gen_func_set(entity, conf);
+	if (ret)
+		return ret;
+
+	ret = pdcp_entity_priv_populate(en_priv, conf);
+	if (ret)
+		return ret;
+
+	ret = pdcp_pre_process_func_set(entity, conf);
+	if (ret)
+		return ret;
+
+	return 0;
+}
lib/pdcp/pdcp_process.h new file +11 -0
new file mode 100644
index 0000000000..c92ab34c40
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_PROCESS_H_
+#define _PDCP_PROCESS_H_
+
+#include <rte_pdcp.h>
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf);

lib/pdcp/pdcp_process.h new file +2 -0
+
+#endif /* _PDCP_PROCESS_H_ */
lib/pdcp/rte_pdcp.c new file +41 -0
new file mode 100644
index 0000000000..b1533971c2
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf)
+{
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE);
+}
+
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)
+{
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
+	int ret;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	if (conf->pdcp_xfrm.en_ordering || conf-
Quoted 1 line

pdcp_xfrm.remove_duplicates || conf->is_slrb ||

lib/pdcp/rte_pdcp.c new file +8 -0
+	    conf->en_sec_offload) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	/*
+	 * 6.3.2 PDCP SN
+	 * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length of the

PDCP SN is

lib/pdcp/rte_pdcp.c new file +1 -0
+	 * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or sl-

PDCP-SN-Size in

lib/pdcp/rte_pdcp.c new file +47 -0
+	 * TS 38.331 [3])
+	 */
+	if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	if (conf->pdcp_xfrm.hfn || conf->pdcp_xfrm.hfn_threshold) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	entity = rte_zmalloc_socket("pdcp_entity", pdcp_entity_size_get(conf),
+				    RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (entity == NULL) {
+		rte_errno = -ENOMEM;
+		return NULL;
+	}
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->state.rx_deliv = conf->count;
+	en_priv->state.tx_next = conf->count;
+	en_priv->cop_pool = conf->cop_pool;
+
+	/* Setup crypto session */
+	ret = pdcp_crypto_sess_create(entity, conf);
+	if (ret)
+		goto entity_free;
+
+	ret = pdcp_process_func_set(entity, conf);
+	if (ret)
+		goto crypto_sess_destroy;
+
+	return entity;
+
+crypto_sess_destroy:
+	pdcp_crypto_sess_destroy(entity);
+entity_free:
+	rte_free(entity);
+	rte_errno = ret;
+	return NULL;
+}
+
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity, struct rte_mbuf

*out_mb[])

lib/pdcp/rte_pdcp.c new file +39 -0
+{
+	int ret;
+
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	/* Teardown crypto sessions */
+	ret = pdcp_crypto_sess_destroy(pdcp_entity);
+	if (ret)
+		return ret;
+
+	rte_free(pdcp_entity);
+
+	RTE_SET_USED(out_mb);
+	return 0;
+}
+
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[])
+{
+	struct entity_priv *en_priv;
+
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(pdcp_entity);
+
+	if (en_priv->flags.is_ul_entity) {
+		en_priv->state.tx_next = 0;
+	} else {
+		en_priv->state.rx_next = 0;
+		en_priv->state.rx_deliv = 0;
+	}
+
+	RTE_SET_USED(out_mb);
+
+	return 0;
+}
lib/pdcp/rte_pdcp.h new file +10 -0
new file mode 100644
index 0000000000..b6c7f32c05
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _RTE_PDCP_H_
+#define _RTE_PDCP_H_
+
+/**
+ * @file rte_pdcp.h
+ *

lib/pdcp/rte_pdcp.h line 20

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+ * 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>

Remove header file which is not needed.
I do not see use of rte_errno.h
I believe rte_common.h and rte_compat.h are also not needed.

lib/pdcp/rte_pdcp_group.h

Quoted 278 lines
lib/pdcp/rte_pdcp.h new file +69 -0
+
+#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 *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, *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;
+
+/**
+ * PDCP entity configuration to be used for establishing an entity.
+ */
+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;
+	/** 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.

lib/pdcp/rte_pdcp.h new file +3 -0
+	 */
+	uint32_t count;
+	/** Indicate whether the PDCP entity belongs to Side Link Radio Bearer.

*/

lib/pdcp/rte_pdcp.h new file +8 -0
+	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;
+	/** Reverse direction during IV generation. Can be used to simulate UE

crypto processing.*/

lib/pdcp/rte_pdcp.h new file +38 -0
+	bool reverse_iv_direction;
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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

+ */

lib/pdcp/rte_pdcp.h new file +23 -0
+__rte_experimental
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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.
+ *
+ * For UL/transmitting PDCP entity, *out_mb* buffer would be unused.
+ *
+ * @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

+ */

lib/pdcp/rte_pdcp.h new file +48 -0
+__rte_experimental
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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[in, 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. Crypto ops would be allocated by
+ *   ``rte_pdcp_pkt_pre_process`` API.
+ * @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
+ */
+__rte_experimental
+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);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * For input mbufs and given PDCP entity, perform PDCP post-processing of the
+ * mbufs.
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

cryptodev
+ * and grouped by *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.
+ */

lib/pdcp/rte_pdcp.h new file +17 -0

Lines of this file are not shown. View the raw message.

lib/pdcp/rte_pdcp_group.h new file +14 -0
new file mode 100644
index 0000000000..2c01c19d4e

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

related
+ * packets by sessions they belong to.
+ */

lib/pdcp/rte_pdcp_group.h new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Remove header files which are not needed.

lib/pdcp/rte_pdcp_group.h

Quoted 37 lines
lib/pdcp/rte_pdcp_group.h new file +37 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

This patchset is not supporting security sessions, so it would be better to return NULL for that. Moreover, we can directly call rte_cryptodev_sym_session_opaque_data_get(cop->sym[0].session) From rte_pdcp_pkt_crypto_group. No need to have a wrapper.

lib/pdcp/version.map

Quoted 89 lines
lib/pdcp/rte_pdcp_group.h new file +6 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

22 lines not shown · raw message

lib/pdcp/rte_pdcp_group.h new file +2 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

1 line not shown · raw message

lib/pdcp/rte_pdcp_group.h new file +13 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

1 line not shown · raw message

lib/pdcp/rte_pdcp_group.h new file +34 -0

Lines of this file are not shown. View the raw message.

lib/pdcp/version.map new file +4 -0
new file mode 100644
index 0000000000..8fa9d5d7cc

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

12 lines not shown · raw message

Parts of this message are not shown here. View the raw message.

#13 lore raw

Hi Akhil,

Thanks for the review. Please see inline.

Thanks,
Anoob

Quoted 123 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Wednesday, January 18, 2023 9:57 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH 2/5] lib: add pdcp protocol

Hi Anoob,

Please see inline comments.

Quoted 20 lines

Subject: [PATCH 2/5] lib: add pdcp protocol

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_release()

Quoted 3 lines

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

Quoted 6 lines

operations belonging to multiple entities, rte_pdcp_pkt_crypto_group() is added to help grouping crypto operations belonging to same entity.

Quoted 9 lines
---
 doc/api/doxy-api-index.md |    3 +-
 doc/api/doxy-api.conf.in  |    1 +
 lib/meson.build           |    1 +
 lib/pdcp/meson.build      |    8 +
 lib/pdcp/pdcp_crypto.c    |  240 ++++++++
 lib/pdcp/pdcp_crypto.h    |   20 +
 lib/pdcp/pdcp_entity.h    |  218 +++++++
 lib/pdcp/pdcp_process.c   | 1195

+++++++++++++++++++++++++++++++++++++

Quoted 62 lines
 lib/pdcp/pdcp_process.h   |   13 +
 lib/pdcp/rte_pdcp.c       |  136 +++++
 lib/pdcp/rte_pdcp.h       |  263 ++++++++
 lib/pdcp/rte_pdcp_group.h |  133 +++++
 lib/pdcp/version.map      |   13 +
 13 files changed, 2243 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
doc/api/doxy-api-index.md +2 -1
index ae4b107240..6014bee079 100644
@@ -126,7 +126,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h),
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in +1 -0
index f0886c3bd1..01314b087e 100644
@@ -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 \
lib/meson.build +1 -0
index fd55925340..a827006d29 100644
@@ -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 = [
lib/pdcp/meson.build new file +0 -0
new file mode 100644
index 0000000000..a7f5a408cf

lib/pdcp/meson.build line 3

Quoted 3 lines
lib/pdcp/meson.build new file +3 -0
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2022 Marvell.
+#

Extra # here.

Quoted 3 lines

Do we support compilation on Windows as well?
Check missing here.

[Anoob] Will add checks in next version.

Quoted 6 lines

lib/pdcp/meson.build line 6

Quoted 3 lines
lib/pdcp/meson.build new file +3 -0
+
+sources = files('pdcp_crypto.c', 'pdcp_process.c', 'rte_pdcp.c')
+headers = files('rte_pdcp.h')

Do we need to add the indirect header as well for
lib/pdcp/rte_pdcp_group.h?

[Anoob] Yes. Will update in next version.

Quoted 5 lines

lib/pdcp/meson.build line 8

Quoted 3 lines
lib/pdcp/meson.build new file +2 -0
+
+deps += ['security']

Crypto not needed as dependency?

[Anoob] Yes. Will include other dependencies as well.

Quoted 160 lines
Quoted 61 lines
lib/pdcp/pdcp_crypto.c new file +14 -0
new file mode 100644
index 0000000000..7ffb8a07a7
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_pdcp.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+
+static int
+pdcp_crypto_caps_cipher_verify(uint8_t dev_id, const struct

rte_crypto_sym_xform *c_xfrm)

lib/pdcp/pdcp_crypto.c new file +13 -0
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+	cap_idx.algo.cipher = c_xfrm->cipher.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_cipher(cap, c_xfrm-
Quoted 1 line

cipher.key.length,

lib/pdcp/pdcp_crypto.c new file +1 -0
+							c_xfrm-
Quoted 1 line

cipher.iv.length);

lib/pdcp/pdcp_crypto.c new file +6 -0
+
+	return ret;
+}
+
+static int
+pdcp_crypto_caps_auth_verify(uint8_t dev_id, const struct

rte_crypto_sym_xform *a_xfrm)

lib/pdcp/pdcp_crypto.c new file +13 -0
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+	cap_idx.algo.auth = a_xfrm->auth.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_auth(cap, a_xfrm-
Quoted 1 line

auth.key.length,

lib/pdcp/pdcp_crypto.c new file +1 -0
+						      a_xfrm-
Quoted 1 line

auth.digest_length,

lib/pdcp/pdcp_crypto.c

Quoted 9 lines
lib/pdcp/pdcp_crypto.c new file +9 -0
+						      a_xfrm->auth.iv.length);
+
+	return ret;
+}
+
+static int
+pdcp_crypto_xfrm_validate(const struct rte_pdcp_entity_conf *conf,
+				 const struct rte_crypto_sym_xform *c_xfrm,
+				 const struct rte_crypto_sym_xform

*a_xfrm,

lib/pdcp/pdcp_crypto.c

Quoted 7 lines
lib/pdcp/pdcp_crypto.c new file +7 -0
+				 bool is_auth_then_cipher)
+{
+	uint16_t ciph_iv_len, auth_digest_len, auth_iv_len;
+	int ret;
+
+	/*
+	 * Uplink means PDCP entity is configured for transmit. Downlink

means

lib/pdcp/pdcp_crypto.c

Quoted 4 lines

PDCP entity is

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * configured for receive. When integrity protection is enabled, PDCP

always performs

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * digest-encrypted or auth-gen-encrypt for uplink (and decrypt-

auth-

lib/pdcp/pdcp_crypto.c

Quoted 2 lines

verify for downlink).

lib/pdcp/pdcp_crypto.c new file +1 -0
+	 * So for uplink, crypto chain would be auth-cipher while for downlink

it

lib/pdcp/pdcp_crypto.c

Quoted 4 lines

would be

lib/pdcp/pdcp_crypto.c new file +3 -0
+	 * cipher-auth.
+	 *
+	 * When integrity protection is not required, xform would be cipher

only.

lib/pdcp/pdcp_crypto.c

Quoted 8 lines
lib/pdcp/pdcp_crypto.c new file +8 -0
+	 */
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK) {
+
+		/* With UPLINK, if auth is enabled, it should be before cipher

*/

lib/pdcp/pdcp_crypto.c

Quoted 8 lines
lib/pdcp/pdcp_crypto.c new file +8 -0
+		if (a_xfrm != NULL && !is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With UPLINK, cipher operation must be encrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_ENCRYPT)
+			return -EINVAL;
+
+		/* With UPLINK, auth operation (if present) must be

generate */

lib/pdcp/pdcp_crypto.c

Quoted 5 lines
lib/pdcp/pdcp_crypto.c new file +1 -0
+		if (a_xfrm != NULL && a_xfrm->auth.op !=

RTE_CRYPTO_AUTH_OP_GENERATE)

lib/pdcp/pdcp_crypto.c new file +3 -0
+			return -EINVAL;
+
+	} else if (conf->pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_DOWNLINK)

lib/pdcp/pdcp_crypto.c

Quoted 3 lines

{

lib/pdcp/pdcp_crypto.c new file +2 -0
+
+		/* With DOWNLINK, if auth is enabled, it should be after

cipher

lib/pdcp/pdcp_crypto.c

Quoted 9 lines

*/

lib/pdcp/pdcp_crypto.c new file +8 -0
+		if (a_xfrm != NULL && is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With DOWNLINK, cipher operation must be decrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_DECRYPT)
+			return -EINVAL;
+
+		/* With DOWNLINK, auth operation (if present) must be

verify

Quoted 16 lines

*/

lib/pdcp/pdcp_crypto.c new file +1 -0
+		if (a_xfrm != NULL && a_xfrm->auth.op !=

RTE_CRYPTO_AUTH_OP_VERIFY)

lib/pdcp/pdcp_crypto.c new file +13 -0
+			return -EINVAL;
+
+	} else {
+		return -EINVAL;
+	}
+
+	if ((c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_NULL) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_AES_CTR) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_ZUC_EEA3) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2))
+		return -EINVAL;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)

lib/pdcp/pdcp_crypto.c

Quoted 10 lines
lib/pdcp/pdcp_crypto.c new file +10 -0
+		ciph_iv_len = 0;
+	else
+		ciph_iv_len = PDCP_IV_LENGTH;
+
+	if (ciph_iv_len != c_xfrm->cipher.iv.length)
+		return -EINVAL;
+
+	if (a_xfrm != NULL) {
+		if ((a_xfrm->auth.algo != RTE_CRYPTO_AUTH_NULL) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_AES_CMAC)

&&

lib/pdcp/pdcp_crypto.c

Quoted 2 lines
lib/pdcp/pdcp_crypto.c new file +2 -0
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_ZUC_EIA3) &&
+		    (a_xfrm->auth.algo !=

RTE_CRYPTO_AUTH_SNOW3G_UIA2))

Quoted 8 lines

lib/pdcp/pdcp_crypto.c line 132

Quoted 6 lines
lib/pdcp/pdcp_crypto.c new file +6 -0
+			return -EINVAL;
+
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			auth_digest_len = 0;
+		else
+			auth_digest_len = 4;

If we have a macro for IV length, why not for digest also?

[Anoob] Will add macro for digest length.

Quoted 6 lines

Moreover, for NULL integrity, digest length is also 4 with all 0s. Refer Annex D.1 in
https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/15.04.00_60/ts
_133501v150400p.pdf

Digest len would be 0 only in case of a_xfrm == NULL

[Anoob] I agree that PDCP requires AUTH NULL to add all 0s. And we satisfy the same by having lib PDCP add zeros. Most of the crypto drivers in DPDK doesn't allow non-zero digest length for NULL auth. The above change was added to make sure the library works well with existing drivers.

Quoted 197 lines

lib/pdcp/pdcp_crypto.c

Quoted 7 lines
lib/pdcp/pdcp_crypto.c new file +6 -0
+
+		if (auth_digest_len != a_xfrm->auth.digest_length)
+			return -EINVAL;
+
+		if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_SNOW3G_UIA2))

Quoted 31 lines
lib/pdcp/pdcp_crypto.c new file +26 -0
+			auth_iv_len = PDCP_IV_LENGTH;
+		else
+			auth_iv_len = 0;
+
+		if (a_xfrm->auth.iv.length != auth_iv_len)
+			return -EINVAL;
+	}
+
+	if (!rte_cryptodev_is_valid_dev(conf->dev_id))
+		return -EINVAL;
+
+	ret = pdcp_crypto_caps_cipher_verify(conf->dev_id, c_xfrm);
+	if (ret)
+		return -ENOTSUP;
+
+	if (a_xfrm != NULL) {
+		ret = pdcp_crypto_caps_auth_verify(conf->dev_id, a_xfrm);
+		if (ret)
+			return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+int
+pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_crypto.c new file +4 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	struct entity_priv *en_priv;
+	bool is_auth_then_cipher;

lib/pdcp/pdcp_crypto.c

Quoted 10 lines
lib/pdcp/pdcp_crypto.c new file +10 -0
+	int ret;
+
+	if (entity == NULL || conf == NULL || conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->dev_id = conf->dev_id;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER)

{

Quoted 118 lines
lib/pdcp/pdcp_crypto.c new file +4 -0
+		c_xfrm = conf->crypto_xfrm;
+		a_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = false;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_crypto.c new file +8 -0
+		a_xfrm = conf->crypto_xfrm;
+		c_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = true;
+	} else {
+		return -EINVAL;
+	}
+
+	ret = pdcp_crypto_xfrm_validate(conf, c_xfrm, a_xfrm,

is_auth_then_cipher);

lib/pdcp/pdcp_crypto.c new file +14 -0
+	if (ret)
+		return ret;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
+		c_xfrm->cipher.iv.offset = 0;
+	else
+		c_xfrm->cipher.iv.offset = PDCP_IV_OFFSET;
+
+	if (a_xfrm != NULL) {
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm->auth.iv.offset = 0;
+		else
+			if (c_xfrm->cipher.iv.offset)
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET +

PDCP_IV_LENGTH;

lib/pdcp/pdcp_crypto.c new file +8 -0
+			else
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET;
+	}
+
+	if (conf->sess_mpool == NULL)
+		return -EINVAL;
+
+	en_priv->crypto_sess = rte_cryptodev_sym_session_create(conf-
Quoted 1 line

dev_id, conf->crypto_xfrm,

lib/pdcp/pdcp_crypto.c new file +1 -0
+								conf-
Quoted 1 line

sess_mpool);

lib/pdcp/pdcp_crypto.c new file +6 -0
+	if (en_priv->crypto_sess == NULL) {
+		/* API returns positive values as error codes */
+		return -rte_errno;
+	}
+
+	rte_cryptodev_sym_session_opaque_data_set(en_priv-

crypto_sess,
(uint64_t)entity);

lib/pdcp/pdcp_crypto.c new file +16 -0
+
+	return 0;
+}
+
+int
+pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
+{
+	struct entity_priv *en_priv;
+
+	if (entity == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	if (en_priv->crypto_sess != NULL) {
+		rte_cryptodev_sym_session_free(en_priv->dev_id, en_priv-
Quoted 1 line

crypto_sess);

lib/pdcp/pdcp_crypto.c new file +5 -0
+		en_priv->crypto_sess = NULL;
+	}
+
+	return 0;
+}
lib/pdcp/pdcp_crypto.h new file +12 -0
new file mode 100644
index 0000000000..dc625b35d0
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_CRYPTO_H_
+#define _PDCP_CRYPTO_H_
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_pdcp.h>
+
+#define PDCP_IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct

rte_crypto_sym_op))

lib/pdcp/pdcp_crypto.h new file +8 -0
+#define PDCP_IV_LENGTH 16
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+int pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* _PDCP_CRYPTO_H_ */
lib/pdcp/pdcp_entity.h new file +15 -0
new file mode 100644
index 0000000000..e312fd4a8c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#ifndef _PDCP_ENTITY_H_
+#define _PDCP_ENTITY_H_
+
+#include <rte_common.h>
+#include <rte_crypto_sym.h>
+#include <rte_mempool.h>
+#include <rte_pdcp.h>
+#include <rte_security.h>
+
+struct entity_priv;
+

lib/pdcp/pdcp_entity.h line 25

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+#define PDCP_PDU_HDR_SIZE_SN_12 (RTE_ALIGN_MUL_CEIL(12, 8) / 8)
+#define PDCP_PDU_HDR_SIZE_SN_18 (RTE_ALIGN_MUL_CEIL(18, 8) / 8)
+
+#define PDCP_GET_SN_12_FROM_COUNT(c) ((c) & 0xfff)
+#define PDCP_GET_SN_18_FROM_COUNT(c) ((c) & 0x3ffff)
+
+#define PDCP_GET_HFN_SN_12_FROM_COUNT(c) (((c) >> 12) & 0xfffff)
+#define PDCP_GET_HFN_SN_18_FROM_COUNT(c) (((c) >> 18) & 0x3fff)
+
+#define PDCP_SET_COUNT_FROM_HFN_SN_12(h, s) ((((h) & 0xfffff) <<

12) | ((s)

Quoted 2 lines

& 0xfff))
+#define PDCP_SET_COUNT_FROM_HFN_SN_18(h, s) ((((h) & 0x3fff) <<

18) | ((s)

lib/pdcp/pdcp_entity.h line 35

Quoted 10 lines

& 0x3ffff))

lib/pdcp/pdcp_entity.h new file +9 -0
+
+#define PDCP_SN_12_WINDOW_SZ 0x800
+#define PDCP_SN_18_WINDOW_SZ 0x20000
+
+#define PDCP_SN_12_HFN_MAX ((1 << (32 - 12)) - 1)
+#define PDCP_SN_12_HFN_MIN 0
+#define PDCP_SN_18_HFN_MAX ((1 << (32 - 18)) - 1)
+#define PDCP_SN_18_HFN_MIN 0
+

Can we have common defines for SN-12 and SN-18 and take SN as parameter?
We can have something like this.

Quoted 10 lines

#define PDCP_PDU_HDR_SIZE(sn_size) (RTE_ALIGN_MUL_CEIL((sn_size), 8) / 8)
#define PDCP_GET_SN_FROM_COUNT(c, sn_size) ((c) & ((1<<sn_size)-1)) #define PDCP_GET_HFN_FROM_COUNT(c, sn_size) (((c) >> sn_size) & ((1 << (32 - sn_size)) - 1))
#define PDCP_SET_COUNT_FROM_HFN_SN(h, s, sn_size) ((((h) & ((1 << (32
- sn_size)) - 1)) << sn_size) | ((s) & ((1<<sn_size)-1))) #define PDCP_HFN_MAX(sn_size) ((1 << (32 - (sn_size))) - 1) #define PDCP_HFN_MIN 0

[Anoob] Agreed. Will replace these macros with generic static inlines.

Quoted 84 lines

lib/pdcp/pdcp_entity.h

Quoted 2 lines
lib/pdcp/pdcp_entity.h new file +2 -0
+/* IV generation function based on the entity configuration */
+typedef void (*iv_gen_t)(struct rte_crypto_op *cop, const struct

entity_priv

Quoted 81 lines

*en_priv,

lib/pdcp/pdcp_entity.h new file +80 -0
+			 uint32_t count);
+
+enum pdcp_pdu_type {
+	PDCP_PDU_TYPE_CTRL = 0,
+	PDCP_PDU_TYPE_DATA = 1,
+};
+
+enum pdcp_up_ctrl_pdu_type {
+	PDCP_UP_CTRL_PDU_TYPE_STATUS_REPORT,
+	PDCP_UP_CTRL_PDU_TYPE_ROHC_FEEDBACK,
+	PDCP_UP_CTRL_PDU_TYPE_EHC_FEEDBACK,
+	PDCP_UP_CRTL_PDU_TYPE_UDC_FEEDBACK
+};
+
+struct entity_state {
+	uint32_t rx_next;
+	uint32_t tx_next;
+	uint32_t rx_deliv;
+	uint32_t rx_reord;
+};
+
+union auth_iv_partial {
+	/* For AES-CMAC, there is no IV, but message gets prepended */
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+	} aes_cmac;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_37_39 : 3;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_65_71 : 7;
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_120_127 : 8;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t zero_37_39 : 3;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_65_71 : 7;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t rsvd_120_127 : 8;
+#endif
+	} zs;
+	uint64_t u64[2];
+};
+
+union cipher_iv_partial {
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t zero_64_127;
+#else
+		uint64_t count : 32;
Quoted 8 lines

lib/pdcp/pdcp_entity.h line 115

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t zero_64_127;

Can we take zero_64_127 out of #if-else

[Anoob] Agreed. Will address in next version.

Quoted 24 lines
Quoted 11 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+#endif
+	} aes_ctr;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+

lib/pdcp/pdcp_entity.h line 143

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+		uint64_t rsvd_64_127;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_64_127;
+#endif

rsvd_64_127 can also be out of #if-else

Quoted 11 lines

lib/pdcp/pdcp_entity.h line 149

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+	} zs;
+	uint64_t u64[2];
+};
+
+/*
+ * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]

If the layout is fixed, can we have 0 length array in rte_pdcp_entity for entity_priv and in entity_priv for entity_dl/ul.
I see that entity_dl/ul are not completely defined. You can define them later when they are supported.

[Anoob] The implementation will be part of next version.

Quoted 5 lines
Quoted 3 lines

+ */
+

Extra line

[Anoob] The description was not just for the following struct, but the section (3 structures basically). Hence kept a blank line in between.

Quoted 69 lines
Quoted 18 lines
lib/pdcp/pdcp_entity.h new file +17 -0
+struct entity_priv {
+	/** Crypto sym session. */
+	struct rte_cryptodev_sym_session *crypto_sess;
+	/** Entity specific IV generation function. */
+	iv_gen_t iv_gen;
+	/** Pre-prepared auth IV. */
+	union auth_iv_partial auth_iv_part;
+	/** Pre-prepared cipher IV. */
+	union cipher_iv_partial cipher_iv_part;
+	/** Entity state variables. */
+	struct entity_state state;
+	/** Flags. */
+	struct {
+		/** PDCP PDU has 4 byte MAC-I. */
+		uint64_t is_authenticated : 1;
+		/** Cipher offset & length in bits. */
+		uint64_t is_ciph_in_bits : 1;

lib/pdcp/pdcp_entity.h

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+		/** Auth offset & length in bits. */
+		uint64_t is_auth_in_bits : 1;
+		/** Is UL/transmitting PDCP entity */
+		uint64_t is_ul_entity : 1;
+	} flags;
+	/** Crypto op pool. */
+	struct rte_mempool *cop_pool;
+	/** PDCP header size. */
+	uint8_t hdr_sz;
+	/** PDCP AAD size. For AES-CMAC, additional message is prepended

for

Quoted 35 lines

the operation. */

lib/pdcp/pdcp_entity.h new file +7 -0
+	uint8_t aad_sz;
+	/** Device ID of the device to be used for offload. */
+	uint8_t dev_id;
+};
+
+struct entity_priv_dl_part {
+	/* TODO - when in-order-delivery is supported, post PDCP packets

would need to cached. */

lib/pdcp/pdcp_entity.h new file +6 -0
+	uint8_t dummy;
+};
+
+struct entity_priv_ul_part {
+	/*
+	 * TODO - when re-establish is supported, both plain & post PDCP

packets would need to be

lib/pdcp/pdcp_entity.h new file +13 -0
+	 * cached.
+	 */
+	uint8_t dummy;
+};
+
+static inline struct entity_priv *
+entity_priv_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+}
+
+static inline struct entity_priv_dl_part *
+entity_dl_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +5 -0
+}
+
+static inline struct entity_priv_ul_part *
+entity_ul_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +
Quoted 2 lines

sizeof(struct entity_priv));
+}

Above inline functions may not be needed also if we have 0 len arrays.

Quoted 9 lines

lib/pdcp/pdcp_entity.h line 216

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+
+static inline int
+pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
+}

PDCP_PDU_HDR_SIZE is same as this inline function. Can we get away with this one?

[Anoob] Removed the macro.

Quoted 20 lines
Quoted 20 lines
lib/pdcp/pdcp_entity.h new file +2 -0
+
+#endif /* _PDCP_ENTITY_H_ */
lib/pdcp/pdcp_process.c new file +11 -0
new file mode 100644
index 0000000000..282cf38ec4
@@ -0,0 +1,1195 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_memcpy.h>
+#include <rte_pdcp.h>
+#include <rte_pdcp_hdr.h>
+
Quoted 8 lines

lib/pdcp/pdcp_process.c line 16

Quoted 5 lines
lib/pdcp/pdcp_process.c new file +5 -0
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+#define PDCP_MAC_I_LEN 4

Can you define it at same place where PDCP_IV_LENGTH is defined and use this in xform validate.

[Anoob] Moved to pdcp_crypto.h

Quoted 1,630 lines
Quoted 14 lines
lib/pdcp/pdcp_process.c new file +13 -0
+
+/* Enum of supported algorithms for ciphering */
+enum pdcp_cipher_algo {
+	PDCP_CIPHER_ALGO_NULL,
+	PDCP_CIPHER_ALGO_AES,
+	PDCP_CIPHER_ALGO_ZUC,
+	PDCP_CIPHER_ALGO_SNOW3G,
+	PDCP_CIPHER_ALGO_MAX
+};
+
+/* Enum of supported algorithms for integrity */
+enum pdcp_auth_algo {
+	PDCP_AUTH_ALGO_NULL,

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +10 -0
+	PDCP_AUTH_ALGO_AES,
+	PDCP_AUTH_ALGO_ZUC,
+	PDCP_AUTH_ALGO_SNOW3G,
+	PDCP_AUTH_ALGO_MAX
+};
+
+/* IV generation functions based on type of operation (cipher - auth) */
+
+static void
+pdcp_iv_gen_null_null(struct rte_crypto_op *cop, const struct

entity_priv

Quoted 11 lines

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	/* No IV required for NULL cipher + NULL auth */
+	RTE_SET_USED(cop);
+	RTE_SET_USED(en_priv);
+	RTE_SET_USED(count);
+}
+
+static void
+pdcp_iv_gen_null_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv *en_priv,

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+			  uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr;
+	uint64_t m;
+
+	/* AES-CMAC requires message to be prepended with info on count

etc

Quoted 22 lines

*/

lib/pdcp/pdcp_process.c new file +5 -0
+
+	/* Prepend by 8 bytes to add custom message */
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_null_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_null(struct rte_crypto_op *cop, const struct

entity_priv

Quoted 49 lines

*en_priv,

lib/pdcp/pdcp_process.c new file +8 -0
+			 uint32_t count)
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, 16);
+}
+
+static void
+pdcp_iv_gen_zs_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64;
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64 = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	rte_memcpy(iv, &iv_u64, 8);
+	rte_memcpy(iv + 8, &iv_u64, 8);
+}
+
+static void
+pdcp_iv_gen_zs_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	/* Generating cipher IV */
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +7 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	iv += PDCP_IV_LENGTH;
+
+	/* Generating auth IV */
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_zs_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv

Quoted 42 lines

*en_priv,

lib/pdcp/pdcp_process.c new file +10 -0
+			uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv *en_priv,

lib/pdcp/pdcp_process.c new file +11 -0
+			    uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +5 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LENGTH);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c

Quoted 5 lines
lib/pdcp/pdcp_process.c new file +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_zs(struct rte_crypto_op *cop, const struct

entity_priv

Quoted 25 lines

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c new file +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LENGTH);
+
+	iv += PDCP_IV_LENGTH;
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c new file +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static int
+pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct

rte_crypto_sym_xform **c_xfrm,

lib/pdcp/pdcp_process.c

Quoted 9 lines
lib/pdcp/pdcp_process.c new file +9 -0
+		     struct rte_crypto_sym_xform **a_xfrm)
+{
+	*c_xfrm = NULL;
+	*a_xfrm = NULL;
+
+	if (conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER)

{

Quoted 76 lines
lib/pdcp/pdcp_process.c new file +3 -0
+		*c_xfrm = conf->crypto_xfrm;
+		*a_xfrm = conf->crypto_xfrm->next;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_process.c new file +11 -0
+		*a_xfrm = conf->crypto_xfrm;
+		*c_xfrm = conf->crypto_xfrm->next;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+pdcp_iv_gen_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +23 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	enum rte_security_pdcp_direction direction;
+	enum pdcp_cipher_algo ciph_algo;
+	enum pdcp_auth_algo auth_algo;
+	struct entity_priv *en_priv;
+	int ret;
+
+	en_priv = entity_priv_get(entity);
+
+	direction = conf->pdcp_xfrm.pkt_dir;
+	if (conf->reverse_iv_direction)
+		direction = !direction;
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	memset(&en_priv->auth_iv_part, 0, sizeof(en_priv->auth_iv_part));
+	memset(&en_priv->cipher_iv_part, 0, sizeof(en_priv-

cipher_iv_part));

lib/pdcp/pdcp_process.c new file +8 -0
+
+	switch (c_xfrm->cipher.algo) {
+	case RTE_CRYPTO_CIPHER_NULL:
+		ciph_algo = PDCP_CIPHER_ALGO_NULL;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		ciph_algo = PDCP_CIPHER_ALGO_AES;
+		en_priv->cipher_iv_part.aes_ctr.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +5 -0
+		en_priv->cipher_iv_part.aes_ctr.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		ciph_algo = PDCP_CIPHER_ALGO_SNOW3G;
+		en_priv->cipher_iv_part.zs.bearer = conf-

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +5 -0
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		ciph_algo = PDCP_CIPHER_ALGO_ZUC;
+		en_priv->cipher_iv_part.zs.bearer = conf-

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +14 -0
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	if (a_xfrm != NULL) {
+		switch (a_xfrm->auth.algo) {
+		case RTE_CRYPTO_AUTH_NULL:
+			auth_algo = PDCP_AUTH_ALGO_NULL;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			auth_algo = PDCP_AUTH_ALGO_AES;
+			en_priv->auth_iv_part.aes_cmac.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c

Quoted 1 line
lib/pdcp/pdcp_process.c new file +1 -0
+			en_priv->auth_iv_part.aes_cmac.direction =

direction;

Quoted 28 lines
lib/pdcp/pdcp_process.c new file +4 -0
+			break;
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			auth_algo = PDCP_AUTH_ALGO_SNOW3G;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +6 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			auth_algo = PDCP_AUTH_ALGO_ZUC;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c new file +11 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		default:
+			return -ENOTSUP;
+		}
+	} else {
+		auth_algo = PDCP_AUTH_ALGO_NULL;
+	}
+
+	static const iv_gen_t

iv_gen_map[PDCP_CIPHER_ALGO_MAX][PDCP_AUTH_ALGO_MAX] = {

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_null_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_null_aes_cmac,

lib/pdcp/pdcp_process.c

Quoted 1 line
lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_SNOW3G]

=

Quoted 12 lines

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_aes_ctr_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_aes_ctr_aes_cmac,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c

Quoted 2 lines
lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_NULL]

=

lib/pdcp/pdcp_process.c

Quoted 7 lines

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,
+

	[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_ZUC]

=

lib/pdcp/pdcp_process.c

Quoted 7 lines

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +2 -0
+
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_SNOW3G]

=

lib/pdcp/pdcp_process.c

Quoted 12 lines

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c new file +9 -0
+	};
+
+	en_priv->iv_gen = iv_gen_map[ciph_algo][auth_algo];
+
+	return 0;
+}
+
+static inline void
+cop_prepare(const struct entity_priv *en_priv, struct rte_mbuf *mb,

struct

Quoted 31 lines

rte_crypto_op *cop,

lib/pdcp/pdcp_process.c new file +29 -0
+	    uint8_t data_offset, uint32_t count, const bool is_auth)
+{
+	const struct rte_crypto_op cop_init = {
+		.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED,
+		.sess_type = RTE_CRYPTO_OP_WITH_SESSION,
+	};
+	struct rte_crypto_sym_op *op;
+	uint32_t pkt_len;
+
+	const uint8_t ciph_shift = 3 * en_priv->flags.is_ciph_in_bits;
+	const uint8_t auth_shift = 3 * en_priv->flags.is_auth_in_bits;
+
+	op = cop->sym;
+	cop->raw = cop_init.raw;
+	op->m_src = mb;
+	op->m_dst = mb;
+
+	/* Set IV */
+	en_priv->iv_gen(cop, en_priv, count);
+
+	/* Prepare op */
+	pkt_len = rte_pktmbuf_pkt_len(mb);
+	op->cipher.data.offset = data_offset << ciph_shift;
+	op->cipher.data.length = (pkt_len - data_offset) << ciph_shift;
+
+	if (is_auth) {
+		op->auth.data.offset = 0;
+		op->auth.data.length = (pkt_len - PDCP_MAC_I_LEN) <<

auth_shift;

lib/pdcp/pdcp_process.c

Quoted 1 line
lib/pdcp/pdcp_process.c new file +1 -0
+		op->auth.digest.data = rte_pktmbuf_mtod_offset(mb,

uint8_t

lib/pdcp/pdcp_process.c

Quoted 11 lines

*,

lib/pdcp/pdcp_process.c new file +1 -0
+							       (pkt_len -

PDCP_MAC_I_LEN));

lib/pdcp/pdcp_process.c new file +3 -0
+	}
+
+	__rte_crypto_sym_op_attach_sym_session(op, en_priv-

crypto_sess);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static inline bool
+pdcp_pre_process_uplane_sn_12_ul_set_sn(struct entity_priv *en_priv,

struct

Quoted 17 lines

rte_mbuf *mb,

lib/pdcp/pdcp_process.c new file +8 -0
+					uint32_t *count)
+{
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	uint32_t sn;
+
+	/* Prepend PDU header */
+	pdu_hdr = (struct rte_pdcp_up_data_pdu_sn_12_hdr

*)rte_pktmbuf_prepend(mb, hdr_sz);

lib/pdcp/pdcp_process.c new file +5 -0
+	if (unlikely(pdu_hdr == NULL))
+		return false;
+
+	/* Update sequence num in the PDU header */
+	*count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +1 -0
+	sn = PDCP_GET_SN_12_FROM_COUNT(*count);

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +10 -0
+
+	pdu_hdr->d_c = PDCP_PDU_TYPE_DATA;
+	pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+	pdu_hdr->sn_7_0 = (sn & 0xff);
+	pdu_hdr->r = 0;
+	return true;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_ul(const struct rte_pdcp_entity

*entity,

Quoted 24 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint16_t nb_cop;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	if (en_priv->flags.is_authenticated) {
+		for (i = 0; i < nb_cop; i++) {
+			if (unlikely(rte_pktmbuf_append(mb[i],

PDCP_MAC_I_LEN) == NULL))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			if

(unlikely(!pdcp_pre_process_uplane_sn_12_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c

Quoted 2 lines
lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset,

count,

lib/pdcp/pdcp_process.c

Quoted 10 lines

true);

lib/pdcp/pdcp_process.c new file +4 -0
+		}
+	} else {
+		for (i = 0; i < nb_cop; i++) {
+			if

(unlikely(!pdcp_pre_process_uplane_sn_12_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset,

count,

lib/pdcp/pdcp_process.c

Quoted 9 lines

false);

lib/pdcp/pdcp_process.c new file +8 -0
+		}
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop

- i);

lib/pdcp/pdcp_process.c

Quoted 6 lines
lib/pdcp/pdcp_process.c new file +6 -0
+	*nb_err = num - i;
+	return i;
+}
+
+static inline bool
+pdcp_pre_process_uplane_sn_18_ul_set_sn(struct entity_priv *en_priv,

struct

Quoted 19 lines

rte_mbuf *mb,

lib/pdcp/pdcp_process.c new file +8 -0
+					uint32_t *count)
+{
+	struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr;
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	uint32_t sn;
+
+	/* Prepend PDU header */
+	pdu_hdr = (struct rte_pdcp_up_data_pdu_sn_18_hdr

*)rte_pktmbuf_prepend(mb, hdr_sz);

lib/pdcp/pdcp_process.c new file +5 -0
+	if (unlikely(pdu_hdr == NULL))
+		return false;
+
+	/* Update sequence num in the PDU header */
+	*count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +3 -0
+	sn = PDCP_GET_SN_18_FROM_COUNT(*count);
+
+	pdu_hdr->d_c = PDCP_PDU_TYPE_DATA;

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +10 -0
+	pdu_hdr->sn_17_16 = ((sn & 0x30000) >> 16);
+	pdu_hdr->sn_15_8 = ((sn & 0xff00) >> 8);
+	pdu_hdr->sn_7_0 = (sn & 0xff);
+	pdu_hdr->r = 0;
+
+	return true;
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_18_ul(const struct rte_pdcp_entity

*entity,

Quoted 24 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint16_t nb_cop;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	if (en_priv->flags.is_authenticated) {
+		for (i = 0; i < nb_cop; i++) {
+			if (unlikely(rte_pktmbuf_append(mb[i],

PDCP_MAC_I_LEN) == NULL))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			if

(unlikely(!pdcp_pre_process_uplane_sn_18_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c

Quoted 2 lines
lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset,

count,

lib/pdcp/pdcp_process.c

Quoted 10 lines

true);

lib/pdcp/pdcp_process.c new file +4 -0
+		}
+	} else {
+		for (i = 0; i < nb_cop; i++) {
+			if

(unlikely(!pdcp_pre_process_uplane_sn_18_ul_set_sn(en_priv, mb[i], +
&count)))

lib/pdcp/pdcp_process.c new file +2 -0
+				goto cop_free;
+			cop_prepare(en_priv, mb[i], cop[i], data_offset,

count,

lib/pdcp/pdcp_process.c

Quoted 10 lines

false);

lib/pdcp/pdcp_process.c new file +9 -0
+		}
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop

- i);

lib/pdcp/pdcp_process.c

Quoted 6 lines
lib/pdcp/pdcp_process.c new file +6 -0
+	*nb_err = num - i;
+	return i;
+}
+
+static uint16_t
+pdcp_pre_process_cplane_sn_12_ul(const struct rte_pdcp_entity

*entity,

Quoted 23 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +11 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_cp_data_pdu_sn_12_hdr *pdu_hdr;
+	uint32_t count, sn;
+	uint16_t nb_cop;
+	int i;
+
+	const uint8_t hdr_sz = en_priv->hdr_sz;
+	const uint8_t data_offset = hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		/* Prepend PDU header */
+		pdu_hdr = (struct rte_pdcp_cp_data_pdu_sn_12_hdr

*)rte_pktmbuf_prepend(mb[i],
+

	       hdr_sz);

lib/pdcp/pdcp_process.c

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0
+		if (unlikely(pdu_hdr == NULL))
+			goto cop_free;
+		if (unlikely(rte_pktmbuf_append(mb[i], PDCP_MAC_I_LEN)

==

lib/pdcp/pdcp_process.c

Quoted 13 lines

NULL))

lib/pdcp/pdcp_process.c new file +4 -0
+			goto cop_free;
+
+		/* Update sequence number in the PDU header */
+		count = __atomic_fetch_add(&en_priv->state.tx_next, 1,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +7 -0
+		sn = PDCP_GET_SN_12_FROM_COUNT(count);
+
+		pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+		pdu_hdr->r = 0;
+
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

true);

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+
+cop_free:
+	/* Using mempool API since crypto API is not providing bulk free */
+	rte_mempool_put_bulk(en_priv->cop_pool, (void *)&cop[i], nb_cop

- i);

lib/pdcp/pdcp_process.c

Quoted 6 lines
lib/pdcp/pdcp_process.c new file +6 -0
+	*nb_err = num - i;
+	return i;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_12_ul(const struct rte_pdcp_entity

*entity,

Quoted 27 lines
lib/pdcp/pdcp_process.c new file +13 -0
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c

Quoted 7 lines
lib/pdcp/pdcp_process.c new file +7 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_uplane_sn_18_ul(const struct rte_pdcp_entity

*entity,

Quoted 27 lines
lib/pdcp/pdcp_process.c new file +13 -0
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c

Quoted 7 lines
lib/pdcp/pdcp_process.c new file +7 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static uint16_t
+pdcp_post_process_cplane_sn_12_ul(const struct rte_pdcp_entity

*entity,

Quoted 44 lines
lib/pdcp/pdcp_process.c new file +12 -0
+				  struct rte_mbuf *in_mb[],
+				  struct rte_mbuf *out_mb[],
+				  uint16_t num, uint16_t *nb_err_ret)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	const uint32_t hdr_trim_sz = en_priv->aad_sz;
+	int i, nb_success = 0, nb_err = 0;
+	struct rte_mbuf *mb, *err_mb[num];
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {

lib/pdcp/pdcp_process.c new file +12 -0
+			err_mb[nb_err++] = mb;
+			continue;
+		}
+
+		if (hdr_trim_sz)
+			rte_pktmbuf_adj(mb, hdr_trim_sz);
+
+		out_mb[nb_success++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +7 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
+}
+
+static inline int
+pdcp_sn_18_count_get(const struct rte_pdcp_entity *entity, int32_t rsn,

uint32_t *count)

lib/pdcp/pdcp_process.c new file +5 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint32_t rhfn, rx_deliv;
+
+	rx_deliv = __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +3 -0
+	rhfn = PDCP_GET_HFN_SN_18_FROM_COUNT(rx_deliv);
+
+	if (rsn < (int32_t)(PDCP_GET_SN_18_FROM_COUNT(rx_deliv) -

PDCP_SN_18_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c

Quoted 4 lines
lib/pdcp/pdcp_process.c new file +4 -0
+		if (unlikely(rhfn == PDCP_SN_18_HFN_MAX))
+			return -ERANGE;
+		rhfn += 1;
+	} else if ((uint32_t)rsn >=

(PDCP_GET_SN_18_FROM_COUNT(rx_deliv) +

Quoted 24 lines

PDCP_SN_18_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +12 -0
+		if (unlikely(rhfn == PDCP_SN_18_HFN_MIN))
+			return -ERANGE;
+		rhfn -= 1;
+	}
+
+	*count = PDCP_SET_COUNT_FROM_HFN_SN_18(rhfn, rsn);
+
+	return 0;
+}
+
+static inline int
+pdcp_sn_12_count_get(const struct rte_pdcp_entity *entity, int32_t rsn,

uint32_t *count)

lib/pdcp/pdcp_process.c new file +5 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	uint32_t rhfn, rx_deliv;
+
+	rx_deliv = __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +3 -0
+	rhfn = PDCP_GET_HFN_SN_12_FROM_COUNT(rx_deliv);
+
+	if (rsn < (int32_t)(PDCP_GET_SN_12_FROM_COUNT(rx_deliv) -

PDCP_SN_12_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c

Quoted 4 lines
lib/pdcp/pdcp_process.c new file +4 -0
+		if (unlikely(rhfn == PDCP_SN_12_HFN_MAX))
+			return -ERANGE;
+		rhfn += 1;
+	} else if ((uint32_t)rsn >=

(PDCP_GET_SN_12_FROM_COUNT(rx_deliv) +

Quoted 14 lines

PDCP_SN_12_WINDOW_SZ)) {

lib/pdcp/pdcp_process.c new file +12 -0
+		if (unlikely(rhfn == PDCP_SN_12_HFN_MIN))
+			return -ERANGE;
+		rhfn -= 1;
+	}
+
+	*count = PDCP_SET_COUNT_FROM_HFN_SN_12(rhfn, rsn);
+
+	return 0;
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity

*entity, struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c

Quoted 1 line
lib/pdcp/pdcp_process.c new file +1 -0
+				       struct rte_crypto_op *cop[], uint16_t

num,

Quoted 32 lines

uint16_t *nb_err,

lib/pdcp/pdcp_process.c new file +12 -0
+				       const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	int32_t rsn = 0;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +5 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_up_data_pdu_sn_12_hdr *);

lib/pdcp/pdcp_process.c new file +4 -0
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr-

sn_7_0));

lib/pdcp/pdcp_process.c new file +6 -0
+		else
+			rte_panic("TODO: Control PDU not handled");
+
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

is_integ_protected);

lib/pdcp/pdcp_process.c

Quoted 9 lines
lib/pdcp/pdcp_process.c new file +9 -0
+	}
+
+	*nb_err = num - nb_cop;
+
+	return nb_cop;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_dl_ip(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c

Quoted 5 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				    struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_12_dl_flags(entity, mb, cop,

num,

lib/pdcp/pdcp_process.c

Quoted 5 lines

nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_12_dl(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c

Quoted 5 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_12_dl_flags(entity, mb, cop,

num,

lib/pdcp/pdcp_process.c

Quoted 7 lines

nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static inline uint16_t
+pdcp_pre_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity

*entity, struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				       struct rte_crypto_op *cop[], uint16_t

num,

Quoted 32 lines

uint16_t *nb_err,

lib/pdcp/pdcp_process.c new file +11 -0
+				       const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	int32_t rsn = 0;
+	uint32_t count;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +4 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_up_data_pdu_sn_18_hdr *);

lib/pdcp/pdcp_process.c new file +4 -0
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_17_16 << 16) | (pdu_hdr-

sn_15_8
<< 8) |

lib/pdcp/pdcp_process.c new file +7 -0
+			       (pdu_hdr->sn_7_0));
+		else
+			rte_panic("TODO: Control PDU not handled");
+
+		if (unlikely(pdcp_sn_18_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

is_integ_protected);

lib/pdcp/pdcp_process.c

Quoted 9 lines
lib/pdcp/pdcp_process.c new file +9 -0
+	}
+
+	*nb_err = num - nb_cop;
+
+	return nb_cop;
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_18_dl_ip(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c

Quoted 5 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				    struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_18_dl_flags(entity, mb, cop,

num,

lib/pdcp/pdcp_process.c

Quoted 5 lines

nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_uplane_sn_18_dl(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c

Quoted 5 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +2 -0
+{
+	return pdcp_pre_process_uplane_sn_18_dl_flags(entity, mb, cop,

num,

lib/pdcp/pdcp_process.c

Quoted 5 lines

nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0
+}
+
+static uint16_t
+pdcp_pre_process_cplane_sn_12_dl(const struct rte_pdcp_entity

*entity,

Quoted 20 lines

struct rte_mbuf *mb[],

lib/pdcp/pdcp_process.c new file +1 -0
+				 struct rte_crypto_op *cop[], uint16_t num,

uint16_t *nb_err)

lib/pdcp/pdcp_process.c new file +11 -0
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_cp_data_pdu_sn_12_hdr *pdu_hdr;
+	uint16_t nb_cop;
+	uint32_t count;
+	int32_t rsn;
+	int i;
+
+	const uint8_t data_offset = en_priv->hdr_sz + en_priv->aad_sz;
+
+	nb_cop = rte_crypto_op_bulk_alloc(en_priv->cop_pool,

RTE_CRYPTO_OP_TYPE_SYMMETRIC, cop,

lib/pdcp/pdcp_process.c new file +4 -0
+					  num);
+
+	for (i = 0; i < nb_cop; i++) {
+		pdu_hdr = rte_pktmbuf_mtod(mb[i], struct

rte_pdcp_cp_data_pdu_sn_12_hdr *);

lib/pdcp/pdcp_process.c

Quoted 4 lines
lib/pdcp/pdcp_process.c new file +4 -0
+		rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr->sn_7_0));
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			break;
+		cop_prepare(en_priv, mb[i], cop[i], data_offset, count,

true);

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+	}
+
+	*nb_err = num - nb_cop;
+	return nb_cop;
+}
+
+static inline bool
+pdcp_post_process_update_entity_state(const struct rte_pdcp_entity

*entity,

Quoted 83 lines
lib/pdcp/pdcp_process.c new file +5 -0
+				      const uint32_t count)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+
+	if (count < __atomic_load_n(&en_priv->state.rx_deliv,

__ATOMIC_RELAXED))

lib/pdcp/pdcp_process.c new file +3 -0
+		return false;
+
+	/* t-Reordering timer is not supported - SDU will be delivered

immediately.

lib/pdcp/pdcp_process.c new file +1 -0
+	 * Update RX_DELIV to the COUNT value of the first PDCP SDU which

has not

lib/pdcp/pdcp_process.c new file +3 -0
+	 * been delivered to upper layers
+	 */
+	__atomic_store_n(&en_priv->state.rx_deliv, (count + 1),

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +2 -0
+
+	if (count >= __atomic_load_n(&en_priv->state.rx_next,

__ATOMIC_RELAXED))

lib/pdcp/pdcp_process.c new file +1 -0
+		__atomic_store_n(&en_priv->state.rx_next, (count + 1),

__ATOMIC_RELAXED);

lib/pdcp/pdcp_process.c new file +6 -0
+
+	return true;
+}
+
+static inline uint16_t
+pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity

*entity,

lib/pdcp/pdcp_process.c new file +18 -0
+					struct rte_mbuf *in_mb[],
+					struct rte_mbuf *out_mb[],
+					uint16_t num, uint16_t *nb_err_ret,
+					const bool is_integ_protected)
+{
+	struct entity_priv *en_priv = entity_priv_get(entity);
+	struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr;
+	int i, nb_success = 0, nb_err = 0, rsn = 0;
+	const uint32_t aad_sz = en_priv->aad_sz;
+	struct rte_mbuf *err_mb[num];
+	struct rte_mbuf *mb;
+	uint32_t count;
+
+	const uint32_t hdr_trim_sz = en_priv->hdr_sz + aad_sz;
+
+	for (i = 0; i < num; i++) {
+		mb = in_mb[i];
+		if (unlikely(mb->ol_flags &

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +2 -0
+			goto error;
+		pdu_hdr = rte_pktmbuf_mtod_offset(mb, struct

rte_pdcp_up_data_pdu_sn_12_hdr *,

lib/pdcp/pdcp_process.c new file +5 -0
+						  aad_sz);
+
+		/* Check for PDU type */
+		if (likely(pdu_hdr->d_c == PDCP_PDU_TYPE_DATA))
+			rsn = ((pdu_hdr->sn_11_8 << 8) | (pdu_hdr-

sn_7_0));

lib/pdcp/pdcp_process.c new file +7 -0
+		else
+			rte_panic("Control PDU should not be received");
+
+		if (unlikely(pdcp_sn_12_count_get(entity, rsn, &count)))
+			goto error;
+
+		if (unlikely(!pdcp_post_process_update_entity_state(entity,

count)))

lib/pdcp/pdcp_process.c new file +14 -0
+			goto error;
+
+		rte_pktmbuf_adj(mb, hdr_trim_sz);
+		if (is_integ_protected)
+			rte_pktmbuf_trim(mb, PDCP_MAC_I_LEN);
+		out_mb[nb_success++] = mb;
+		continue;
+
+error:
+		err_mb[nb_err++] = mb;
+	}
+
+	if (unlikely(nb_err != 0))
+		rte_memcpy(&out_mb[nb_success], err_mb, nb_err *

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c line 567

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0
+
+	*nb_err_ret = nb_err;
+	return nb_success;
[… more lines in the raw message]

*entity,

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

out_mb, num, nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*entity,

lib/pdcp/pdcp_process.c

Quoted 72 lines
lib/pdcp/pdcp_process.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

out_mb, num, nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*entity,

lib/pdcp/pdcp_process.c new file +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

rte_pdcp_up_data_pdu_sn_18_hdr *,

lib/pdcp/pdcp_process.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

sn_15_8
<< 8) |

lib/pdcp/pdcp_process.c new file +8 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

count)))

lib/pdcp/pdcp_process.c new file +14 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*entity,

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

out_mb, num, nb_err, true);

lib/pdcp/pdcp_process.c new file +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*entity,

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +5 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

out_mb, num, nb_err, false);

lib/pdcp/pdcp_process.c new file +4 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

*entity,

lib/pdcp/pdcp_process.c

Quoted 62 lines
lib/pdcp/pdcp_process.c new file +18 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))

lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

rte_pdcp_cp_data_pdu_sn_12_hdr *,

lib/pdcp/pdcp_process.c new file +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

count)))

lib/pdcp/pdcp_process.c new file +13 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

sizeof(struct rte_mbuf *));

lib/pdcp/pdcp_process.c new file +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +7 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

RTE_SECURITY_PDCP_MODE_CONTROL) &&

lib/pdcp/pdcp_process.c new file +1 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&&

lib/pdcp/pdcp_process.c

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

pdcp_post_process_cplane_sn_12_ul;

lib/pdcp/pdcp_process.c

Quoted 5 lines
lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

RTE_SECURITY_PDCP_MODE_CONTROL) &&

lib/pdcp/pdcp_process.c new file +1 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

&&

lib/pdcp/pdcp_process.c

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

pdcp_post_process_cplane_sn_12_dl;

lib/pdcp/pdcp_process.c

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

RTE_SECURITY_PDCP_MODE_DATA)

384 lines not shown · raw message

Quoted 8 lines

7 lines not shown · raw message

474 lines not shown · raw message

Parts of this message are not shown here. View the raw message.

#14 lore raw

PATCH 3/5 app/test: add lib pdcp tests

In reply to Anoob Joseph

Add tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.

---
 app/test/meson.build      |   1 +
 app/test/test_cryptodev.h |   3 +
 app/test/test_pdcp.c      | 663 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 667 insertions(+)
 create mode 100644 app/test/test_pdcp.c
app/test/meson.build +1 -0
index 1b9ce355f8..7e1f3f6543 100644
@@ -95,6 +95,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +3 -0
index abd795f54a..89057dba22 100644
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+
 #define HEX_DUMP 0
 
 #define FALSE                           0
app/test/test_pdcp.c new file +663 -0

663 lines not on this page · raw message

Signature · 1 line
2.25.1
#15 lore raw

PATCH 4/5 app/test: pdcp HFN tests in combined mode

In reply to Anoob Joseph

From: Volodymyr Fialko <[email protected]>

Add tests to verify HFN/SN behaviour.

---
 app/test/test_pdcp.c | 390 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 363 insertions(+), 27 deletions(-)
app/test/test_pdcp.c +363 -27
index 10a383ddd7..1e74147579 100644
@@ -4,6 +4,7 @@
 
 #include <rte_malloc.h>
 #include <rte_pdcp.h>
+#include <rte_pdcp_hdr.h>
 
 #include "test.h"
 #include "test_cryptodev.h"
@@ -19,17 +20,17 @@ struct pdcp_testsuite_params {
 
 static struct pdcp_testsuite_params testsuite_params;
 
-#define PDCP_MAX_TEST_INPUT_LEN 2048
+#define PDCP_MAX_TEST_DATA_LEN 2048
 
 struct pdcp_test_conf {
 	struct rte_pdcp_entity_conf entity;
 	struct rte_crypto_sym_xform c_xfrm;
 	struct rte_crypto_sym_xform a_xfrm;
 	bool is_integrity_protected;
-	uint8_t input[PDCP_MAX_TEST_INPUT_LEN];
+	uint8_t input[PDCP_MAX_TEST_DATA_LEN];
 	uint32_t input_len;
-	const uint8_t *expected;
-	uint32_t expected_len;
+	uint8_t output[PDCP_MAX_TEST_DATA_LEN];
+	uint32_t output_len;
 };
 
 static inline int
@@ -38,6 +39,19 @@ pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
 	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
 }
 
+static int
+pktmbuf_read_into(const struct rte_mbuf *m, void *buf, size_t buf_len)
+{
+	if (m->pkt_len > buf_len)
+		return -ENOMEM;
+
+	const void *read = rte_pktmbuf_read(m, 0, m->pkt_len, buf);
+	if (read != NULL && read != buf)
+		memcpy(buf, read, m->pkt_len);
+
+	return 0;
+}
+
 static int
 cryptodev_init(int dev_id)
 {
@@ -300,14 +314,45 @@ process_crypto_request(uint8_t dev_id, struct rte_crypto_op *op)
 	return op;
 }
 
+static uint32_t
+pdcp_sn_from_raw_get(const void *data, enum rte_security_pdcp_sn_size size)
+{
+	uint32_t sn = 0;
+
+	if (size == RTE_SECURITY_PDCP_SN_SIZE_12) {
+		sn = rte_cpu_to_be_16(*(const uint16_t *)data);
+		sn = sn & 0xfff;
+	} else if (size == RTE_SECURITY_PDCP_SN_SIZE_18) {
+		sn = rte_cpu_to_be_32(*(const uint32_t *)data);
+		sn = (sn & 0x3ffff00) >> 8;
+	}
+
+	return sn;
+}
+
+static void
+pdcp_sn_to_raw_set(void *data, uint32_t sn, int size)
+{
+	if (size == RTE_SECURITY_PDCP_SN_SIZE_12) {
+		struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr = data;
+		pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+	} else if (size == RTE_SECURITY_PDCP_SN_SIZE_18) {
+		struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr = data;
+		pdu_hdr->sn_17_16 = ((sn & 0x30000) >> 16);
+		pdu_hdr->sn_15_8 = ((sn & 0xff00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+	}
+}
+
 static int
 create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 {
 	const struct pdcp_testsuite_params *ts_params = &testsuite_params;
 	struct rte_crypto_sym_xform c_xfrm, a_xfrm;
-	uint32_t hfn, sn, count = 0;
+	uint32_t hfn, sn, expected_len, count = 0;
+	uint8_t *data, *expected;
 	int pdcp_hdr_sz;
-	uint8_t *data;
 
 	memset(conf, 0, sizeof(*conf));
 	memset(&c_xfrm, 0, sizeof(c_xfrm));
@@ -326,6 +371,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 		conf->entity.pdcp_xfrm.pkt_dir = RTE_SECURITY_PDCP_DOWNLINK;
 
 	conf->entity.pdcp_xfrm.sn_size = pdcp_test_data_sn_size[index];
+	/* Zero initialize unsupported flags */
 	conf->entity.pdcp_xfrm.hfn_threshold = 0;
 	conf->entity.pdcp_xfrm.hfn_ovrd = 0;
 	conf->entity.pdcp_xfrm.sdap_enabled = 0;
@@ -414,14 +460,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 	    pdcp_test_params[index].domain == RTE_SECURITY_PDCP_MODE_DATA) {
 		data = pdcp_test_data_in[index];
 		hfn = pdcp_test_hfn[index] << pdcp_test_data_sn_size[index];
-		sn = 0;
-		if (pdcp_test_data_sn_size[index] == RTE_SECURITY_PDCP_SN_SIZE_12) {
-			sn = rte_cpu_to_be_16(*(uint16_t *)data);
-			sn = sn & 0xfff;
-		} else if (pdcp_test_data_sn_size[index] == RTE_SECURITY_PDCP_SN_SIZE_18) {
-			sn = rte_cpu_to_be_32(*(uint32_t *)data);
-			sn = (sn & 0x3ffff00) >> 8;
-		}
+		sn = pdcp_sn_from_raw_get(data, pdcp_test_data_sn_size[index]);
 		count = hfn | sn;
 	}
 	conf->entity.count = count;
@@ -448,29 +487,32 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 	}
 
 	if (conf->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
-		conf->expected = pdcp_test_data_out[index];
+		expected = pdcp_test_data_out[index];
 	else
-		conf->expected = pdcp_test_data_in[index];
+		expected = pdcp_test_data_in[index];
 
 	/* Calculate expected packet length */
-	conf->expected_len = pdcp_test_data_in_len[index];
+	expected_len = pdcp_test_data_in_len[index];
 
 	/* In DL processing, PDCP header would be stripped */
 	if (conf->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
-		conf->expected += pdcp_hdr_sz;
-		conf->expected_len -= pdcp_hdr_sz;
+		expected += pdcp_hdr_sz;
+		expected_len -= pdcp_hdr_sz;
 	}
 
 	/* In UL processing with integrity protection, MAC would be added */
 	if (conf->is_integrity_protected &&
 	    conf->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
-		conf->expected_len += 4;
+		expected_len += 4;
+
+	memcpy(conf->output, expected, expected_len);
+	conf->output_len = expected_len;
 
 	return 0;
 }
 
 static int
-test_attempt_single(const struct pdcp_test_conf *t_conf)
+test_attempt_single(struct pdcp_test_conf *t_conf)
 {
 	const struct pdcp_testsuite_params *ts_params = &testsuite_params;
 	struct rte_mbuf *mbuf, *mb, **out_mb = NULL;
@@ -584,9 +626,17 @@ test_attempt_single(const struct pdcp_test_conf *t_conf)
 		goto mbuf_free;
 	}
 
-	ret = pdcp_known_vec_verify(mbuf, t_conf->expected, t_conf->expected_len);
-	if (ret)
-		goto mbuf_free;
+	/* If expected output provided - verify, else - store for future use */
+	if (t_conf->output_len) {
+		ret = pdcp_known_vec_verify(mbuf, t_conf->output, t_conf->output_len);
+		if (ret)
+			goto mbuf_free;
+	} else {
+		ret = pktmbuf_read_into(mbuf, t_conf->output, PDCP_MAX_TEST_DATA_LEN);
+		if (ret)
+			goto mbuf_free;
+		t_conf->output_len = mbuf->pkt_len;
+	}
 
 	ret = rte_pdcp_entity_suspend(pdcp_entity, out_mb);
 	if (ret) {
@@ -609,6 +659,195 @@ test_attempt_single(const struct pdcp_test_conf *t_conf)
 	return TEST_FAILED;
 }
 
+static void
+uplink_to_downlink_convert(const struct pdcp_test_conf *ul_cfg,
+			   struct pdcp_test_conf *dl_cfg)
+{
+	assert(ul_cfg->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK);
+
+	memcpy(dl_cfg, ul_cfg, sizeof(*dl_cfg));
+	dl_cfg->entity.pdcp_xfrm.pkt_dir = RTE_SECURITY_PDCP_DOWNLINK;
+	dl_cfg->entity.reverse_iv_direction = false;
+
+	if (dl_cfg->is_integrity_protected) {
+		dl_cfg->entity.crypto_xfrm = &dl_cfg->c_xfrm;
+
+		dl_cfg->c_xfrm.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+		dl_cfg->c_xfrm.next = &dl_cfg->a_xfrm;
+
+		dl_cfg->a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+		dl_cfg->a_xfrm.next = NULL;
+	} else {
+		dl_cfg->entity.crypto_xfrm = &dl_cfg->c_xfrm;
+		dl_cfg->c_xfrm.next = NULL;
+		dl_cfg->c_xfrm.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+	}
+
+	memcpy(dl_cfg->input, ul_cfg->output, ul_cfg->output_len);
+	dl_cfg->input_len = ul_cfg->output_len;
+
+	memcpy(dl_cfg->output, ul_cfg->input, ul_cfg->input_len);
+	dl_cfg->output_len = ul_cfg->input_len;
+}
+
+/*
+ * According to ETSI TS 138 323 V17.1.0, Section 5.2.2.1,
+ * SN could be divided into following ranges,
+ * relatively to current value of RX_DELIV state:
+ * +-------------+-------------+-------------+-------------+
+ * |  -Outside   |  -Window    |   +Window   |  +Outside   |
+ * |   (valid)   |  (Invalid)  |   (Valid)   |  (Invalid)  |
+ * +-------------+-------------^-------------+-------------+
+ *                             |
+ *                             v
+ *                        SN(RX_DELIV)
+ */
+enum sn_range_type {
+	SN_RANGE_MINUS_OUTSIDE,
+	SN_RANGE_MINUS_WINDOW,
+	SN_RANGE_PLUS_WINDOW,
+	SN_RANGE_PLUS_OUTSIDE,
+};
+
+#define PDCP_SET_COUNT(hfn, sn, size) ((hfn << size) | (sn & ((1 << size) - 1)))
+
+/*
+ * Take uplink test case as base, modify RX_DELIV in state and SN in input
+ */
+static int
+test_sn_range_type_with_config(enum sn_range_type type, struct pdcp_test_conf *conf)
+{
+	uint32_t rx_deliv_hfn, rx_deliv_sn, rx_deliv, new_hfn, new_sn;
+	const int domain = conf->entity.pdcp_xfrm.domain;
+	struct pdcp_test_conf dl_conf;
+	int ret, expected_ret;
+
+	if (domain != RTE_SECURITY_PDCP_MODE_CONTROL && domain != RTE_SECURITY_PDCP_MODE_DATA)
+		return TEST_SKIPPED;
+
+	const uint32_t sn_size = conf->entity.pdcp_xfrm.sn_size;
+	/* According to formula(7.2.a Window_Size) */
+	const uint32_t window_size = 1 << (sn_size - 1);
+	/* Max value of SN that could fit in `sn_size` bits */
+	const uint32_t max_sn = (1 << sn_size) - 1;
+	const uint32_t shift = (max_sn - window_size) / 2;
+	/* Could be any number up to `shift` value */
+	const uint32_t default_sn = RTE_MIN(2u, shift);
+
+	/* Initialize HFN as non zero value, to be able check values before */
+	rx_deliv_hfn = 0xa;
+
+	switch (type) {
+	case SN_RANGE_PLUS_WINDOW:
+		/* Within window size, HFN stay same */
+		new_hfn = rx_deliv_hfn;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn + 1;
+		expected_ret = TEST_SUCCESS;
+		break;
+	case SN_RANGE_MINUS_WINDOW:
+		/* Within window size, HFN stay same */
+		new_hfn = rx_deliv_hfn;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn - 1;
+		expected_ret = TEST_FAILED;
+		break;
+	case SN_RANGE_PLUS_OUTSIDE:
+		/* RCVD_SN >= SN(RX_DELIV) + Window_Size */
+		new_hfn = rx_deliv_hfn - 1;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn + window_size;
+		expected_ret = TEST_FAILED;
+		break;
+	case SN_RANGE_MINUS_OUTSIDE:
+		/* RCVD_SN < SN(RX_DELIV) - Window_Size */
+		new_hfn = rx_deliv_hfn + 1;
+		rx_deliv_sn = window_size + default_sn;
+		new_sn = rx_deliv_sn - window_size - 1;
+		expected_ret = TEST_SUCCESS;
+		break;
+	default:
+		return TEST_FAILED;
+	}
+
+	rx_deliv = PDCP_SET_COUNT(rx_deliv_hfn, rx_deliv_sn, sn_size);
+
+	/* Configure Uplink to generate expected, encrypted packet */
+	pdcp_sn_to_raw_set(conf->input, new_sn, conf->entity.pdcp_xfrm.sn_size);
+	conf->entity.reverse_iv_direction = true;
+	conf->entity.count = PDCP_SET_COUNT(new_hfn, new_sn, sn_size);
+	conf->output_len = 0;
+	ret = test_attempt_single(conf);
+	if (ret != TEST_SUCCESS)
+		return ret;
+
+	/* Flip configuration to downlink */
+	uplink_to_downlink_convert(conf, &dl_conf);
+	/* Modify the rx_deliv to verify the expected behaviour */
+	dl_conf.entity.count = rx_deliv;
+	ret = test_attempt_single(&dl_conf);
+	if (ret == TEST_SKIPPED)
+		return TEST_SKIPPED;
+	TEST_ASSERT_EQUAL(ret, expected_ret, "Unexpected result");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_sn_range_type(enum sn_range_type type)
+{
+	int i, ret, passed = 0;
+	struct pdcp_test_conf t_conf;
+
+	int nb_test = RTE_DIM(pdcp_test_params);
+
+	for (i = 0; i < nb_test; i++) {
+		create_test_conf_from_index(i, &t_conf);
+		if (t_conf.entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+			continue;
+		printf("[%03i] - %s", i, pdcp_test_params[i].name);
+		ret = test_sn_range_type_with_config(type, &t_conf);
+		if (ret == TEST_FAILED) {
+			printf(" - failed\n");
+			return ret;
+		} else if (ret == TEST_SKIPPED) {
+			printf(" - skipped\n");
+			continue;
+		}
+		printf(" - passed\n");
+		passed += 1;
+	}
+
+	printf("Passed: %i\n", passed);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_sn_plus_window(void)
+{
+	return test_sn_range_type(SN_RANGE_PLUS_WINDOW);
+}
+
+static int
+test_sn_minus_window(void)
+{
+	return test_sn_range_type(SN_RANGE_MINUS_WINDOW);
+}
+
+
+static int
+test_sn_plus_outside(void)
+{
+	return test_sn_range_type(SN_RANGE_PLUS_OUTSIDE);
+}
+
+static int
+test_sn_minus_outside(void)
+{
+	return test_sn_range_type(SN_RANGE_MINUS_OUTSIDE);
+}
+
 static int
 test_iterate_all(void)
 {
@@ -632,6 +871,7 @@ test_iterate_all(void)
 		printf(" - passed\n");
 		passed += 1;
 	}
+
 	printf("Passed: %i\n", passed);
 
 	return TEST_SUCCESS;
@@ -643,8 +883,52 @@ test_sample(void)
 	return test_iterate_all();
 }
 
-static struct unit_test_suite pdcp_testsuite  = {
-	.suite_name = "PDCP Unit Test Suite",
+static int
+test_combined(void)
+{
+	struct pdcp_test_conf ul_conf, dl_conf;
+	int ret, nb_test, i, passed = 0;
+
+	nb_test = RTE_DIM(pdcp_test_params);
+
+	for (i = 0; i < nb_test; i++) {
+		create_test_conf_from_index(i, &ul_conf);
+		if (ul_conf.entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+			continue;
+
+		ul_conf.entity.reverse_iv_direction = true;
+		ul_conf.output_len = 0;
+		printf("[%03i] - %s", i, pdcp_test_params[i].name);
+
+		ret = test_attempt_single(&ul_conf);
+		if (ret == TEST_FAILED) {
+			printf(" - failed\n");
+			return ret;
+		} else if (ret == TEST_SKIPPED) {
+			printf(" - skipped\n");
+			continue;
+		}
+
+		uplink_to_downlink_convert(&ul_conf, &dl_conf);
+		ret = test_attempt_single(&dl_conf);
+		if (ret == TEST_FAILED) {
+			printf(" - failed\n");
+			return ret;
+		} else if (ret == TEST_SKIPPED) {
+			printf(" - skipped\n");
+			continue;
+		}
+
+		printf(" - passed\n");
+		passed += 1;
+	}
+	printf("Passed: %i\n", passed);
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite known_vector_cases  = {
+	.suite_name = "PDCP known vectors",
 	.setup = testsuite_setup,
 	.teardown = testsuite_teardown,
 	.unit_test_cases = {
@@ -654,10 +938,62 @@ static struct unit_test_suite pdcp_testsuite  = {
 	}
 };
 
+static struct unit_test_suite combined_mode_cases  = {
+	.suite_name = "PDCP combined mode",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup_pdcp, ut_teardown_pdcp,
+			test_combined),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static struct unit_test_suite hfn_sn_test_cases  = {
+	.suite_name = "PDCP HFN/SN",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(ut_setup_pdcp, ut_teardown_pdcp,
+			test_sn_plus_window),
+		TEST_CASE_ST(ut_setup_pdcp, ut_teardown_pdcp,
+			test_sn_minus_window),
+		TEST_CASE_ST(ut_setup_pdcp, ut_teardown_pdcp,
+			test_sn_plus_outside),
+		TEST_CASE_ST(ut_setup_pdcp, ut_teardown_pdcp,
+			test_sn_minus_outside),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
 static int
 test_pdcp(void)
 {
-	return unit_test_suite_runner(&pdcp_testsuite);
+	int ret;
+
+	static struct unit_test_suite pdcp_testsuite  = {
+		.suite_name = "PDCP Unit Test Suite",
+		.unit_test_cases = {TEST_CASES_END()},
+	};
+
+	struct unit_test_suite *static_suites[] = {
+		&known_vector_cases,
+		&combined_mode_cases,
+		&hfn_sn_test_cases,
+		NULL /* End of suites list */
+	};
+
+	pdcp_testsuite.unit_test_suites = rte_zmalloc(NULL, sizeof(static_suites), 0);
+	if (pdcp_testsuite.unit_test_suites == NULL) {
+		RTE_LOG(ERR, USER1, "No memory for: '%s'\n", pdcp_testsuite.suite_name);
+		return TEST_FAILED;
+	}
+
+	memcpy(pdcp_testsuite.unit_test_suites, static_suites, sizeof(static_suites));
+
+	ret = unit_test_suite_runner(&pdcp_testsuite);
+	rte_free(pdcp_testsuite.unit_test_suites);
+	return ret;
 }
 
 REGISTER_TEST_COMMAND(pdcp_autotest, test_pdcp);
Signature · 1 line
2.25.1
#16 lore raw

PATCH 5/5 doc: add PDCP library guide

In reply to Anoob Joseph

Add guide for PDCP library.

---
 .../img/pdcp_functional_overview.svg          |   1 +
 doc/guides/prog_guide/index.rst               |   1 +
 doc/guides/prog_guide/pdcp_lib.rst            | 211 ++++++++++++++++++
 3 files changed, 213 insertions(+)
 create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg
 create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
doc/guides/prog_guide/img/pdcp_functional_overview.svg new file +1 -0
new file mode 100644
index 0000000000..287daafc21
@@ -0,0 +1 @@
+<svg width="1280" height="720" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden"><defs><clipPath id="clip0"><rect x="0" y="0" width="1280" height="720"/></clipPath></defs><g clip-path="url(#clip0)"><rect x="0" y="0" width="1280" height="720" fill="#FFFFFF"/><rect x="202" y="100" width="369" height="457" fill="#A5A5A5" fill-opacity="0.501961"/><rect x="640" y="100" width="369" height="457" fill="#A5A5A5" fill-opacity="0.501961"/><path d="M605.5 73.5001 605.5 590.633" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M380.5 634 803.25 634 803.25 585.907 790.5 585.907 816 557.5 841.5 585.907 828.75 585.907 828.75 659.5 380.5 659.5Z" stroke="#787878" stroke-width="1.33333" stroke-miterlimit="8" fill="#A5A5A5" fill-rule="evenodd"/><rect x="362.5" y="557.5" width="28" height="102" stroke="#787878" stroke-width="1.33333" stroke-miterlimit="8" fill="#A5A5A5"/><rect x="412.5" y="671.5" width="370" height="32" stroke="#000000" stroke-linejoin="round" stroke-miterlimit="10" fill="none"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(492.364 694)">Radio Interface (<tspan font-size="19" x="137.5" y="0">Uu</tspan><tspan font-size="19" x="161.333" y="0">/PC5)</tspan><tspan font-size="19" x="-282.121" y="-653">UE/NG</tspan><tspan font-size="19" x="-222.955" y="-653">-</tspan><tspan font-size="19" x="-216.788" y="-653">RAN/UE A</tspan><tspan font-size="19" x="375.54" y="-653">NG</tspan>-<tspan font-size="19" x="409.706" y="-653">RAN/UE/UE B</tspan><tspan font-size="14" x="0.896851" y="-647">Transmitting </tspan><tspan font-size="14" x="1.31018" y="-631">PDCP entity</tspan><tspan font-size="14" x="167.401" y="-647">Receiving </tspan><tspan font-size="14" x="160.148" y="-631">PDCP entity</tspan></text><path d="M314.5 71.5001 431.364 71.6549" stroke="#000000" stroke-width="0.666667" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M331.5 71.5001C331.5 65.9772 349.633 61.5001 372 61.5001 394.368 61.5001 412.5 65.9772 412.5 71.5001 412.5 77.0229 394.368 81.5001 372 81.5001 349.633 81.5001 331.5 77.0229 331.5 71.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M353.5 90.5001 363.5 90.5001 363.5 48.5001 383.5 48.5001 383.5 90.5001 393.5 90.5001 373.5 110.5Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M877.364 82.6549 760.5 82.5001" stroke="#000000" stroke-width="0.666667" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M860.5 83.5001C860.5 89.0229 842.368 93.5001 820 93.5001 797.633 93.5001 779.5 89.0229 779.5 83.5001 779.5 77.9772 797.633 73.5001 820 73.5001 842.368 73.5001 860.5 77.9772 860.5 83.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M838.5 64.5 828.5 64.5 828.5 106.5 808.5 106.5 808.5 64.5 798.5 64.5 818.5 44.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><rect x="244.5" y="128.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(302.494 150)">Transmission buffer:<tspan font-size="19" x="-4.67999" y="23">Sequence</tspan><tspan font-size="19" x="84.32" y="23">numberin</tspan>g</text><rect x="244.5" y="199.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(297.314 222)">Header or uplink data<tspan font-size="19" x="34.08" y="23">Compressio</tspan>n</text><rect x="682.5" y="141.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(735.782 164)">Header or uplink data<tspan font-size="19" x="24.2466" y="23">Decompressio</tspan>n</text><rect x="244.5" y="482.5" width="285" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(300.314 505)">Routing / Duplication</text><rect x="244.5" y="437.5" width="285" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(309.734 460)">Add PDCP header</text><rect x="244.5" y="383.5" width="189" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(298.62 406)">Ciphering</text><rect x="244.5" y="333.5" width="189" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(261.953 356)">Integrity protection</text><path d="M472.167 267.5 472.167 409.802 470.833 409.802 470.833 267.5ZM475.5 408.468 471.5 416.468 467.5 408.468Z"/><path d="M332.167 267.5 332.167 319.552 330.833 319.552 330.833 267.5ZM335.5 318.218 331.5 326.218 327.5 318.219Z"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(253.644 291)">Packets associated <tspan font-size="19" x="14.0067" y="23">to a PDCP SDU</tspan></text><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="matrix(6.12323e-17 1 -1 6.12323e-17 499.312 299)">Packets not <tspan font-size="19" x="-14" y="23">associated to a </tspan><tspan font-size="19" x="-2.75546e-15" y="45">PDCP SDU</tspan></text><rect x="682.5" y="482.5" width="285" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(728.535 505)">Remove PDCP Header</text><rect x="682.5" y="437.5" width="203" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(733.729 460)">Deciphering</text><rect x="682.5" y="389.5" width="203" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(702.159 412)">Integrity Verification</text><rect x="682.5" y="303.5" width="203" height="77" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(712.729 325)">Reception buffer:<tspan font-size="19" x="24.6667" y="23">Reordering</tspan><tspan font-size="19" x="-13.1667" y="45">Duplicate discardin</tspan><tspan font-size="19" x="144.167" y="45">g</tspan><tspan font-size="19" x="-10.0989" y="-84">Packets associated </tspan><tspan font-size="19" x="3.90784" y="-61">to a PDCP SDU</tspan></text><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="matrix(6.12323e-17 1 -1 6.12323e-17 960.34 294)">Packets not <tspan font-size="19" x="-14" y="23">associated to a </tspan><tspan font-size="19" x="1" y="45">PDCP SDU</tspan></text><path d="M0.666667-8.2074e-07 0.666763 78.6116-0.66657 78.6116-0.666667 8.2074e-07ZM4.00009 77.2782 0.000104987 85.2782-3.9999 77.2782Z" transform="matrix(1 0 0 -1 779.5 296.778)"/><path d="M0.666667-2.88742e-07 0.666769 235.734-0.666565 235.734-0.666667 2.88742e-07ZM4.0001 234.401 0.000104987 242.401-3.9999 234.401Z" transform="matrix(1 0 0 -1 931.5 453.901)"/></g></svg>
\ No newline at end of file
doc/guides/prog_guide/index.rst +1 -0
index 8564883018..d062cd53ac 100644
@@ -76,4 +76,5 @@ Programmer's Guide
     lto
     profile_app
     asan
+    pdcp_lib
     glossary
doc/guides/prog_guide/pdcp_lib.rst new file +211 -0

211 lines not on this page · raw message

Signature · 1 line
2.25.1
#17 lore raw
In reply to Anoob Joseph

For such new library, I think we need to vote in techboard to accept it. That's a process we had in recent years to keep the project scope in control.

22/12/2022 10:25, Anoob Joseph:

Quoted 35 lines

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_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 belonging to same entity.

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for *pre_process* and *post_process* based on features enabled in the entity.

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

#18 lore raw
Quoted 3 lines · Thomas Monjalon

For such new library, I think we need to vote in techboard to accept it. That's a process we had in recent years to keep the project scope in control.

Looks like this process not defined nor documented. In order to bring clarity for new library acceptance and make life easy for contributors (also, less forking the DPDK repo),
IMO, we should document the process as there is a lot of effort involved and send multiple version, and finally it gets rejected due to various reasons.

I would suggest, some guideline to get started for discussion. I would suggest taking up this for TB meeting to define it.

1)For new library(new directory under lib/ directory) needs to get approval from DPDK tech board.
2)Author needs to send any of the following to start the approval process -Send a write-up on the scope and purpose library. TB may ask for sending API specification RFC is the scope or purpose is not clear. OR
-Send RFC with API specification.

If it's above, following new libraries needs approval. So I suggest we take approval in coming TB meeting to conclude one way or another.

1) pdcp library (https://patches.dpdk.org/project/dpdk/list/?series=26246)
2) mldev library or device class(https://patches.dpdk.org/project/dpdk/list/?series=25753)
3) memara (https://patches.dpdk.org/project/dpdk/list/?series=26546)
4) pmu ( started as EAL file and moving to separate library at
https://patches.dpdk.org/project/dpdk/list/?series=26616)

Please add the libraries if I missed something.

#19 lore raw

v2 cover lib: add pdcp protocol

In reply to Anoob Joseph

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 operations,
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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_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 belonging to same entity.

Similar to lib IPsec, lib PDCP would allow application to use same API sequence while leveraging protocol offload features enabled by rte_security library. Lib PDCP would internally change the handles registered for *pre_process* and *post_process* based on features enabled in the entity.

Lib PDCP would create the required sessions on the device provided in entity to minimize the application requirements. Also, the crypto_op allocation and free would also be done internally by lib PDCP to allow the library to create crypto ops as required for the input packets. For example, when control PDUs are received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP is expected to handle it differently.

Lib PDCP utilizes reorder library for implementing in-order delivery. It utilizes bitmap library for implementing status reports and track the COUNT value of the packets received. To allow application to choose timer implementation of choice, lib PDCP allows application to configure handles that can be used for starting & stopping timers. Upon expiry, application can call corresponding PDCP API(``rte_pdcp_t_reordering_expiry_handle``) for handling the event. Unit tests are added to verify both rte_timer based timers as well as rte_eventdev based timers.

PDCP tracks the sequence number of the received packets and during events such as re-establishment, it is required to generate reports and transmit to the peer. This series introduces ``rte_pdcp_control_pdu_create`` for handling control PDU generation.

Changes in v2:
- Added control PDU handling
- Added t-Reordering timer
- Added in-order delivery
- Added status PDU generation
- Rebased on top of new features added in reorder library
- Split base patch
- Increased test coverage
- Improved thread safety

Changes from RFC
- Implementation for all APIs covering basic control plane & user plane packets
- Unit test leveraging existing PDCP vectors available in test_cryptodev
- Unit test performing both UL & DL operations to verify various protocol features
- Updated documentation

Sample application sequence:

	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
	struct rte_crypto_op *cop[MAX_BURST_SIZE];
	struct rte_pdcp_group grp[MAX_BURST_SIZE];
	struct rte_pdcp_entity *pdcp_entity;
	int nb_max_out_mb, ret, nb_grp;

	/* Create PDCP entity */
	pdcp_entity = rte_pdcp_entity_establish(&conf);

	/**
	 * Allocate buffer for holding mbufs returned during PDCP suspend,
	 * release & post-process APIs.
	 */

	/* Max packets that can be cached in entity + burst size */
	nb_max_out_mb = pdcp_entity->max_pkt_cache + 1;
	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
	if (out_mb == NULL) {
		/* Handle error */
	}

	while (1) {
		/* Receive packet and form mbuf */

		/**
		 * Prepare packets for crypto operation. Following operations
		 * would be done,
		 *
		 * Transmitting entity/UL (only data PDUs):
		 *  - Perform compression
		 *  - Assign sequence number
		 *  - Add PDCP header
		 *  - Create & prepare crypto_op
		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
		 *  - Save original PDCP SDU (during PDCP re-establishment,
		 *    unconfirmed PDCP SDUs need to crypto processed again and
		 *    transmitted/re-transmitted)
		 *
		 *  Receiving entity/DL:
		 *  - Any control PDUs received would be processed and
		 *    appropriate actions taken. If data PDU, continue.
		 *  - Determine sequence number (based on HFN & per packet SN)
		 *  - Prepare crypto_op
		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
		 */
		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts, cop,
						      nb_rx, &nb_err);
		if (nb_err != 0) {
			/* Handle error packets */
		}

		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop, nb_success)
				!= nb_success) {
			/* Retry for enqueue failure packets */
		}

		...

		ret = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
						  MAX_BURST_SIZE);
		if (ret == 0)
			continue;

		/**
		 * Received a burst of completed crypto ops from cryptodev. It
		 * may belong to various entities. Group similar ones together
		 * for entity specific post-processing.
		 */

		/**
		 * Groups similar entities together. Frees crypto op and based
		 * on crypto_op status, set mbuf->ol_flags which would be
		 * checked in rte_pdcp_pkt_post_process().
		 */
		nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);

		for (i = 0; i != nb_grp; i++) {

			/**
			 * Post process packets after crypto completion.
			 * Following operations would be done,
			 *
			 *  Transmitting entity/UL:
			 *  - Check crypto result
			 *
			 *  Receiving entity/DL:
			 *  - Check crypto operation status
			 *  - Check for duplication (if yes, drop duplicate)
			 *  - Perform decompression
			 *  - Trim PDCP header
			 *  - Hold packet (SDU) for in-order delivery (return
			 *    completed packets as and when sequence is
			 *    completed)
			 *  - If not in sequence, cache the packet and start
			 *    t-Reordering timer. When timer expires, the
			 *    packets need to delivered to upper layers (not
			 *    treated as error packets).
			 */
			nb_success = rte_pdcp_pkt_post_process(grp[i].id.ptr,
							       grp[i].m, out_mb,
							       grp[i].cnt,
							       &nb_err);
			if (nb_err != 0) {
				/* Handle error packets */
			}

			/* Perform additional operations */

			/**
			 * Tranmitting entity/UL
			 * - If duplication is enabled, duplicate PDCP PDUs
			 * - When lower layers confirm reception of a PDCP PDU,
			 *   it should be communicated to PDCP layer so that
			 *   PDCP can drop the corresponding SDU
			 */
		}
	}

Sample output from unit test executed on crypto_cn10k PMD(summary):

~# DPDK_TEST=pdcp_autotest ./dpdk-test --log-level=7
<snip>
+ ------------------------------------------------------- +
+ Test Suite Summary : PDCP Unit Test Suite
+ ------------------------------------------------------- +
+ Known vector cases : 109/160 passed, 0/160 skipped, 0/160 failed, 51/160 unsupported
+ PDCP combined mode : 1/1 passed, 0/1 skipped, 0/1 failed, 0/1 unsupported
+ PDCP HFN/SN : 4/4 passed, 0/4 skipped, 0/4 failed, 0/4 unsupported
+ PDCP reorder : 5/5 passed, 0/5 skipped, 0/5 failed, 0/5 unsupported
+ PDCP status report : 9/9 passed, 0/9 skipped, 0/9 failed, 0/9 unsupported
+ ------------------------------------------------------- +

 + Sub Testsuites Total :      5
 + Sub Testsuites Skipped :    0
 + Sub Testsuites Passed :     5
 + Sub Testsuites Failed :     0
 + ------------------------------------------------------- +
 + Tests Total :       179
 + Tests Skipped :      0
 + Tests Executed :    179
 + Tests Unsupported:  51
 + Tests Passed :      128

+ Tests Failed : 0
+ ------------------------------------------------------- +
Test OK

Anoob Joseph (10):
lib: add pdcp protocol
pdcp: add pre and post-process
pdcp: add packet group
pdcp: add crypto session create and destroy
pdcp: add pre and post process for UL
pdcp: add pre and post process for DL
pdcp: add IV generation routines
app/test: add lib pdcp tests
doc: add PDCP library guide
pdcp: add control PDU handling

Volodymyr Fialko (12):
net: add PDCP header
test/pdcp: pdcp HFN tests in combined mode
pdcp: implement t-Reordering and packet buffering test/pdcp: add in-order delivery cases
pdcp: add timer callback handlers
pdcp: add timer expiry handle
test/pdcp: add timer expiry cases test/pdcp: add timer restart case
pdcp: add support for status report
pdcp: allocate reorder buffer alongside with entity
pdcp: add thread safe processing
test/pdcp: add PDCP status report cases

 app/test/meson.build                          |    1 +
 app/test/test_cryptodev.h                     |    3 +
 app/test/test_pdcp.c                          | 1923 +++++++++++++++++
 doc/api/doxy-api-index.md                     |    4 +-
 doc/api/doxy-api.conf.in                      |    1 +
 .../img/pdcp_functional_overview.svg          |    1 +
 doc/guides/prog_guide/index.rst               |    1 +
 doc/guides/prog_guide/pdcp_lib.rst            |  285 +++
 lib/meson.build                               |    1 +
 lib/net/meson.build                           |    1 +
 lib/net/rte_pdcp_hdr.h                        |  140 ++
 lib/pdcp/meson.build                          |   21 +
 lib/pdcp/pdcp_cnt.c                           |  164 ++
 lib/pdcp/pdcp_cnt.h                           |   24 +
 lib/pdcp/pdcp_crypto.c                        |  237 ++
 lib/pdcp/pdcp_crypto.h                        |   21 +
 lib/pdcp/pdcp_ctrl_pdu.c                      |   72 +
 lib/pdcp/pdcp_ctrl_pdu.h                      |   16 +
 lib/pdcp/pdcp_entity.h                        |  306 +++
 lib/pdcp/pdcp_process.c                       | 1379 ++++++++++++
 lib/pdcp/pdcp_process.h                       |   13 +
 lib/pdcp/pdcp_reorder.c                       |   20 +
 lib/pdcp/pdcp_reorder.h                       |   68 +
 lib/pdcp/rte_pdcp.c                           |  261 +++
 lib/pdcp/rte_pdcp.h                           |  369 ++++
 lib/pdcp/rte_pdcp_group.h                     |  125 ++
 lib/pdcp/version.map                          |   17 +
 27 files changed, 5473 insertions(+), 1 deletion(-)
 create mode 100644 app/test/test_pdcp.c
 create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg
 create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
 create mode 100644 lib/net/rte_pdcp_hdr.h
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_cnt.c
 create mode 100644 lib/pdcp/pdcp_cnt.h
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.c
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/pdcp_reorder.c
 create mode 100644 lib/pdcp/pdcp_reorder.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/rte_pdcp_group.h
 create mode 100644 lib/pdcp/version.map
Signature · 1 line
2.25.1
#20 lore raw

PATCH v2 1/22 net: add PDCP header

From: Volodymyr Fialko <[email protected]>

Add PDCP protocol header to be used for supporting PDCP protocol processing.

---
 doc/api/doxy-api-index.md |   3 +-
 lib/net/meson.build       |   1 +
 lib/net/rte_pdcp_hdr.h    | 140 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 lib/net/rte_pdcp_hdr.h
doc/api/doxy-api-index.md +2 -1
index c709fd48ad..debbe4134f 100644
@@ -127,7 +127,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 hdr](@ref rte_pdcp_hdr.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
lib/net/meson.build +1 -0
index 379d161ee0..bd56f91c22 100644
@@ -22,6 +22,7 @@ headers = files(
         'rte_geneve.h',
         'rte_l2tpv2.h',
         'rte_ppp.h',
+        'rte_pdcp_hdr.h',
 )
 
 sources = files(
lib/net/rte_pdcp_hdr.h new file +140 -0

140 lines not on this page · raw message

Signature · 1 line
2.25.1
#22 lore raw

PATCH v2 2/22 lib: add pdcp protocol

In reply to Anoob Joseph

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_release()

---
 doc/api/doxy-api-index.md |   3 +-
 doc/api/doxy-api.conf.in  |   1 +
 lib/meson.build           |   1 +
 lib/pdcp/meson.build      |  17 +++++
 lib/pdcp/pdcp_crypto.c    |  21 +++++
 lib/pdcp/pdcp_crypto.h    |  15 ++++
 lib/pdcp/pdcp_entity.h    |  95 +++++++++++++++++++++++
 lib/pdcp/pdcp_process.c   | 138 +++++++++++++++++++++++++++++++++
 lib/pdcp/pdcp_process.h   |  13 ++++
 lib/pdcp/rte_pdcp.c       | 138 +++++++++++++++++++++++++++++++++
 lib/pdcp/rte_pdcp.h       | 157 ++++++++++++++++++++++++++++++++++++++
 lib/pdcp/version.map      |  10 +++
 12 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/version.map
doc/api/doxy-api-index.md +2 -1
index debbe4134f..cd7a6cae44 100644
@@ -128,7 +128,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in +1 -0
index d230a19e1f..58789308a9 100644
@@ -62,6 +62,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 \
lib/meson.build +1 -0
index 0812ce6026..d217c04ea9 100644
@@ -64,6 +64,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 = [
lib/pdcp/meson.build new file +17 -0
new file mode 100644
index 0000000000..ccaf426240
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2023 Marvell.
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+sources = files(
+        'pdcp_crypto.c',
+        'pdcp_process.c',
+        'rte_pdcp.c',
+        )
+headers = files('rte_pdcp.h')
+
+deps += ['mbuf', 'net', 'cryptodev', 'security']
lib/pdcp/pdcp_crypto.c new file +21 -0
new file mode 100644
index 0000000000..755e27ec9e
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_pdcp.h>
+
+#include "pdcp_crypto.h"
+
+int
+pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf)
+{
+	RTE_SET_USED(entity);
+	RTE_SET_USED(conf);
+	return 0;
+}
+
+void
+pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
+{
+	RTE_SET_USED(entity);
+}
lib/pdcp/pdcp_crypto.h new file +15 -0
new file mode 100644
index 0000000000..6563331d37
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CRYPTO_H
+#define PDCP_CRYPTO_H
+
+#include <rte_pdcp.h>
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+void pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* PDCP_CRYPTO_H */
lib/pdcp/pdcp_entity.h new file +95 -0

95 lines not on this page · raw message

lib/pdcp/pdcp_process.c new file +138 -0

138 lines not on this page · raw message

lib/pdcp/pdcp_process.h new file +13 -0
new file mode 100644
index 0000000000..fd53fff0aa
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_PROCESS_H
+#define PDCP_PROCESS_H
+
+#include <rte_pdcp.h>
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf);
+
+#endif /* PDCP_PROCESS_H */
lib/pdcp/rte_pdcp.c new file +138 -0

138 lines not on this page · raw message

lib/pdcp/rte_pdcp.h new file +157 -0

157 lines not on this page · raw message

lib/pdcp/version.map new file +10 -0
new file mode 100644
index 0000000000..923e165f3f
@@ -0,0 +1,10 @@
+EXPERIMENTAL {
+	global:
+
+	# added in 23.07
+	rte_pdcp_entity_establish;
+	rte_pdcp_entity_release;
+	rte_pdcp_entity_suspend;
+
+	local: *;
+};
Signature · 1 line
2.25.1
#23 lore raw

Hi Anoob,

Fix check patch issues and please see some inline comments.

Quoted 328 lines

Subject: [PATCH v2 02/22] lib: add pdcp protocol

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_entity_establish()
2. rte_pdcp_entity_suspend()
3. rte_pdcp_entity_release()

---
 doc/api/doxy-api-index.md |   3 +-
 doc/api/doxy-api.conf.in  |   1 +
 lib/meson.build           |   1 +
 lib/pdcp/meson.build      |  17 +++++
 lib/pdcp/pdcp_crypto.c    |  21 +++++
 lib/pdcp/pdcp_crypto.h    |  15 ++++
 lib/pdcp/pdcp_entity.h    |  95 +++++++++++++++++++++++
 lib/pdcp/pdcp_process.c   | 138 +++++++++++++++++++++++++++++++++
 lib/pdcp/pdcp_process.h   |  13 ++++
 lib/pdcp/rte_pdcp.c       | 138 +++++++++++++++++++++++++++++++++
 lib/pdcp/rte_pdcp.h       | 157 ++++++++++++++++++++++++++++++++++++++
 lib/pdcp/version.map      |  10 +++
 12 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 lib/pdcp/meson.build
 create mode 100644 lib/pdcp/pdcp_crypto.c
 create mode 100644 lib/pdcp/pdcp_crypto.h
 create mode 100644 lib/pdcp/pdcp_entity.h
 create mode 100644 lib/pdcp/pdcp_process.c
 create mode 100644 lib/pdcp/pdcp_process.h
 create mode 100644 lib/pdcp/rte_pdcp.c
 create mode 100644 lib/pdcp/rte_pdcp.h
 create mode 100644 lib/pdcp/version.map
doc/api/doxy-api-index.md +2 -1
index debbe4134f..cd7a6cae44 100644
@@ -128,7 +128,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in +1 -0
index d230a19e1f..58789308a9 100644
@@ -62,6 +62,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 \
lib/meson.build +1 -0
index 0812ce6026..d217c04ea9 100644
@@ -64,6 +64,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 = [
lib/pdcp/meson.build new file +17 -0
new file mode 100644
index 0000000000..ccaf426240
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2023 Marvell.
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+sources = files(
+        'pdcp_crypto.c',
+        'pdcp_process.c',
+        'rte_pdcp.c',
+        )
+headers = files('rte_pdcp.h')
+
+deps += ['mbuf', 'net', 'cryptodev', 'security']
lib/pdcp/pdcp_crypto.c new file +10 -0
new file mode 100644
index 0000000000..755e27ec9e
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_pdcp.h>
+
+#include "pdcp_crypto.h"
+
+int
+pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_crypto.c new file +11 -0
+{
+	RTE_SET_USED(entity);
+	RTE_SET_USED(conf);
+	return 0;
+}
+
+void
+pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
+{
+	RTE_SET_USED(entity);
+}
lib/pdcp/pdcp_crypto.h new file +15 -0
new file mode 100644
index 0000000000..6563331d37
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CRYPTO_H
+#define PDCP_CRYPTO_H
+
+#include <rte_pdcp.h>
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+void pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* PDCP_CRYPTO_H */
lib/pdcp/pdcp_entity.h new file +17 -0
new file mode 100644
index 0000000000..ca1d56b516
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_ENTITY_H
+#define PDCP_ENTITY_H
+
+#include <rte_common.h>
+#include <rte_crypto_sym.h>
+#include <rte_mempool.h>
+#include <rte_pdcp.h>
+#include <rte_security.h>
+
+struct entity_priv;
+
+/* IV generation function based on the entity configuration */
+typedef void (*iv_gen_t)(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_entity.h new file +38 -0
+			 uint32_t count);
+
+struct entity_state {
+	uint32_t rx_next;
+	uint32_t tx_next;
+	uint32_t rx_deliv;
+	uint32_t rx_reord;
+};
+
+/*
+ * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]
+ */
+
+struct entity_priv {
+	/** Crypto sym session. */
+	struct rte_cryptodev_sym_session *crypto_sess;
+	/** Entity specific IV generation function. */
+	iv_gen_t iv_gen;
+	/** Entity state variables. */
+	struct entity_state state;
+	/** Flags. */
+	struct {
+		/** PDCP PDU has 4 byte MAC-I. */
+		uint64_t is_authenticated : 1;
+		/** Cipher offset & length in bits. */
+		uint64_t is_ciph_in_bits : 1;
+		/** Auth offset & length in bits. */
+		uint64_t is_auth_in_bits : 1;
+		/** Is UL/transmitting PDCP entity. */
+		uint64_t is_ul_entity : 1;
+		/** Is NULL auth. */
+		uint64_t is_null_auth : 1;
+	} flags;
+	/** Crypto op pool. */
+	struct rte_mempool *cop_pool;
+	/** PDCP header size. */
+	uint8_t hdr_sz;
+	/** PDCP AAD size. For AES-CMAC, additional message is prepended for

the operation. */

lib/pdcp/pdcp_entity.h new file +7 -0
+	uint8_t aad_sz;
+	/** Device ID of the device to be used for offload. */
+	uint8_t dev_id;
+};
+
+struct entity_priv_dl_part {
+	/* NOTE: when in-order-delivery is supported, post PDCP packets would

need to cached. */

lib/pdcp/pdcp_entity.h new file +6 -0
+	uint8_t dummy;
+};
+
+struct entity_priv_ul_part {
+	/*
+	 * NOTE: when re-establish is supported, plain PDCP packets & COUNT

values need to be

lib/pdcp/pdcp_entity.h new file +13 -0
+	 * cached.
+	 */
+	uint8_t dummy;
+};
+
+static inline struct entity_priv *
+entity_priv_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity));
+}
+
+static inline struct entity_priv_dl_part *
+entity_dl_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +5 -0
+}
+
+static inline struct entity_priv_ul_part *
+entity_ul_part_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +9 -0
+}
+
+static inline int
+pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
+}
+
+#endif /* PDCP_ENTITY_H */
lib/pdcp/pdcp_process.c new file +17 -0
new file mode 100644
index 0000000000..d4b158536d
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_memcpy.h>
+#include <rte_pdcp.h>
+#include <rte_pdcp_hdr.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct

rte_crypto_sym_xform **c_xfrm,

lib/pdcp/pdcp_process.c new file +12 -0
+		     struct rte_crypto_sym_xform **a_xfrm)
+{
+	*c_xfrm = NULL;
+	*a_xfrm = NULL;
+
+	if (conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		*c_xfrm = conf->crypto_xfrm;
+		*a_xfrm = conf->crypto_xfrm->next;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_process.c new file +11 -0
+		*a_xfrm = conf->crypto_xfrm;
+		*c_xfrm = conf->crypto_xfrm->next;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	int ret;
+
+	/**
+	 * flags.is_authenticated
+	 *
+	 * MAC-I would be added in case of control plane packets and when

authentication

lib/pdcp/pdcp_process.c new file +4 -0
+	 * transform is not NULL.
+	 */
+
+	if (conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL)

lib/pdcp/pdcp_process.c

Quoted 1 line
lib/pdcp/pdcp_process.c new file +1 -0
+		en_priv->flags.is_authenticated = 1;

This check should be added after getting the xfrm.
If domain == control and a_xfrm is NULL, then it should be error, right?

Quoted 148 lines
lib/pdcp/pdcp_process.c new file +12 -0
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (a_xfrm != NULL)
+		en_priv->flags.is_authenticated = 1;
+
+	/**
+	 * flags.is_ciph_in_bits
+	 *
+	 * For ZUC & SNOW3G cipher algos, offset & length need to be provided

in bits.

lib/pdcp/pdcp_process.c new file +10 -0
+	 */
+
+	if ((c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2) ||
+	    (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3))
+		en_priv->flags.is_ciph_in_bits = 1;
+
+	/**
+	 * flags.is_auth_in_bits
+	 *
+	 * For ZUC & SNOW3G authentication algos, offset & length need to be

provided in bits.

lib/pdcp/pdcp_process.c new file +4 -0
+	 */
+
+	if (a_xfrm != NULL) {
+		if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2)

||

lib/pdcp/pdcp_process.c new file +19 -0
+		    (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3))
+			en_priv->flags.is_auth_in_bits = 1;
+	}
+
+	/**
+	 * flags.is_ul_entity
+	 *
+	 * Indicate whether the entity is UL/transmitting PDCP entity.
+	 */
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		en_priv->flags.is_ul_entity = 1;
+
+	/**
+	 * flags.is_null_auth
+	 *
+	 * For NULL auth, 4B zeros need to be added by lib PDCP. Indicate that
+	 * algo is NULL auth to perform the same.
+	 */
+	if (a_xfrm != NULL && a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_NULL)

lib/pdcp/pdcp_process.c new file +13 -0
+		en_priv->flags.is_null_auth = 1;
+
+	/**
+	 * hdr_sz
+	 *
+	 * PDCP header size of the entity
+	 */
+	en_priv->hdr_sz = pdcp_hdr_size_get(conf->pdcp_xfrm.sn_size);
+
+	/**
+	 * aad_sz
+	 *
+	 * For AES-CMAC, additional message is prepended for processing. Need

to be trimmed after

lib/pdcp/pdcp_process.c new file +3 -0
+	 * crypto processing is done.
+	 */
+	if (a_xfrm != NULL && a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_AES_CMAC)

lib/pdcp/pdcp_process.c new file +9 -0
+		en_priv->aad_sz = 8;
+	else
+		en_priv->aad_sz = 0;
+
+	return 0;
+}
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +15 -0
+{
+	struct entity_priv *en_priv;
+	int ret;
+
+	if (entity == NULL || conf == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	ret = pdcp_entity_priv_populate(en_priv, conf);
+	if (ret)
+		return ret;
+
+	return 0;
+}
lib/pdcp/pdcp_process.h new file +11 -0
new file mode 100644
index 0000000000..fd53fff0aa
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_PROCESS_H
+#define PDCP_PROCESS_H
+
+#include <rte_pdcp.h>
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf);

lib/pdcp/pdcp_process.h new file +2 -0
+
+#endif /* PDCP_PROCESS_H */
lib/pdcp/rte_pdcp.c new file +30 -0
new file mode 100644
index 0000000000..8914548dbd
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf)
+{
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE);
+}
+
+struct rte_pdcp_entity *

lib/pdcp/rte_pdcp.c line 40

Quoted 10 lines
lib/pdcp/rte_pdcp.c new file +10 -0
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)
+{
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

Quoted 14 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+
+	if (conf->pdcp_xfrm.en_ordering || conf-
Quoted 1 line

pdcp_xfrm.remove_duplicates || conf->is_slrb ||

lib/pdcp/rte_pdcp.c new file +8 -0
+	    conf->en_sec_offload) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	/*
+	 * 6.3.2 PDCP SN
+	 * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length of the

PDCP SN is

lib/pdcp/rte_pdcp.c new file +1 -0
+	 * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or sl-

PDCP-SN-Size in

lib/pdcp/rte_pdcp.c line 58

Quoted 7 lines
lib/pdcp/rte_pdcp.c new file +7 -0
+	 * TS 38.331 [3])
+	 */
+	if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}

Check for PDCP crypto algos may also be added.
As only 4 cipher and 4 auth algos are supported in case of PDCP.

lib/pdcp/rte_pdcp.c line 63

Quoted 5 lines
lib/pdcp/rte_pdcp.c new file +5 -0
+
+	if (conf->pdcp_xfrm.hfn || conf->pdcp_xfrm.hfn_threshold) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

What is the reason to set errno as EINVAL when HFN is set?

Quoted 86 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+
+	entity_size = pdcp_entity_size_get(conf);
+	if (entity_size < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	entity = rte_zmalloc_socket("pdcp_entity", entity_size,

RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);

lib/pdcp/rte_pdcp.c new file +32 -0
+	if (entity == NULL) {
+		rte_errno = -ENOMEM;
+		return NULL;
+	}
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->state.rx_deliv = conf->count;
+	en_priv->state.tx_next = conf->count;
+	en_priv->cop_pool = conf->cop_pool;
+
+	/* Setup crypto session */
+	ret = pdcp_crypto_sess_create(entity, conf);
+	if (ret)
+		goto entity_free;
+
+	ret = pdcp_process_func_set(entity, conf);
+	if (ret)
+		goto crypto_sess_destroy;
+
+	return entity;
+
+crypto_sess_destroy:
+	pdcp_crypto_sess_destroy(entity);
+entity_free:
+	rte_free(entity);
+	rte_errno = ret;
+	return NULL;
+}
+
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity, struct rte_mbuf

*out_mb[])

lib/pdcp/rte_pdcp.c new file +35 -0
+{
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	/* Teardown crypto sessions */
+	pdcp_crypto_sess_destroy(pdcp_entity);
+
+	rte_free(pdcp_entity);
+
+	RTE_SET_USED(out_mb);
+	return 0;
+}
+
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[])
+{
+	struct entity_priv *en_priv;
+
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(pdcp_entity);
+
+	if (en_priv->flags.is_ul_entity) {
+		en_priv->state.tx_next = 0;
+	} else {
+		en_priv->state.rx_next = 0;
+		en_priv->state.rx_deliv = 0;
+	}
+
+	RTE_SET_USED(out_mb);
+
+	return 0;
+}
lib/pdcp/rte_pdcp.h new file +3 -0
new file mode 100644
index 0000000000..33c355b05a
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */

lib/pdcp/rte_pdcp.h line 13

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+
+#ifndef RTE_PDCP_H
+#define RTE_PDCP_H
+
+/**
+ * @file rte_pdcp.h
+ *
+ * RTE PDCP support.
+ *
+ * librte_pdcp provides a framework for PDCP protocol processing.

A framework for PDCP protocol processing.

lib/pdcp/rte_pdcp.h line 26

Quoted 13 lines
lib/pdcp/rte_pdcp.h new file +13 -0
+ */
+
+#include <rte_compat.h>
+#include <rte_common.h>
+#include <rte_mempool.h>
+#include <rte_security.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * PDCP entity.

You can probably explain more on what a PDCP entity is.

Quoted 11 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+ */
+struct rte_pdcp_entity {
+	/**
+	 * 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 t-Reordering

timer

lib/pdcp/rte_pdcp.h line 43

Quoted 7 lines
lib/pdcp/rte_pdcp.h new file +7 -0
+	 * 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 *rte_pdcp_pkt_post_process()* with *out_mb*
+	 * which can hold maximum number of packets which may be returned.
+	 */

The above comment explains the need for holding the packets.
But it does not talk about the parameter it is explaining.
This explanation should be part of programmer's guide and not the API guide.

lib/pdcp/rte_pdcp.h line 46

Quoted 3 lines
lib/pdcp/rte_pdcp.h new file +3 -0
+	uint32_t max_pkt_cache;
+	/** User area for saving application data. */
+	uint64_t user_area[2];

Is it being used right now in the patches? If not, can we add it later?
And if really needed now, can we rename to user_data

Quoted 19 lines
lib/pdcp/rte_pdcp.h new file +18 -0
+} __rte_cache_aligned;
+
+/**
+ * PDCP entity configuration to be used for establishing an entity.
+ */
+/* Structure rte_pdcp_entity_conf 8< */
+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;
+	/** 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.

lib/pdcp/rte_pdcp.h

Quoted 1 line
lib/pdcp/rte_pdcp.h new file +1 -0
+	 */

If the HFN is to be ignored, then why to add a check in entity establish and return EINVAL? It should be silently ignored in that case with a debug print at max.

Quoted 114 lines
lib/pdcp/rte_pdcp.h new file +2 -0
+	uint32_t count;
+	/** Indicate whether the PDCP entity belongs to Side Link Radio Bearer.

*/

lib/pdcp/rte_pdcp.h new file +6 -0
+	bool is_slrb;
+	/** Enable security offload on the device specified. */
+	bool en_sec_offload;
+	/** Device on which security/crypto session need to be created. */
+	uint8_t dev_id;
+	/** Reverse direction during IV generation. Can be used to simulate UE

crypto processing.*/

lib/pdcp/rte_pdcp.h new file +39 -0
+	bool reverse_iv_direction;
+};
+/* >8 End of structure rte_pdcp_entity_conf. */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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

+ */

lib/pdcp/rte_pdcp.h new file +23 -0
+__rte_experimental
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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.
+ *
+ * For UL/transmitting PDCP entity, *out_mb* buffer would be unused.
+ *
+ * @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

+ */

lib/pdcp/rte_pdcp.h new file +10 -0
+__rte_experimental
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PDCP_H */
lib/pdcp/version.map new file +10 -1
new file mode 100644
index 0000000000..923e165f3f
@@ -0,0 +1,10 @@
+EXPERIMENTAL {
+	global:
+
+	# added in 23.07
+	rte_pdcp_entity_establish;
+	rte_pdcp_entity_release;
+	rte_pdcp_entity_suspend;
+
+	local: *;
+};
--

2.25.1

#24 lore raw

Hi Akhil,

Thanks for the review. Please see inline.

Thanks,
Anoob

Quoted 13 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Tuesday, May 16, 2023 9:01 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 02/22] lib: add pdcp protocol

Quoted 3 lines

Hi Anoob,

Fix check patch issues and please see some inline comments.

[Anoob] Checkpatch warnings are false positives. I'll try to work around couple of them. Rest we may need to ignore.

Quoted 313 lines
Quoted 19 lines

Subject: [PATCH v2 02/22] lib: add pdcp protocol

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_entity_establish() 2. rte_pdcp_entity_suspend() 3. rte_pdcp_entity_release()

Quoted 9 lines
---
 doc/api/doxy-api-index.md |   3 +-
 doc/api/doxy-api.conf.in  |   1 +
 lib/meson.build           |   1 +
 lib/pdcp/meson.build      |  17 +++++
 lib/pdcp/pdcp_crypto.c    |  21 +++++
 lib/pdcp/pdcp_crypto.h    |  15 ++++
 lib/pdcp/pdcp_entity.h    |  95 +++++++++++++++++++++++
 lib/pdcp/pdcp_process.c   | 138

+++++++++++++++++++++++++++++++++

Quoted 3 lines
 lib/pdcp/pdcp_process.h   |  13 ++++
 lib/pdcp/rte_pdcp.c       | 138 +++++++++++++++++++++++++++++++++
 lib/pdcp/rte_pdcp.h       | 157

++++++++++++++++++++++++++++++++++++++

Quoted 167 lines
 lib/pdcp/version.map      |  10 +++
 12 files changed, 608 insertions(+), 1 deletion(-)  create mode

100644 lib/pdcp/meson.build create mode 100644 lib/pdcp/pdcp_crypto.c create mode 100644 lib/pdcp/pdcp_crypto.h create mode 100644 lib/pdcp/pdcp_entity.h create mode 100644 lib/pdcp/pdcp_process.c create mode 100644 lib/pdcp/pdcp_process.h create mode 100644 lib/pdcp/rte_pdcp.c create mode 100644 lib/pdcp/rte_pdcp.h create mode 100644 lib/pdcp/version.map

doc/api/doxy-api-index.md +2 -1
index debbe4134f..cd7a6cae44 100644
@@ -128,7 +128,8 @@ The public API headers are grouped by topics:
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [PDCP hdr](@ref rte_pdcp_hdr.h)
+  [PDCP hdr](@ref rte_pdcp_hdr.h),
+  [PDCP](@ref rte_pdcp.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
doc/api/doxy-api.conf.in index renamed from doc/api/doxy-api.conf.in +0 -0

d230a19e1f..58789308a9 100644

doc/api/doxy-api.conf.in +1 -0
@@ -62,6 +62,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 0812ce6026..d217c04ea9 100644

lib/meson.build +1 -0
@@ -64,6 +64,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 = [
lib/pdcp/meson.build new file mode renamed from lib/pdcp/meson.build +0 -0

100644 index 0000000000..ccaf426240

lib/pdcp/meson.build new file +16 -0
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2023 Marvell.
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+sources = files(
+        'pdcp_crypto.c',
+        'pdcp_process.c',
+        'rte_pdcp.c',
+        )
+headers = files('rte_pdcp.h')
+
+deps += ['mbuf', 'net', 'cryptodev', 'security']
lib/pdcp/pdcp_crypto.c new file renamed from lib/pdcp/pdcp_crypto.c +0 -0

mode 100644 index 0000000000..755e27ec9e

lib/pdcp/pdcp_crypto.c new file +10 -0
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_pdcp.h>
+
+#include "pdcp_crypto.h"
+
+int
+pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_crypto.c new file +10 -0
+{
+	RTE_SET_USED(entity);
+	RTE_SET_USED(conf);
+	return 0;
+}
+
+void
+pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity) {
+	RTE_SET_USED(entity);
+}
lib/pdcp/pdcp_crypto.h new file renamed from lib/pdcp/pdcp_crypto.h +0 -0

mode 100644 index 0000000000..6563331d37

lib/pdcp/pdcp_crypto.h new file +15 -0
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CRYPTO_H
+#define PDCP_CRYPTO_H
+
+#include <rte_pdcp.h>
+
+int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
+			    const struct rte_pdcp_entity_conf *conf);
+
+void pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity);
+
+#endif /* PDCP_CRYPTO_H */
lib/pdcp/pdcp_entity.h new file renamed from lib/pdcp/pdcp_entity.h +0 -0

mode 100644 index 0000000000..ca1d56b516

lib/pdcp/pdcp_entity.h new file +18 -0
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_ENTITY_H
+#define PDCP_ENTITY_H
+
+#include <rte_common.h>
+#include <rte_crypto_sym.h>
+#include <rte_mempool.h>
+#include <rte_pdcp.h>
+#include <rte_security.h>
+
+struct entity_priv;
+
+/* IV generation function based on the entity configuration */
+typedef void (*iv_gen_t)(struct rte_crypto_op *cop, const struct
+entity_priv

*en_priv,

lib/pdcp/pdcp_entity.h new file +28 -0
+			 uint32_t count);
+
+struct entity_state {
+	uint32_t rx_next;
+	uint32_t tx_next;
+	uint32_t rx_deliv;
+	uint32_t rx_reord;
+};
+
+/*
+ * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv]
+[entity_dl/ul]  */
+
+struct entity_priv {
+	/** Crypto sym session. */
+	struct rte_cryptodev_sym_session *crypto_sess;
+	/** Entity specific IV generation function. */
+	iv_gen_t iv_gen;
+	/** Entity state variables. */
+	struct entity_state state;
+	/** Flags. */
+	struct {
+		/** PDCP PDU has 4 byte MAC-I. */
+		uint64_t is_authenticated : 1;
+		/** Cipher offset & length in bits. */
+		uint64_t is_ciph_in_bits : 1;
+		/** Auth offset & length in bits. */
+		uint64_t is_auth_in_bits : 1;

lib/pdcp/pdcp_entity.h

Quoted 10 lines
lib/pdcp/pdcp_entity.h new file +10 -0
+		/** Is UL/transmitting PDCP entity. */
+		uint64_t is_ul_entity : 1;
+		/** Is NULL auth. */
+		uint64_t is_null_auth : 1;
+	} flags;
+	/** Crypto op pool. */
+	struct rte_mempool *cop_pool;
+	/** PDCP header size. */
+	uint8_t hdr_sz;
+	/** PDCP AAD size. For AES-CMAC, additional message is prepended

for

Quoted 10 lines

the operation. */

lib/pdcp/pdcp_entity.h new file +8 -0
+	uint8_t aad_sz;
+	/** Device ID of the device to be used for offload. */
+	uint8_t dev_id;
+};
+
+struct entity_priv_dl_part {
+	/* NOTE: when in-order-delivery is supported, post PDCP packets
+would

need to cached. */

lib/pdcp/pdcp_entity.h

Quoted 6 lines
lib/pdcp/pdcp_entity.h new file +6 -0
+	uint8_t dummy;
+};
+
+struct entity_priv_ul_part {
+	/*
+	 * NOTE: when re-establish is supported, plain PDCP packets &

COUNT

Quoted 50 lines

values need to be

lib/pdcp/pdcp_entity.h new file +12 -0
+	 * cached.
+	 */
+	uint8_t dummy;
+};
+
+static inline struct entity_priv *
+entity_priv_get(const struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity)); }
+
+static inline struct entity_priv_dl_part * entity_dl_part_get(const
+struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +5 -0
+}
+
+static inline struct entity_priv_ul_part * entity_ul_part_get(const
+struct rte_pdcp_entity *entity) {
+	return RTE_PTR_ADD(entity, sizeof(struct rte_pdcp_entity) +

sizeof(struct entity_priv));

lib/pdcp/pdcp_entity.h new file +7 -0
+}
+
+static inline int
+pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size) {
+	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8; }
+
+#endif /* PDCP_ENTITY_H */
lib/pdcp/pdcp_process.c new renamed from lib/pdcp/pdcp_process.c +0 -0

file mode 100644 index 0000000000..d4b158536d

lib/pdcp/pdcp_process.c new file +17 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_memcpy.h>
+#include <rte_pdcp.h>
+#include <rte_pdcp_hdr.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct

rte_crypto_sym_xform **c_xfrm,

lib/pdcp/pdcp_process.c

Quoted 8 lines
lib/pdcp/pdcp_process.c new file +8 -0
+		     struct rte_crypto_sym_xform **a_xfrm) {
+	*c_xfrm = NULL;
+	*a_xfrm = NULL;
+
+	if (conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER)

{

Quoted 26 lines
lib/pdcp/pdcp_process.c new file +3 -0
+		*c_xfrm = conf->crypto_xfrm;
+		*a_xfrm = conf->crypto_xfrm->next;
+	} else if (conf->crypto_xfrm->type ==

RTE_CRYPTO_SYM_XFORM_AUTH) {

lib/pdcp/pdcp_process.c new file +11 -0
+		*a_xfrm = conf->crypto_xfrm;
+		*c_xfrm = conf->crypto_xfrm->next;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	int ret;
+
+	/**
+	 * flags.is_authenticated
+	 *
+	 * MAC-I would be added in case of control plane packets and when

authentication

lib/pdcp/pdcp_process.c new file +1 -0
+	 * transform is not NULL.
Quoted 8 lines

lib/pdcp/pdcp_process.c

Quoted 5 lines
lib/pdcp/pdcp_process.c new file +3 -0
+	 */
+
+	if (conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL)

lib/pdcp/pdcp_process.c new file +1 -0
+		en_priv->flags.is_authenticated = 1;

This check should be added after getting the xfrm.
If domain == control and a_xfrm is NULL, then it should be error, right?

[Anoob] Lib PDCP would handle such cases. Even if a_xfrm is non NULL but is NULL auth, it is lib PDCP which would add zeroized digest. And a_xfrm == NULL is also treated as NULL auth generally. The comment above this explains the same. Idea is to have lib PDCP handle all possible cases rather than putting too much restrictions on both app & PMD.

Quoted 154 lines
Quoted 15 lines
lib/pdcp/pdcp_process.c new file +13 -0
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (a_xfrm != NULL)
+		en_priv->flags.is_authenticated = 1;
+
+	/**
+	 * flags.is_ciph_in_bits
+	 *
+	 * For ZUC & SNOW3G cipher algos, offset & length need to be
+provided

in bits.

lib/pdcp/pdcp_process.c

Quoted 3 lines
lib/pdcp/pdcp_process.c new file +3 -0
+	 */
+
+	if ((c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2)
||
> +	    (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3))

lib/pdcp/pdcp_process.c

Quoted 6 lines
lib/pdcp/pdcp_process.c new file +6 -0
+		en_priv->flags.is_ciph_in_bits = 1;
+
+	/**
+	 * flags.is_auth_in_bits
+	 *
+	 * For ZUC & SNOW3G authentication algos, offset & length need to

be

lib/pdcp/pdcp_process.c

Quoted 5 lines

provided in bits.

lib/pdcp/pdcp_process.c new file +4 -0
+	 */
+
+	if (a_xfrm != NULL) {
+		if ((a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_SNOW3G_UIA2)

Quoted 7 lines

||

lib/pdcp/pdcp_process.c new file +6 -0
+		    (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3))
+			en_priv->flags.is_auth_in_bits = 1;
+	}
+
+	/**
+	 * flags.is_ul_entity

lib/pdcp/pdcp_process.c

Quoted 10 lines
lib/pdcp/pdcp_process.c new file +10 -0
+	 *
+	 * Indicate whether the entity is UL/transmitting PDCP entity.
+	 */
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		en_priv->flags.is_ul_entity = 1;
+
+	/**
+	 * flags.is_null_auth
+	 *
+	 * For NULL auth, 4B zeros need to be added by lib PDCP. Indicate

that

Quoted 103 lines
lib/pdcp/pdcp_process.c new file +3 -0
+	 * algo is NULL auth to perform the same.
+	 */
+	if (a_xfrm != NULL && a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_NULL)

lib/pdcp/pdcp_process.c new file +14 -0
+		en_priv->flags.is_null_auth = 1;
+
+	/**
+	 * hdr_sz
+	 *
+	 * PDCP header size of the entity
+	 */
+	en_priv->hdr_sz = pdcp_hdr_size_get(conf->pdcp_xfrm.sn_size);
+
+	/**
+	 * aad_sz
+	 *
+	 * For AES-CMAC, additional message is prepended for processing.
+Need

to be trimmed after

lib/pdcp/pdcp_process.c new file +3 -0
+	 * crypto processing is done.
+	 */
+	if (a_xfrm != NULL && a_xfrm->auth.algo ==

RTE_CRYPTO_AUTH_AES_CMAC)

lib/pdcp/pdcp_process.c new file +9 -0
+		en_priv->aad_sz = 8;
+	else
+		en_priv->aad_sz = 0;
+
+	return 0;
+}
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +15 -0
+{
+	struct entity_priv *en_priv;
+	int ret;
+
+	if (entity == NULL || conf == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	ret = pdcp_entity_priv_populate(en_priv, conf);
+	if (ret)
+		return ret;
+
+	return 0;
+}
lib/pdcp/pdcp_process.h new renamed from lib/pdcp/pdcp_process.h +0 -0

file mode 100644 index 0000000000..fd53fff0aa

lib/pdcp/pdcp_process.h new file +11 -0
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_PROCESS_H
+#define PDCP_PROCESS_H
+
+#include <rte_pdcp.h>
+
+int
+pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf);

lib/pdcp/pdcp_process.h new file +2 -0
+
+#endif /* PDCP_PROCESS_H */
lib/pdcp/rte_pdcp.c new file mode renamed from lib/pdcp/rte_pdcp.c +0 -0

100644 index 0000000000..8914548dbd

lib/pdcp/rte_pdcp.c new file +31 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) {
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE); }
+
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) {
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
Quoted 8 lines

lib/pdcp/rte_pdcp.c line 40

Quoted 6 lines
lib/pdcp/rte_pdcp.c new file +6 -0
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

[Anoob] I do not think so. I checked rte_ethdev.h, rte_flow.h etc and all APIs are returning negative values in case of errors.

Quoted 22 lines
Quoted 18 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+
+	if (conf->pdcp_xfrm.en_ordering || conf-
Quoted 1 line

pdcp_xfrm.remove_duplicates || conf->is_slrb ||

lib/pdcp/rte_pdcp.c new file +9 -0
+	    conf->en_sec_offload) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	/*
+	 * 6.3.2 PDCP SN
+	 * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length
+of the

PDCP SN is

lib/pdcp/rte_pdcp.c new file +2 -0
+	 * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or
+sl-

PDCP-SN-Size in

lib/pdcp/rte_pdcp.c

Quoted 3 lines
lib/pdcp/rte_pdcp.c new file +3 -0
+	 * TS 38.331 [3])
+	 */
+	if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Quoted 7 lines

lib/pdcp/rte_pdcp.c line 58

Quoted 4 lines
lib/pdcp/rte_pdcp.c new file +4 -0
+	    (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}

Check for PDCP crypto algos may also be added.
As only 4 cipher and 4 auth algos are supported in case of PDCP.

[Anoob] Validation happens when we create session. Please check,
pdcp: add crypto session create and destroy

Quoted 8 lines

lib/pdcp/rte_pdcp.c line 63

Quoted 6 lines
lib/pdcp/rte_pdcp.c new file +5 -0
+
+	if (conf->pdcp_xfrm.hfn || conf->pdcp_xfrm.hfn_threshold) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

What is the reason to set errno as EINVAL when HFN is set?

[Anoob] HFN is part of pdcp_xfrm which is defined in rte_security. Lib PDCP allows user to specify complete 32 bit count value using rte_pdcp_entity_conf.count. Since HFN is also used to construct 32 bit count value, having two ways to set count would be misleading. Hence lib PDCP would enforce that application does not set this value.

Quoted 91 lines
Quoted 91 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+
+	entity_size = pdcp_entity_size_get(conf);
+	if (entity_size < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	entity = rte_zmalloc_socket("pdcp_entity", entity_size,

RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);

lib/pdcp/rte_pdcp.c new file +33 -0
+	if (entity == NULL) {
+		rte_errno = -ENOMEM;
+		return NULL;
+	}
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->state.rx_deliv = conf->count;
+	en_priv->state.tx_next = conf->count;
+	en_priv->cop_pool = conf->cop_pool;
+
+	/* Setup crypto session */
+	ret = pdcp_crypto_sess_create(entity, conf);
+	if (ret)
+		goto entity_free;
+
+	ret = pdcp_process_func_set(entity, conf);
+	if (ret)
+		goto crypto_sess_destroy;
+
+	return entity;
+
+crypto_sess_destroy:
+	pdcp_crypto_sess_destroy(entity);
+entity_free:
+	rte_free(entity);
+	rte_errno = ret;
+	return NULL;
+}
+
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity, struct
+rte_mbuf

*out_mb[])

lib/pdcp/rte_pdcp.c new file +35 -0
+{
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	/* Teardown crypto sessions */
+	pdcp_crypto_sess_destroy(pdcp_entity);
+
+	rte_free(pdcp_entity);
+
+	RTE_SET_USED(out_mb);
+	return 0;
+}
+
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[])
+{
+	struct entity_priv *en_priv;
+
+	if (pdcp_entity == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(pdcp_entity);
+
+	if (en_priv->flags.is_ul_entity) {
+		en_priv->state.tx_next = 0;
+	} else {
+		en_priv->state.rx_next = 0;
+		en_priv->state.rx_deliv = 0;
+	}
+
+	RTE_SET_USED(out_mb);
+
+	return 0;
+}
lib/pdcp/rte_pdcp.h new file mode renamed from lib/pdcp/rte_pdcp.h +0 -0

100644 index 0000000000..33c355b05a

lib/pdcp/rte_pdcp.h new file +7 -0
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef RTE_PDCP_H
+#define RTE_PDCP_H
+
Quoted 8 lines

lib/pdcp/rte_pdcp.h line 13

Quoted 6 lines
lib/pdcp/rte_pdcp.h new file +6 -0
+/**
+ * @file rte_pdcp.h
+ *
+ * RTE PDCP support.
+ *
+ * librte_pdcp provides a framework for PDCP protocol processing.

A framework for PDCP protocol processing.

[Anoob] Will do next version.

Quoted 16 lines
Quoted 4 lines
lib/pdcp/rte_pdcp.h new file +3 -0
+ */
+
+#include <rte_compat.h>

lib/pdcp/rte_pdcp.h line 26

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+#include <rte_common.h>
+#include <rte_mempool.h>
+#include <rte_security.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * PDCP entity.

You can probably explain more on what a PDCP entity is.

[Anoob] Will do in next version.

Quoted 21 lines

lib/pdcp/rte_pdcp.h

Quoted 5 lines
lib/pdcp/rte_pdcp.h new file +4 -0
+ */
+struct rte_pdcp_entity {
+	/**
+	 * PDCP entities may hold packets for purposes of in-order delivery

(in

lib/pdcp/rte_pdcp.h

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +6 -0
+	 * 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 t-Reordering

timer

lib/pdcp/rte_pdcp.h new file +3 -0
+	 * expires.
+	 *
+	 * When post-processing of PDCP packet which completes a

sequence is

lib/pdcp/rte_pdcp.h

Quoted 1 line
lib/pdcp/rte_pdcp.h new file +1 -0
+	 * done, the API may return more packets than enqueued.

Application is

lib/pdcp/rte_pdcp.h

Quoted 1 line
lib/pdcp/rte_pdcp.h new file +1 -0
+	 * expected to provide *rte_pdcp_pkt_post_process()* with

*out_mb*

Quoted 8 lines

lib/pdcp/rte_pdcp.h

Quoted 1 line
lib/pdcp/rte_pdcp.h new file +1 -0
+	 * which can hold maximum number of packets which may be

returned.

lib/pdcp/rte_pdcp.h

Quoted 1 line
lib/pdcp/rte_pdcp.h new file +1 -0
+	 */

The above comment explains the need for holding the packets. But it does not talk about the parameter it is explaining. This explanation should be part of programmer's guide and not the API guide.

[Anoob] Agreed. Will make the required changes.

Quoted 8 lines

lib/pdcp/rte_pdcp.h line 46

Quoted 4 lines
lib/pdcp/rte_pdcp.h new file +3 -0
+	uint32_t max_pkt_cache;
+	/** User area for saving application data. */
+	uint64_t user_area[2];

Is it being used right now in the patches? If not, can we add it later?
And if really needed now, can we rename to user_data

[Anoob] Agreed. Will remove.

Quoted 19 lines
Quoted 8 lines
lib/pdcp/rte_pdcp.h new file +7 -0
+} __rte_cache_aligned;
+
+/**
+ * PDCP entity configuration to be used for establishing an entity.
+ */
+/* Structure rte_pdcp_entity_conf 8< */ struct rte_pdcp_entity_conf {
+	/** PDCP transform for the entity. */

lib/pdcp/rte_pdcp.h

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+	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;
+	/** 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

Quoted 6 lines

lib/pdcp/rte_pdcp.h

Quoted 2 lines

this value.

lib/pdcp/rte_pdcp.h new file +1 -0
+	 */

If the HFN is to be ignored, then why to add a check in entity establish and return EINVAL?
It should be silently ignored in that case with a debug print at max.

[Anoob] Explained above. Please check.

Quoted 122 lines

lib/pdcp/rte_pdcp.h

Quoted 4 lines
lib/pdcp/rte_pdcp.h new file +2 -0
+	uint32_t count;
+	/** Indicate whether the PDCP entity belongs to Side Link Radio

Bearer.

Quoted 30 lines

*/

lib/pdcp/rte_pdcp.h new file +7 -0
+	bool is_slrb;
+	/** Enable security offload on the device specified. */
+	bool en_sec_offload;
+	/** Device on which security/crypto session need to be created. */
+	uint8_t dev_id;
+	/** Reverse direction during IV generation. Can be used to simulate
+UE

crypto processing.*/

lib/pdcp/rte_pdcp.h new file +21 -0
+	bool reverse_iv_direction;
+};
+/* >8 End of structure rte_pdcp_entity_conf. */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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);

lib/pdcp/rte_pdcp.h

Quoted 10 lines
lib/pdcp/rte_pdcp.h new file +10 -0
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 5.1.3 PDCP entity release
+ *
+ * Release PDCP entity.
+ *
+ * For UL/transmitting PDCP entity, all stored PDCP SDUs would be

dropped.

Quoted 76 lines

+ * For DL/receiving PDCP entity, the stored PDCP SDUs would be

lib/pdcp/rte_pdcp.h new file +9 -0
+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

+ */

lib/pdcp/rte_pdcp.h new file +25 -0
+__rte_experimental
+int
+rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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.
+ *
+ * For UL/transmitting PDCP entity, *out_mb* buffer would be unused.
+ *
+ * @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

+ */

lib/pdcp/rte_pdcp.h new file +10 -0
+__rte_experimental
+int
+rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
+			struct rte_mbuf *out_mb[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PDCP_H */
lib/pdcp/version.map new file mode renamed from lib/pdcp/version.map +0 -0

100644 index 0000000000..923e165f3f

lib/pdcp/version.map new file +10 -1
@@ -0,0 +1,10 @@
+EXPERIMENTAL {
+	global:
+
+	# added in 23.07
+	rte_pdcp_entity_establish;
+	rte_pdcp_entity_release;
+	rte_pdcp_entity_suspend;
+
+	local: *;
+};
--

2.25.1

#25 lore raw

Hi Anoob,

Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
(quoted diff) +2 -0
+static int
+pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +8 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	int ret;
+
+	/**
+	 * flags.is_authenticated
+	 *
+	 * MAC-I would be added in case of control plane packets and when

authentication

lib/pdcp/pdcp_process.c new file +1 -0
+	 * transform is not NULL.
Quoted 8 lines

Review

Quoted 5 lines
lib/pdcp/pdcp_crypto.c new file +3 -0
+	 */
+
+	if (conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL)

(quoted diff) +1 -0
+		en_priv->flags.is_authenticated = 1;

This check should be added after getting the xfrm.
If domain == control and a_xfrm is NULL, then it should be error, right?

Quoted 5 lines

[Anoob] Lib PDCP would handle such cases. Even if a_xfrm is non NULL but is NULL auth, it is lib PDCP which would add zeroized digest. And a_xfrm == NULL is also treated as NULL auth generally. The comment above this explains the same. Idea is to have lib PDCP handle all possible cases rather than putting too much restrictions on both app & PMD.

I believe there is a case in PDCP which allows no integrity as well.(LTE Uplane) In that case, a_xfrm is NULL is not equivalent to NULL auth.
No integrity would mean no MAC-I.

Quoted 45 lines
Quoted 36 lines
Quoted 36 lines
lib/pdcp/rte_pdcp.c new file mode renamed from lib/pdcp/rte_pdcp.c +0 -0

100644 index 0000000000..8914548dbd

lib/pdcp/rte_pdcp.c new file +31 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) {
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE); }
+
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) {
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
Quoted 8 lines

lib/pdcp/rte_pdcp.c line 40

Quoted 6 lines
lib/pdcp/rte_pdcp.c new file +6 -0
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

Quoted 2 lines

[Anoob] I do not think so. I checked rte_ethdev.h, rte_flow.h etc and all APIs are returning negative values in case of errors.

Check again lib/ethdev/rte_ethdev.c
rte_errno are set as positive values only and
APIs return error numbers as negative values.

Quoted 31 lines
Quoted 23 lines
Quoted 19 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+
+	if (conf->pdcp_xfrm.en_ordering || conf-
Quoted 1 line

pdcp_xfrm.remove_duplicates || conf->is_slrb ||

lib/pdcp/rte_pdcp.c new file +9 -0
+	    conf->en_sec_offload) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	/*
+	 * 6.3.2 PDCP SN
+	 * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length
+of the

PDCP SN is

lib/pdcp/rte_pdcp.c new file +2 -0
+	 * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or
+sl-

PDCP-SN-Size in

lib/pdcp/rte_pdcp.c

Quoted 3 lines
lib/pdcp/rte_pdcp.c new file +3 -0
+	 * TS 38.331 [3])
+	 */
+	if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Quoted 7 lines

lib/pdcp/rte_pdcp.c line 58

Quoted 4 lines
lib/pdcp/rte_pdcp.c new file +4 -0
+	    (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}

Check for PDCP crypto algos may also be added.
As only 4 cipher and 4 auth algos are supported in case of PDCP.

Quoted 2 lines

[Anoob] Validation happens when we create session. Please check,
pdcp: add crypto session create and destroy

Agreed, already acked that.

Quoted 33 lines
Quoted 9 lines

lib/pdcp/rte_pdcp.c line 63

Quoted 7 lines
lib/pdcp/rte_pdcp.c new file +5 -0
+
+	if (conf->pdcp_xfrm.hfn || conf->pdcp_xfrm.hfn_threshold) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

What is the reason to set errno as EINVAL when HFN is set?

[Anoob] HFN is part of pdcp_xfrm which is defined in rte_security. Lib PDCP allows user to specify complete 32 bit count value using rte_pdcp_entity_conf.count. Since HFN is also used to construct 32 bit count value, having two ways to set count would be misleading. Hence lib PDCP would enforce that application does not set this value.

Quoted 17 lines
Quoted 6 lines
lib/pdcp/rte_pdcp.c new file +5 -0
+/**
+ * PDCP entity configuration to be used for establishing an entity.
+ */
+/* Structure rte_pdcp_entity_conf 8< */ struct rte_pdcp_entity_conf {
+	/** PDCP transform for the entity. */

lib/pdcp/rte_pdcp.c

Quoted 10 lines
lib/pdcp/rte_pdcp.c new file +10 -0
+	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;
+	/** 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

Quoted 9 lines
Quoted 6 lines

lib/pdcp/rte_pdcp.c

Quoted 2 lines

this value.

lib/pdcp/rte_pdcp.c new file +1 -0
+	 */

If the HFN is to be ignored, then why to add a check in entity establish and return EINVAL?
It should be silently ignored in that case with a debug print at max.

[Anoob] Explained above. Please check.

No it is not explained. Above comments says
" pdcp_xfrm.hfn would be ignored as the HFN would be derived from this value"

Here you are saying the field will be ignored.
But while creating entity, it is returning EINVAL if hfn is provided.

#26 lore raw

Hi Akhil,

Please see inline.

Thanks,
Anoob

Quoted 43 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 1:10 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 02/22] lib: add pdcp protocol

Hi Anoob,

Quoted 24 lines
Quoted 15 lines
Quoted 15 lines
(quoted diff) +3 -0
+static int
+pdcp_entity_priv_populate(struct entity_priv *en_priv, const
+struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c new file +9 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	int ret;
+
+	/**
+	 * flags.is_authenticated
+	 *
+	 * MAC-I would be added in case of control plane packets and
+when

authentication

lib/pdcp/pdcp_process.c new file +1 -0
+	 * transform is not NULL.
Quoted 8 lines

Review

Quoted 5 lines
lib/pdcp/pdcp_crypto.c new file +3 -0
+	 */
+
+	if (conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL)

(quoted diff) +1 -0
+		en_priv->flags.is_authenticated = 1;

This check should be added after getting the xfrm.
If domain == control and a_xfrm is NULL, then it should be error, right?

Quoted 5 lines

[Anoob] Lib PDCP would handle such cases. Even if a_xfrm is non NULL but is NULL auth, it is lib PDCP which would add zeroized digest. And a_xfrm == NULL is also treated as NULL auth generally. The comment above this explains the same. Idea is to have lib PDCP handle all possible cases rather than putting too much restrictions on both app &

Quoted 5 lines

PMD.

I believe there is a case in PDCP which allows no integrity as well.(LTE Uplane) In that case, a_xfrm is NULL is not equivalent to NULL auth.
No integrity would mean no MAC-I.

[Anoob] The comment explains the logic. If it is control plane, then digest is must and that case lib PDCP is trying to handle. Anyway, adding an extra error check and returning error in that case is not a big deal. Will add that in the appropriate place.

Quoted 50 lines
Quoted 50 lines
Quoted 49 lines
Quoted 37 lines
lib/pdcp/rte_pdcp.c new file renamed from lib/pdcp/rte_pdcp.c +0 -0

mode
100644 index 0000000000..8914548dbd

lib/pdcp/rte_pdcp.c new file +28 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) {
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct
+entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE); }
+

lib/pdcp/rte_pdcp.c line 38

Quoted 10 lines
lib/pdcp/rte_pdcp.c new file +10 -0
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) {
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

Quoted 6 lines
Quoted 2 lines

[Anoob] I do not think so. I checked rte_ethdev.h, rte_flow.h etc and all APIs are returning negative values in case of errors.

Check again lib/ethdev/rte_ethdev.c
rte_errno are set as positive values only and APIs return error numbers as negative values.

[Anoob] Okay. There are many APIs were this is not done correctly (check rte_flow.h) . For lib PDCP additions, I'll have this handled. Some of these conventions should be documented to avoid confusion.

Quoted 82 lines
Quoted 33 lines
Quoted 25 lines
Quoted 21 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+
+	if (conf->pdcp_xfrm.en_ordering || conf-
Quoted 1 line

pdcp_xfrm.remove_duplicates || conf->is_slrb ||

lib/pdcp/rte_pdcp.c new file +9 -0
+	    conf->en_sec_offload) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}
+
+	/*
+	 * 6.3.2 PDCP SN
+	 * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length
+of the

PDCP SN is

lib/pdcp/rte_pdcp.c new file +2 -0
+	 * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or
+sl-

PDCP-SN-Size in

lib/pdcp/rte_pdcp.c

Quoted 3 lines
lib/pdcp/rte_pdcp.c new file +3 -0
+	 * TS 38.331 [3])
+	 */
+	if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Quoted 7 lines

lib/pdcp/rte_pdcp.c line 58

Quoted 4 lines
lib/pdcp/rte_pdcp.c new file +4 -0
+	    (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
+		rte_errno = -ENOTSUP;
+		return NULL;
+	}

Check for PDCP crypto algos may also be added.
As only 4 cipher and 4 auth algos are supported in case of PDCP.

Quoted 2 lines

[Anoob] Validation happens when we create session. Please check,
pdcp: add crypto session create and destroy

Agreed, already acked that.

Quoted 10 lines
Quoted 9 lines

lib/pdcp/rte_pdcp.c line 63

Quoted 7 lines
lib/pdcp/rte_pdcp.c new file +5 -0
+
+	if (conf->pdcp_xfrm.hfn || conf->pdcp_xfrm.hfn_threshold) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

What is the reason to set errno as EINVAL when HFN is set?

Quoted 3 lines

[Anoob] HFN is part of pdcp_xfrm which is defined in rte_security. Lib PDCP allows user to specify complete 32 bit count value using rte_pdcp_entity_conf.count. Since HFN is also used to construct 32 bit

count

Quoted 1 line

value, having two ways to set count would be misleading. Hence lib PDCP

would

Quoted 7 lines

enforce that application does not set this value.

Quoted 5 lines

lib/pdcp/rte_pdcp.c

Quoted 5 lines
lib/pdcp/rte_pdcp.c new file +4 -0
+/**
+ * PDCP entity configuration to be used for establishing an entity.
+ */
+/* Structure rte_pdcp_entity_conf 8< */ struct rte_pdcp_entity_conf

{

Quoted 12 lines
Quoted 12 lines

lib/pdcp/rte_pdcp.c

Quoted 11 lines
lib/pdcp/rte_pdcp.c new file +11 -0
+	/** 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;
+	/** 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

Quoted 4 lines
Quoted 4 lines

lib/pdcp/rte_pdcp.c

Quoted 2 lines

this value.

lib/pdcp/rte_pdcp.c new file +1 -0
+	 */

If the HFN is to be ignored, then why to add a check in entity establish

and

Quoted 3 lines
Quoted 2 lines

return EINVAL?
It should be silently ignored in that case with a debug print at max.

Quoted 8 lines
Quoted 2 lines

[Anoob] Explained above. Please check.

No it is not explained. Above comments says
" pdcp_xfrm.hfn would be ignored as the HFN would be derived from this value"

Here you are saying the field will be ignored.
But while creating entity, it is returning EINVAL if hfn is provided.

[Anoob] Agreed. Will address in next version.

#27 lore raw
Quoted 52 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
lib/pdcp/rte_pdcp.c new file renamed from lib/pdcp/rte_pdcp.c +0 -0

mode
100644 index 0000000000..8914548dbd

lib/pdcp/rte_pdcp.c new file +12 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

lib/pdcp/rte_pdcp.c

Quoted 8 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) {
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct
+entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_DOWNLINK)

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

lib/pdcp/rte_pdcp.c line 22

Quoted 2 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

Quoted 22 lines
Quoted 21 lines
Quoted 10 lines
Quoted 10 lines
lib/pdcp/rte_pdcp.c new file +10 -0
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE); }
+
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) {
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
Quoted 8 lines

lib/pdcp/rte_pdcp.c line 40

Quoted 6 lines
lib/pdcp/rte_pdcp.c new file +6 -0
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

[Anoob] I do not think so. I checked rte_ethdev.h, rte_flow.h etc and all APIs are returning negative values in case of errors.

Quoted 7 lines
Quoted 3 lines

Check again lib/ethdev/rte_ethdev.c
rte_errno are set as positive values only and APIs return error numbers as negative values.

[Anoob] Okay. There are many APIs were this is not done correctly (check rte_flow.h) . For lib PDCP additions, I'll have this handled. Some of these conventions should be documented to avoid confusion.

I am not sure what you are referring to.
I cannot find any discrepancy in rte_flow.c as well.

Can you give an example where it is wrong. We can ask specific people to fix that.

Regarding documentation.
It is mentioned in rte_errno.h
/**
* Error number value, stored per-thread, which can be queried after
* calls to certain functions to determine why those functions failed. *
* Uses standard values from errno.h wherever possible, with a small number
* of additional possible values for RTE-specific conditions. */
#define rte_errno RTE_PER_LCORE(_rte_errno)

And errno.h has all positive values defined.

#28 lore raw

Hi Akhil,

Please see inline.

Thanks,
Anoob

Quoted 93 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 2:16 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 02/22] lib: add pdcp protocol

Quoted 30 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
lib/pdcp/rte_pdcp.c new renamed from lib/pdcp/rte_pdcp.c +0 -0

file mode
100644 index 0000000000..8914548dbd

lib/pdcp/rte_pdcp.c new file +12 -0
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_errno.h>
+#include <rte_pdcp.h>
+#include <rte_malloc.h>
+
+#include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+#include "pdcp_process.h"
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

lib/pdcp/rte_pdcp.c

Quoted 8 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+static int
+pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) {
+	int size;
+
+	size = sizeof(struct rte_pdcp_entity) + sizeof(struct
+entity_priv);
+
+	if (conf->pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_DOWNLINK)

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

lib/pdcp/rte_pdcp.c line 22

Quoted 2 lines
lib/pdcp/rte_pdcp.c new file +2 -0
+		size += sizeof(struct entity_priv_dl_part);
+	else if (conf->pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

lib/pdcp/rte_pdcp.c

Quoted 8 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+		size += sizeof(struct entity_priv_ul_part);
+	else
+		return -EINVAL;
+
+	return RTE_ALIGN_CEIL(size, RTE_CACHE_LINE_SIZE); }
+
+struct rte_pdcp_entity *
+rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf

*conf) {

Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
Quoted 10 lines

lib/pdcp/rte_pdcp.c line 40

Quoted 8 lines
lib/pdcp/rte_pdcp.c new file +8 -0
+	struct rte_pdcp_entity *entity = NULL;
+	struct entity_priv *en_priv;
+	int ret, entity_size;
+
+	if (conf == NULL || conf->cop_pool == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}

errnos are normally set as positive values.

[Anoob] I do not think so. I checked rte_ethdev.h, rte_flow.h etc and all APIs are returning negative values in case of errors.

Quoted 8 lines
Quoted 3 lines

Check again lib/ethdev/rte_ethdev.c
rte_errno are set as positive values only and APIs return error numbers as negative values.

[Anoob] Okay. There are many APIs were this is not done correctly (check
rte_flow.h) . For lib PDCP additions, I'll have this handled. Some of these conventions should be documented to avoid confusion.

I am not sure what you are referring to.
I cannot find any discrepancy in rte_flow.c as well.

Can you give an example where it is wrong. We can ask specific people to fix that.

Regarding documentation.
It is mentioned in rte_errno.h
/**
* Error number value, stored per-thread, which can be queried after
* calls to certain functions to determine why those functions failed. *
* Uses standard values from errno.h wherever possible, with a small
number
* of additional possible values for RTE-specific conditions. */
#define rte_errno RTE_PER_LCORE(_rte_errno)

Quoted 1 line

And errno.h has all positive values defined.

[Anoob] Agreed. There are descriptions in rte_flow.h which got us confused. Thanks for the clarification. Changes in PDCP will come in next version.

#29 lore raw

PATCH v2 3/22 pdcp: add pre and post-process

In reply to Anoob Joseph

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()). Functionality of pre-process & post-process varies based on the type of entity. Registration of entity specific function pointer allows skipping multiple checks that would come in datapath otherwise.

---
 lib/pdcp/rte_pdcp.h  | 97 ++++++++++++++++++++++++++++++++++++++++++++
 lib/pdcp/version.map |  3 ++
 2 files changed, 100 insertions(+)
lib/pdcp/rte_pdcp.h +97 -0
index 33c355b05a..75dc569f66 100644
@@ -22,10 +22,29 @@
 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
@@ -150,6 +169,84 @@ int
 rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
 			struct rte_mbuf *out_mb[]);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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[in, 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. Crypto ops would be allocated by
+ *   ``rte_pdcp_pkt_pre_process`` API.
+ * @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
+ */
+__rte_experimental
+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);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * 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 *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.
+ */
+__rte_experimental
+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);
+}
+
 #ifdef __cplusplus
 }
 #endif
lib/pdcp/version.map +3 -0
index 923e165f3f..f9ff30600a 100644
@@ -6,5 +6,8 @@ EXPERIMENTAL {
 	rte_pdcp_entity_release;
 	rte_pdcp_entity_suspend;
 
+	rte_pdcp_pkt_post_process;
+	rte_pdcp_pkt_pre_process;
+
 	local: *;
 };
Signature · 1 line
2.25.1
Acked-by on v2 3/22
#30 lore raw

RE: [PATCH v2 03/22] pdcp: add pre and post-process

Quoted 9 lines

Subject: [PATCH v2 03/22] pdcp: add pre and post-process

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()). Functionality of pre-process & post-process varies based on the type of entity. Registration of entity specific function pointer allows skipping multiple checks that would come in datapath otherwise.

Quoted 3 lines

Haven't compiled it yet. Check for doxygen build issues if any.

#31 lore raw

PATCH v2 4/22 pdcp: add packet group

In reply to Anoob Joseph

Crypto processing in PDCP is performed asynchronously by rte_cryptodev_enqueue_burst() and rte_cryptodev_dequeue_burst(). Since cryptodev dequeue can return crypto operations belonging to multiple entities, rte_pdcp_pkt_crypto_group() is added to help grouping crypto operations belonging to same entity.

---
 lib/pdcp/meson.build      |   1 +
 lib/pdcp/rte_pdcp.h       |   2 +
 lib/pdcp/rte_pdcp_group.h | 125 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+)
 create mode 100644 lib/pdcp/rte_pdcp_group.h
lib/pdcp/meson.build +1 -0
index ccaf426240..08679b743a 100644
@@ -13,5 +13,6 @@ sources = files(
         'rte_pdcp.c',
         )
 headers = files('rte_pdcp.h')
+indirect_headers += files('rte_pdcp_group.h')
 
 deps += ['mbuf', 'net', 'cryptodev', 'security']
lib/pdcp/rte_pdcp.h +2 -0
index 75dc569f66..54f88e3fd3 100644
@@ -247,6 +247,8 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,
 	return entity->post_process(entity, in_mb, out_mb, num, nb_err);
 }
 
+#include <rte_pdcp_group.h>
+
 #ifdef __cplusplus
 }
 #endif
lib/pdcp/rte_pdcp_group.h new file +125 -0

125 lines not on this page · raw message

Signature · 1 line
2.25.1
#32 lore raw

RE: [PATCH v2 04/22] pdcp: add packet group

Quoted 64 lines

Subject: [PATCH v2 04/22] pdcp: add packet group

Crypto processing in PDCP is performed asynchronously by rte_cryptodev_enqueue_burst() and rte_cryptodev_dequeue_burst(). Since cryptodev dequeue can return crypto operations belonging to multiple entities, rte_pdcp_pkt_crypto_group() is added to help grouping crypto operations belonging to same entity.

---
 lib/pdcp/meson.build      |   1 +
 lib/pdcp/rte_pdcp.h       |   2 +
 lib/pdcp/rte_pdcp_group.h | 125
++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+)
 create mode 100644 lib/pdcp/rte_pdcp_group.h
lib/pdcp/meson.build +1 -0
index ccaf426240..08679b743a 100644
@@ -13,5 +13,6 @@ sources = files(
         'rte_pdcp.c',
         )
 headers = files('rte_pdcp.h')
+indirect_headers += files('rte_pdcp_group.h')
 
 deps += ['mbuf', 'net', 'cryptodev', 'security']
lib/pdcp/rte_pdcp.h +2 -0
index 75dc569f66..54f88e3fd3 100644
@@ -247,6 +247,8 @@ rte_pdcp_pkt_post_process(const struct
 rte_pdcp_entity *entity,
 	return entity->post_process(entity, in_mb, out_mb, num, nb_err);
 }
 
+#include <rte_pdcp_group.h>
+
 #ifdef __cplusplus
 }

#endif

lib/pdcp/rte_pdcp_group.h new file +14 -0
new file mode 100644
index 0000000000..cb322f55c7
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 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
Quoted 3 lines

related
+ * packets by sessions they belong to.
+ */

Why do we need to have a separate public header file which we do not wish user to use directly for just a single API?

Can it not be added into rte_pdcp.h?

Quoted 97 lines
lib/pdcp/rte_pdcp_group.h new file +40 -0
+
+#include <rte_common.h>
+#include <rte_crypto.h>
+#include <rte_cryptodev.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 *sess = cop->sym[0].session;
+
+	return (struct rte_pdcp_entity *)
+		rte_cryptodev_sym_session_opaque_data_get(sess);
+}
+
+/**
+ * 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 @see 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.
+ *
+ */

lib/pdcp/rte_pdcp_group.h new file +2 -0
+static inline uint16_t
+rte_pdcp_pkt_crypto_group(struct rte_crypto_op *cop[], struct rte_mbuf

*mb[],

lib/pdcp/rte_pdcp_group.h new file +13 -0
+			  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;

lib/pdcp/rte_pdcp_group.h new file +18 -0
+
+		/* 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]);

lib/pdcp/rte_pdcp_group.h line 119

Quoted 10 lines
lib/pdcp/rte_pdcp_group.h new file +10 -0
+	}
+
+	/* Finalize last group */
+	if (ps != NULL) {
+		grp[n].cnt = mb + j - grp[n].m;
+		n++;
+	}
+
+	return n;
+}

These APIs are being called from application directly (as per the cover letter). Should be marked as experimental and also add them in version.map

Quoted 8 lines
lib/pdcp/rte_pdcp_group.h new file +6 -1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PDCP_GROUP_H */
--

2.25.1

#33 lore raw

RE: [PATCH v2 04/22] pdcp: add packet group

Hi Akhil, Konstantin,

Please see inline.

Thanks,
Anoob

Quoted 85 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Tuesday, May 16, 2023 9:27 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 04/22] pdcp: add packet group

Quoted 4 lines

Subject: [PATCH v2 04/22] pdcp: add packet group

Crypto processing in PDCP is performed asynchronously by rte_cryptodev_enqueue_burst() and rte_cryptodev_dequeue_burst().

Since

Quoted 60 lines

cryptodev dequeue can return crypto operations belonging to multiple entities, rte_pdcp_pkt_crypto_group() is added to help grouping crypto operations belonging to same entity.

---
 lib/pdcp/meson.build      |   1 +
 lib/pdcp/rte_pdcp.h       |   2 +
 lib/pdcp/rte_pdcp_group.h | 125
++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+)
 create mode 100644 lib/pdcp/rte_pdcp_group.h
lib/pdcp/meson.build index renamed from lib/pdcp/meson.build +0 -0

ccaf426240..08679b743a 100644

lib/pdcp/meson.build +1 -0
@@ -13,5 +13,6 @@ sources = files(
         'rte_pdcp.c',
         )
 headers = files('rte_pdcp.h')
+indirect_headers += files('rte_pdcp_group.h')
 
 deps += ['mbuf', 'net', 'cryptodev', 'security'] diff --git

a/lib/pdcp/rte_pdcp.h b/lib/pdcp/rte_pdcp.h index
75dc569f66..54f88e3fd3 100644

lib/pdcp/rte_pdcp.h +2 -0
@@ -247,6 +247,8 @@ rte_pdcp_pkt_post_process(const struct
 rte_pdcp_entity *entity,
 	return entity->post_process(entity, in_mb, out_mb, num, nb_err);  }
 
+#include <rte_pdcp_group.h>
+
 #ifdef __cplusplus
 }
 #endif
lib/pdcp/rte_pdcp_group.h new renamed from lib/pdcp/rte_pdcp_group.h +0 -0

file mode 100644 index 0000000000..cb322f55c7

lib/pdcp/rte_pdcp_group.h new file +16 -0
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 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
Quoted 3 lines

related
+ * packets by sessions they belong to.
+ */

Why do we need to have a separate public header file which we do not wish user to use directly for just a single API?

Quoted 1 line

Can it not be added into rte_pdcp.h?

[Anoob] This follows how the code organization is done in lib IPsec. My understanding is, it is done for 2 reasons,
1. Separate out helper inline functions into a separate header
2. Main header focus on core design of the protocol interface, ie, structs, macros & APIs.

Also, lib_pdcp.h is bound to grow. So rather than splitting it later, why don't we start with better organized code layout which is already followed in similar use case, ie, lib IPsec.

@Konstantin, did you have any other thoughts when you made the split this way?

Quoted 110 lines
Quoted 41 lines
lib/pdcp/rte_pdcp_group.h new file +40 -0
+
+#include <rte_common.h>
+#include <rte_crypto.h>
+#include <rte_cryptodev.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 *sess = cop->sym[0].session;
+
+	return (struct rte_pdcp_entity *)
+		rte_cryptodev_sym_session_opaque_data_get(sess);
+}
+
+/**
+ * Take as input completed crypto ops, extract related mbufs and
+group them
Quoted 4 lines

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*

Quoted 2 lines

flag
+ * in rte_mbuf.ol_flags. The crypto_ops would be freed after the

grouping.

Quoted 7 lines

+ *
+ * Note that application must ensure only crypto-ops prepared by +lib_pdcp is
+ * provided back to @see rte_pdcp_pkt_crypto_group().
+ *
+ * @param cop
+ * The address of an array of *num* pointers to the input

*rte_crypto_op*

Quoted 3 lines

+ * structures.
+ * @param[out] mb
+ * The address of an array of *num* pointers to output *rte_mbuf*

structures.

Quoted 2 lines

+ * @param[out] grp
+ * The address of an array of *num* to output *rte_pdcp_group*

structures.

Quoted 46 lines

+ * @param num
+ * The maximum number of crypto-ops to process.
+ * @return
+ * Number of filled elements in *grp* array.
+ *
+ */

lib/pdcp/rte_pdcp_group.h new file +3 -0
+static inline uint16_t
+rte_pdcp_pkt_crypto_group(struct rte_crypto_op *cop[], struct
+rte_mbuf

*mb[],

lib/pdcp/rte_pdcp_group.h new file +12 -0
+			  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;

lib/pdcp/rte_pdcp_group.h new file +23 -0
+
+		/* 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;
Quoted 8 lines

lib/pdcp/rte_pdcp_group.h line 119

Quoted 5 lines
lib/pdcp/rte_pdcp_group.h new file +5 -0
+		n++;
+	}
+
+	return n;
+}

These APIs are being called from application directly (as per the cover letter). Should be marked as experimental and also add them in version.map

[Anoob] Agreed. Will do.

Quoted 10 lines
Quoted 10 lines
lib/pdcp/rte_pdcp_group.h new file +6 -1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_PDCP_GROUP_H */
--

2.25.1

#34 lore raw

PATCH v2 5/22 pdcp: add crypto session create and destroy

In reply to Anoob Joseph

Add routines to create & destroy sessions. PDCP lib would take crypto transforms as input and creates the session on the corresponding device after verifying capabilities.

---
 lib/pdcp/pdcp_crypto.c | 222 ++++++++++++++++++++++++++++++++++++++++-
 lib/pdcp/pdcp_crypto.h |   6 ++
 2 files changed, 225 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_crypto.c +219 -3
index 755e27ec9e..0e6e7d99d8 100644
@@ -2,20 +2,236 @@
  * Copyright(C) 2023 Marvell.
  */
 
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
+#include <rte_cryptodev.h>
+#include <rte_errno.h>
 #include <rte_pdcp.h>
 
 #include "pdcp_crypto.h"
+#include "pdcp_entity.h"
+
+static int
+pdcp_crypto_caps_cipher_verify(uint8_t dev_id, const struct rte_crypto_sym_xform *c_xfrm)
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+	cap_idx.algo.cipher = c_xfrm->cipher.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_cipher(cap, c_xfrm->cipher.key.length,
+							c_xfrm->cipher.iv.length);
+
+	return ret;
+}
+
+static int
+pdcp_crypto_caps_auth_verify(uint8_t dev_id, const struct rte_crypto_sym_xform *a_xfrm)
+{
+	const struct rte_cryptodev_symmetric_capability *cap;
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	int ret;
+
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+	cap_idx.algo.auth = a_xfrm->auth.algo;
+
+	cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (cap == NULL)
+		return -1;
+
+	ret = rte_cryptodev_sym_capability_check_auth(cap, a_xfrm->auth.key.length,
+						      a_xfrm->auth.digest_length,
+						      a_xfrm->auth.iv.length);
+
+	return ret;
+}
+
+static int
+pdcp_crypto_xfrm_validate(const struct rte_pdcp_entity_conf *conf,
+				 const struct rte_crypto_sym_xform *c_xfrm,
+				 const struct rte_crypto_sym_xform *a_xfrm,
+				 bool is_auth_then_cipher)
+{
+	uint16_t ciph_iv_len, auth_digest_len, auth_iv_len;
+	int ret;
+
+	/*
+	 * Uplink means PDCP entity is configured for transmit. Downlink means PDCP entity is
+	 * configured for receive. When integrity protection is enabled, PDCP always performs
+	 * digest-encrypted or auth-gen-encrypt for uplink (and decrypt-auth-verify for downlink).
+	 * So for uplink, crypto chain would be auth-cipher while for downlink it would be
+	 * cipher-auth.
+	 *
+	 * When integrity protection is not required, xform would be cipher only.
+	 */
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK) {
+
+		/* With UPLINK, if auth is enabled, it should be before cipher */
+		if (a_xfrm != NULL && !is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With UPLINK, cipher operation must be encrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_ENCRYPT)
+			return -EINVAL;
+
+		/* With UPLINK, auth operation (if present) must be generate */
+		if (a_xfrm != NULL && a_xfrm->auth.op != RTE_CRYPTO_AUTH_OP_GENERATE)
+			return -EINVAL;
+
+	} else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
+
+		/* With DOWNLINK, if auth is enabled, it should be after cipher */
+		if (a_xfrm != NULL && is_auth_then_cipher)
+			return -EINVAL;
+
+		/* With DOWNLINK, cipher operation must be decrypt */
+		if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_DECRYPT)
+			return -EINVAL;
+
+		/* With DOWNLINK, auth operation (if present) must be verify */
+		if (a_xfrm != NULL && a_xfrm->auth.op != RTE_CRYPTO_AUTH_OP_VERIFY)
+			return -EINVAL;
+
+	} else {
+		return -EINVAL;
+	}
+
+	if ((c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_NULL) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_AES_CTR) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_ZUC_EEA3) &&
+	    (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2))
+		return -EINVAL;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
+		ciph_iv_len = 0;
+	else
+		ciph_iv_len = PDCP_IV_LEN;
+
+	if (ciph_iv_len != c_xfrm->cipher.iv.length)
+		return -EINVAL;
+
+	if (a_xfrm != NULL) {
+		if ((a_xfrm->auth.algo != RTE_CRYPTO_AUTH_NULL) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_AES_CMAC) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_ZUC_EIA3) &&
+		    (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2))
+			return -EINVAL;
+
+		/* For AUTH NULL, lib PDCP would add 4 byte 0s */
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			auth_digest_len = 0;
+		else
+			auth_digest_len = PDCP_MAC_I_LEN;
+
+		if (auth_digest_len != a_xfrm->auth.digest_length)
+			return -EINVAL;
+
+		if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2))
+			auth_iv_len = PDCP_IV_LEN;
+		else
+			auth_iv_len = 0;
+
+		if (a_xfrm->auth.iv.length != auth_iv_len)
+			return -EINVAL;
+	}
+
+	if (!rte_cryptodev_is_valid_dev(conf->dev_id))
+		return -EINVAL;
+
+	ret = pdcp_crypto_caps_cipher_verify(conf->dev_id, c_xfrm);
+	if (ret)
+		return -ENOTSUP;
+
+	if (a_xfrm != NULL) {
+		ret = pdcp_crypto_caps_auth_verify(conf->dev_id, a_xfrm);
+		if (ret)
+			return -ENOTSUP;
+	}
+
+	return 0;
+}
 
 int
 pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf)
 {
-	RTE_SET_USED(entity);
-	RTE_SET_USED(conf);
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	struct entity_priv *en_priv;
+	bool is_auth_then_cipher;
+	int ret;
+
+	if (entity == NULL || conf == NULL || conf->crypto_xfrm == NULL)
+		return -EINVAL;
+
+	en_priv = entity_priv_get(entity);
+
+	en_priv->dev_id = conf->dev_id;
+
+	if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		c_xfrm = conf->crypto_xfrm;
+		a_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = false;
+	} else if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		a_xfrm = conf->crypto_xfrm;
+		c_xfrm = conf->crypto_xfrm->next;
+		is_auth_then_cipher = true;
+	} else {
+		return -EINVAL;
+	}
+
+	ret = pdcp_crypto_xfrm_validate(conf, c_xfrm, a_xfrm, is_auth_then_cipher);
+	if (ret)
+		return ret;
+
+	if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
+		c_xfrm->cipher.iv.offset = 0;
+	else
+		c_xfrm->cipher.iv.offset = PDCP_IV_OFFSET;
+
+	if (a_xfrm != NULL) {
+		if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm->auth.iv.offset = 0;
+		else
+			if (c_xfrm->cipher.iv.offset)
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET + PDCP_IV_LEN;
+			else
+				a_xfrm->auth.iv.offset = PDCP_IV_OFFSET;
+	}
+
+	if (conf->sess_mpool == NULL)
+		return -EINVAL;
+
+	en_priv->crypto_sess = rte_cryptodev_sym_session_create(conf->dev_id, conf->crypto_xfrm,
+								conf->sess_mpool);
+	if (en_priv->crypto_sess == NULL) {
+		/* API returns positive values as error codes */
+		return -rte_errno;
+	}
+
+	rte_cryptodev_sym_session_opaque_data_set(en_priv->crypto_sess, (uint64_t)entity);
+
 	return 0;
 }
 
 void
 pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
 {
-	RTE_SET_USED(entity);
+	struct entity_priv *en_priv;
+
+	en_priv = entity_priv_get(entity);
+
+	if (en_priv->crypto_sess != NULL) {
+		rte_cryptodev_sym_session_free(en_priv->dev_id, en_priv->crypto_sess);
+		en_priv->crypto_sess = NULL;
+	}
 }
lib/pdcp/pdcp_crypto.h +6 -0
index 6563331d37..e178ddd725 100644
@@ -5,8 +5,14 @@
 #ifndef PDCP_CRYPTO_H
 #define PDCP_CRYPTO_H
 
+#include <rte_crypto.h>
+#include <rte_crypto_sym.h>
 #include <rte_pdcp.h>
 
+#define PDCP_IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op))
+#define PDCP_IV_LEN 16
+#define PDCP_MAC_I_LEN 4
+
 int pdcp_crypto_sess_create(struct rte_pdcp_entity *entity,
 			    const struct rte_pdcp_entity_conf *conf);
 
Signature · 1 line
2.25.1
Acked-by on v2 5/22
#35 lore raw

RE: [PATCH v2 05/22] pdcp: add crypto session create and destroy

Quoted 8 lines

Subject: [PATCH v2 05/22] pdcp: add crypto session create and destroy

Add routines to create & destroy sessions. PDCP lib would take crypto transforms as input and creates the session on the corresponding device after verifying capabilities.

#36 lore raw

PATCH v2 6/22 pdcp: add pre and post process for UL

In reply to Anoob Joseph

Add routines to perform pre & post processing based on the type of entity. To avoid checks in datapath, there are different function pointers registered based on the following,
1. Control plane v/s user plane
2. 12 bit v/s 18 bit SN

For control plane only 12 bit SN need to be supported (as per PDCP specification).

---
 lib/pdcp/pdcp_entity.h  |  42 +++++
 lib/pdcp/pdcp_process.c | 330 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 372 insertions(+)
lib/pdcp/pdcp_entity.h +42 -0
index ca1d56b516..46cdaead09 100644
@@ -92,4 +92,46 @@ pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
 	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
 }
 
+static inline uint32_t
+pdcp_window_size_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return 1 << (sn_size - 1);
+}
+
+static inline uint32_t
+pdcp_sn_mask_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return (1 << sn_size) - 1;
+}
+
+static inline uint32_t
+pdcp_sn_from_count_get(uint32_t count, enum rte_security_pdcp_sn_size sn_size)
+{
+	return (count & pdcp_sn_mask_get(sn_size));
+}
+
+static inline uint32_t
+pdcp_hfn_mask_get(enum rte_security_pdcp_sn_size sn_size)
+{
+	return ~pdcp_sn_mask_get(sn_size);
+}
+
+static inline uint32_t
+pdcp_hfn_from_count_get(uint32_t count, enum rte_security_pdcp_sn_size sn_size)
+{
+	return (count & pdcp_hfn_mask_get(sn_size)) >> sn_size;
+}
+
+static inline uint32_t
+pdcp_count_from_hfn_sn_get(uint32_t hfn, uint32_t sn, enum rte_security_pdcp_sn_size sn_size)
+{
+	return (((hfn << sn_size) & pdcp_hfn_mask_get(sn_size)) | (sn & pdcp_sn_mask_get(sn_size)));
+}
+
+static inline uint32_t
+pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size)
+{
+	return (1 << (32 - sn_size)) - 1;
+}
+
 #endif /* PDCP_ENTITY_H */
lib/pdcp/pdcp_process.c +330 -0

341 lines not on this page · raw message

Signature · 1 line
2.25.1
Acked-by on v2 6/22
#37 lore raw

RE: [PATCH v2 06/22] pdcp: add pre and post process for UL

Quoted 8 lines

Subject: [PATCH v2 06/22] pdcp: add pre and post process for UL

Add routines to perform pre & post processing based on the type of entity. To avoid checks in datapath, there are different function pointers registered based on the following,
1. Control plane v/s user plane
2. 12 bit v/s 18 bit SN

Quoted 7 lines

For control plane only 12 bit SN need to be supported (as per PDCP specification).

---

#38 lore raw

PATCH v2 7/22 pdcp: add pre and post process for DL

In reply to Anoob Joseph

Add routines to perform pre & post processing for down link entities.

---
 lib/pdcp/pdcp_entity.h  |   2 +
 lib/pdcp/pdcp_process.c | 453 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 455 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
index 46cdaead09..d2d9bbe149 100644
@@ -13,6 +13,8 @@
 
 struct entity_priv;
 
+#define PDCP_HFN_MIN 0
+
 /* IV generation function based on the entity configuration */
 typedef void (*iv_gen_t)(struct rte_crypto_op *cop, const struct entity_priv *en_priv,
 			 uint32_t count);
lib/pdcp/pdcp_process.c +453 -0

474 lines not on this page · raw message

Signature · 1 line
2.25.1
#39 lore raw

RE: [PATCH v2 07/22] pdcp: add pre and post process for DL

Quoted 33 lines

static int
pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct
rte_pdcp_entity_conf *conf)
{

lib/pdcp/pdcp_process.c +3 -0
+	struct entity_priv *en_priv = entity_priv_get(entity);
+
 	entity->pre_process = NULL;
 	entity->post_process = NULL;
@@ -342,6 +756,13 @@ pdcp_pre_post_func_set(struct rte_pdcp_entity
 *entity, const struct rte_pdcp_ent
 		entity->post_process = pdcp_post_process_ul;
 	}
 
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL) &&

lib/pdcp/pdcp_process.c +6 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)) {
+		entity->pre_process = pdcp_pre_process_cplane_sn_12_dl;
+		entity->post_process = pdcp_post_process_cplane_sn_12_dl;
+	}
+
 	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c +1 -0
 	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
 	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)) {
@@ -356,6 +777,38 @@ pdcp_pre_post_func_set(struct rte_pdcp_entity
 *entity, const struct rte_pdcp_ent
 		entity->post_process = pdcp_post_process_ul;
 	}
 
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent · line 783

Quoted 3 lines
lib/pdcp/pdcp_process.c +3 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (en_priv->flags.is_authenticated)) {

is_authenticated is checked only in case of DL.
For UL, the check is there in the same function.
Can we have it consistent with UL?

Quoted 38 lines
(quoted diff) +2 -0
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_dl_ip;
+		entity->post_process =

pdcp_post_process_uplane_sn_12_dl_ip;

lib/pdcp/pdcp_process.c +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c +8 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_dl;
+		entity->post_process = pdcp_post_process_uplane_sn_12_dl;
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c +5 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_dl_ip;
+		entity->post_process =

pdcp_post_process_uplane_sn_18_dl_ip;

lib/pdcp/pdcp_process.c +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain == RTE_SECURITY_PDCP_MODE_DATA)

&&

lib/pdcp/pdcp_process.c +7 -1
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18) &&
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) &&
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_dl;
+		entity->post_process = pdcp_post_process_uplane_sn_18_dl;
+	}
+
 	if (entity->pre_process == NULL || entity->post_process == NULL)
 		return -ENOTSUP;
 
--

2.25.1

#40 lore raw

RE: [PATCH v2 07/22] pdcp: add pre and post process for DL

HI Akhil,

Please see inline.

Thanks,
Anoob

Quoted 52 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 12:17 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 07/22] pdcp: add pre and post process for DL

Quoted 15 lines

static int
pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct
rte_pdcp_entity_conf *conf) {

lib/pdcp/pdcp_process.c +3 -0
+	struct entity_priv *en_priv = entity_priv_get(entity);
+
 	entity->pre_process = NULL;
 	entity->post_process = NULL;
@@ -342,6 +756,13 @@ pdcp_pre_post_func_set(struct rte_pdcp_entity
 *entity, const struct rte_pdcp_ent
 		entity->post_process = pdcp_post_process_ul;
 	}
 
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_CONTROL) &&

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12)

&&

lib/pdcp/pdcp_process.c pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent

Quoted 3 lines
lib/pdcp/pdcp_process.c +3 -0
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)) {
+		entity->pre_process = pdcp_pre_process_cplane_sn_12_dl;
+		entity->post_process =

pdcp_post_process_cplane_sn_12_dl;

lib/pdcp/pdcp_process.c pdcp_post_process_ul(const struct rte_pdcp_entity *entity,

Quoted 3 lines
lib/pdcp/pdcp_process.c +2 -0
+	}
+
 	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_DATA) &&

Quoted 1 line

(conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Quoted 1 line

(conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)) {

@@

lib/pdcp/pdcp_process.c pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent

Quoted 6 lines

-356,6 +777,38 @@ pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent

lib/pdcp/pdcp_process.c +1 -0
 		entity->post_process = pdcp_post_process_ul;
 	}
 
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_DATA)

Review

Quoted 2 lines

&&

(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Quoted 7 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)

&&

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (en_priv->flags.is_authenticated)) {

is_authenticated is checked only in case of DL. For UL, the check is there in the same function. Can we have it consistent with UL?

[Anoob] The check here allows registering different function pointers so that datapath checks are avoided. The level of optimization vs level of code complexity is the reason for delta. For DL, most of the code is the same and so we added const flags & allowed different functions to call with flags. For UL, the code had significant changes in both paths. Hence an extra top level check was okay.

Quoted 52 lines

Review

Quoted 2 lines
(quoted diff) +1 -0
+		entity->pre_process =

pdcp_pre_process_uplane_sn_12_dl_ip;

lib/pdcp/pdcp_process.c pdcp_post_process_ul(const struct rte_pdcp_entity *entity,

Quoted 5 lines
(quoted diff) +1 -0
+		entity->post_process =

pdcp_post_process_uplane_sn_12_dl_ip;

lib/pdcp/pdcp_process.c +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_DATA)

Review

Quoted 2 lines

&&

(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_12)

&&

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)

&&

lib/pdcp/pdcp_process.c pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent

Quoted 3 lines
lib/pdcp/pdcp_process.c +3 -0
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_12_dl;
+		entity->post_process =

pdcp_post_process_uplane_sn_12_dl;

lib/pdcp/pdcp_process.c pdcp_post_process_ul(const struct rte_pdcp_entity *entity,

Quoted 3 lines
lib/pdcp/pdcp_process.c +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_DATA)

Review

Quoted 2 lines

&&

(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18)

&&

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)

&&

Review

Quoted 2 lines
(quoted diff) +2 -0
+	    (en_priv->flags.is_authenticated)) {
+		entity->pre_process =

pdcp_pre_process_uplane_sn_18_dl_ip;

lib/pdcp/pdcp_process.c pdcp_post_process_ul(const struct rte_pdcp_entity *entity,

Quoted 5 lines
(quoted diff) +1 -0
+		entity->post_process =

pdcp_post_process_uplane_sn_18_dl_ip;

lib/pdcp/pdcp_process.c +3 -0
+	}
+
+	if ((conf->pdcp_xfrm.domain ==

RTE_SECURITY_PDCP_MODE_DATA)

Review

Quoted 2 lines

&&

(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.sn_size == RTE_SECURITY_PDCP_SN_SIZE_18)

&&

Review

Quoted 1 line
(quoted diff) +1 -0
+	    (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)

&&

lib/pdcp/pdcp_process.c pdcp_pre_post_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_ent

Quoted 3 lines
lib/pdcp/pdcp_process.c +3 -0
+	    (!en_priv->flags.is_authenticated)) {
+		entity->pre_process = pdcp_pre_process_uplane_sn_18_dl;
+		entity->post_process =

pdcp_post_process_uplane_sn_18_dl;

Quoted 7 lines
lib/pdcp/pdcp_process.c +2 -1
+	}
+
 	if (entity->pre_process == NULL || entity->post_process == NULL)
 		return -ENOTSUP;
 
--

2.25.1

#41 lore raw

PATCH v2 8/22 pdcp: add IV generation routines

In reply to Anoob Joseph

For PDCP, IV generated has varying formats depending on the ciphering and authentication algorithm used. Add routines to populate IV accordingly.

---
 lib/pdcp/pdcp_entity.h  |  87 ++++++++++++
 lib/pdcp/pdcp_process.c | 284 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 371 insertions(+)
lib/pdcp/pdcp_entity.h +87 -0
index d2d9bbe149..3108795977 100644
@@ -26,6 +26,89 @@ struct entity_state {
 	uint32_t rx_reord;
 };
 
+union auth_iv_partial {
+	/* For AES-CMAC, there is no IV, but message gets prepended */
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+	} aes_cmac;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_37_39 : 3;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_65_71 : 7;
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_120_127 : 8;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t zero_37_39 : 3;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_65_71 : 7;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t rsvd_120_127 : 8;
+#endif
+	} zs;
+	uint64_t u64[2];
+};
+
+union cipher_iv_partial {
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+		uint64_t zero_64_127;
+	} aes_ctr;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+		uint64_t rsvd_64_127;
+	} zs;
+	uint64_t u64[2];
+};
+
 /*
  * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]
  */
@@ -35,6 +118,10 @@ struct entity_priv {
 	struct rte_cryptodev_sym_session *crypto_sess;
 	/** Entity specific IV generation function. */
 	iv_gen_t iv_gen;
+	/** Pre-prepared auth IV. */
+	union auth_iv_partial auth_iv_part;
+	/** Pre-prepared cipher IV. */
+	union cipher_iv_partial cipher_iv_part;
 	/** Entity state variables. */
 	struct entity_state state;
 	/** Flags. */
lib/pdcp/pdcp_process.c +284 -0

302 lines not on this page · raw message

Signature · 1 line
2.25.1
#42 lore raw

RE: [PATCH v2 08/22] pdcp: add IV generation routines

Quoted 57 lines

Subject: [PATCH v2 08/22] pdcp: add IV generation routines

For PDCP, IV generated has varying formats depending on the ciphering and authentication algorithm used. Add routines to populate IV accordingly.

---
 lib/pdcp/pdcp_entity.h  |  87 ++++++++++++
 lib/pdcp/pdcp_process.c | 284
++++++++++++++++++++++++++++++++++++++++
 2 files changed, 371 insertions(+)
lib/pdcp/pdcp_entity.h +36 -0
index d2d9bbe149..3108795977 100644
@@ -26,6 +26,89 @@ struct entity_state {
 	uint32_t rx_reord;
 };
 
+union auth_iv_partial {
+	/* For AES-CMAC, there is no IV, but message gets prepended */
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+	} aes_cmac;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_37_39 : 3;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+
+		uint64_t rsvd_65_71 : 7;
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_120_127 : 8;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t zero_37_39 : 3;
+		uint64_t zero_40_63 : 24;
+

lib/pdcp/pdcp_entity.h struct entity_state { · line 74

Quoted 10 lines
lib/pdcp/pdcp_entity.h +10 -0
+		uint64_t direction_64 : 1;
+		uint64_t rsvd_65_71 : 7;
+		uint64_t rsvd_72_111 : 40;
+		uint64_t direction_112 : 1;
+		uint64_t rsvd_113_119 : 7;
+		uint64_t rsvd_120_127 : 8;
+#endif
+	} zs;
+	uint64_t u64[2];
+};

Can we add pictorial comments for each of the IV formats? So that we may not need to refer the specifications again and again.

Quoted 411 lines
lib/pdcp/pdcp_entity.h +41 -0
+
+union cipher_iv_partial {
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+		uint64_t zero_64_127;
+	} aes_ctr;
+	struct {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+		uint64_t count : 32;
+		uint64_t zero_38_39 : 2;
+		uint64_t direction : 1;
+		uint64_t bearer : 5;
+		uint64_t zero_40_63 : 24;
+#else
+		uint64_t count : 32;
+		uint64_t bearer : 5;
+		uint64_t direction : 1;
+		uint64_t zero_38_39 : 2;
+		uint64_t zero_40_63 : 24;
+#endif
+		uint64_t rsvd_64_127;
+	} zs;
+	uint64_t u64[2];
+};
+
 /*
  * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]
  */
@@ -35,6 +118,10 @@ struct entity_priv {
 	struct rte_cryptodev_sym_session *crypto_sess;
 	/** Entity specific IV generation function. */
 	iv_gen_t iv_gen;
+	/** Pre-prepared auth IV. */
+	union auth_iv_partial auth_iv_part;
+	/** Pre-prepared cipher IV. */
+	union cipher_iv_partial cipher_iv_part;
 	/** Entity state variables. */
 	struct entity_state state;
 	/** Flags. */
lib/pdcp/pdcp_process.c +44 -0
index 79d6ca352a..9c1a5e0669 100644
@@ -13,6 +13,181 @@
 #include "pdcp_entity.h"
 #include "pdcp_process.h"
 
+/* Enum of supported algorithms for ciphering */
+enum pdcp_cipher_algo {
+	PDCP_CIPHER_ALGO_NULL,
+	PDCP_CIPHER_ALGO_AES,
+	PDCP_CIPHER_ALGO_ZUC,
+	PDCP_CIPHER_ALGO_SNOW3G,
+	PDCP_CIPHER_ALGO_MAX
+};
+
+/* Enum of supported algorithms for integrity */
+enum pdcp_auth_algo {
+	PDCP_AUTH_ALGO_NULL,
+	PDCP_AUTH_ALGO_AES,
+	PDCP_AUTH_ALGO_ZUC,
+	PDCP_AUTH_ALGO_SNOW3G,
+	PDCP_AUTH_ALGO_MAX
+};
+
+/* IV generation functions based on type of operation (cipher - auth) */
+
+static void
+pdcp_iv_gen_null_null(struct rte_crypto_op *cop, const struct entity_priv
 *en_priv, uint32_t count)
+{
+	/* No IV required for NULL cipher + NULL auth */
+	RTE_SET_USED(cop);
+	RTE_SET_USED(en_priv);
+	RTE_SET_USED(count);
+}
+
+static void
+pdcp_iv_gen_null_aes_cmac(struct rte_crypto_op *cop, const struct
 entity_priv *en_priv,
+			  uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr;
+	uint64_t m;
+
+	/* AES-CMAC requires message to be prepended with info on count etc
 */
+
+	/* Prepend by 8 bytes to add custom message */
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +6 -0
+
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_null_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_process.c +8 -0
+			 uint32_t count)
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, 16);
+}
+
+static void
+pdcp_iv_gen_zs_null(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c +7 -0
+{
+	uint64_t iv_u64;
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64 = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +6 -0
+	rte_memcpy(iv, &iv_u64, 8);
+	rte_memcpy(iv + 8, &iv_u64, 8);
+}
+
+static void
+pdcp_iv_gen_zs_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c +8 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	/* Generating cipher IV */
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +7 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	iv += PDCP_IV_LEN;
+
+	/* Generating auth IV */
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +8 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
+static void
+pdcp_iv_gen_zs_aes_cmac(struct rte_crypto_op *cop, const struct entity_priv

*en_priv,

lib/pdcp/pdcp_process.c +10 -0
+			uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +5 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+	rte_memcpy(iv + 8, &iv_u64[0], 8);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_aes_cmac(struct rte_crypto_op *cop, const struct

entity_priv *en_priv,

lib/pdcp/pdcp_process.c +11 -0
+			    uint32_t count)
+{
+	struct rte_crypto_sym_op *op = cop->sym;
+	struct rte_mbuf *mb = op->m_src;
+	uint8_t *m_ptr, *iv;
+	uint64_t iv_u64[2];
+	uint64_t m;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +5 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LEN);
+
+	m_ptr = (uint8_t *)rte_pktmbuf_prepend(mb, 8);
+	m = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +5 -0
+	rte_memcpy(m_ptr, &m, 8);
+}
+
+static void
+pdcp_iv_gen_aes_ctr_zs(struct rte_crypto_op *cop, const struct entity_priv

*en_priv, uint32_t count)

lib/pdcp/pdcp_process.c +7 -0
+{
+	uint64_t iv_u64[2];
+	uint8_t *iv;
+
+	iv = rte_crypto_op_ctod_offset(cop, uint8_t *, PDCP_IV_OFFSET);
+
+	iv_u64[0] = en_priv->cipher_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +6 -0
+	iv_u64[1] = 0;
+	rte_memcpy(iv, iv_u64, PDCP_IV_LEN);
+
+	iv += PDCP_IV_LEN;
+
+	iv_u64[0] = en_priv->auth_iv_part.u64[0] |

((uint64_t)(rte_cpu_to_be_32(count)));

lib/pdcp/pdcp_process.c +6 -0
+	rte_memcpy(iv, &iv_u64[0], 8);
+
+	iv_u64[1] = iv_u64[0] ^ en_priv->auth_iv_part.u64[1];
+	rte_memcpy(iv + 8, &iv_u64[1], 8);
+}
+
 static int
 pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct

rte_crypto_sym_xform **c_xfrm,

lib/pdcp/pdcp_process.c +0 -0
 		     struct rte_crypto_sym_xform **a_xfrm)
@@ -36,6 +211,111 @@ pdcp_crypto_xfrm_get(const struct

rte_pdcp_entity_conf *conf, struct rte_crypto_

lib/pdcp/pdcp_process.c +2 -0
 	return 0;
 }
 
+static int
+pdcp_iv_gen_func_set(struct rte_pdcp_entity *entity, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_process.c +31 -0
+{
+	struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
+	enum rte_security_pdcp_direction direction;
+	enum pdcp_cipher_algo ciph_algo;
+	enum pdcp_auth_algo auth_algo;
+	struct entity_priv *en_priv;
+	int ret;
+
+	en_priv = entity_priv_get(entity);
+
+	direction = conf->pdcp_xfrm.pkt_dir;
+	if (conf->reverse_iv_direction)
+		direction = !direction;
+
+	ret = pdcp_crypto_xfrm_get(conf, &c_xfrm, &a_xfrm);
+	if (ret)
+		return ret;
+
+	if (c_xfrm == NULL)
+		return -EINVAL;
+
+	memset(&en_priv->auth_iv_part, 0, sizeof(en_priv->auth_iv_part));
+	memset(&en_priv->cipher_iv_part, 0, sizeof(en_priv->cipher_iv_part));
+
+	switch (c_xfrm->cipher.algo) {
+	case RTE_CRYPTO_CIPHER_NULL:
+		ciph_algo = PDCP_CIPHER_ALGO_NULL;
+		break;
+	case RTE_CRYPTO_CIPHER_AES_CTR:
+		ciph_algo = PDCP_CIPHER_ALGO_AES;
+		en_priv->cipher_iv_part.aes_ctr.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c +24 -0
+		en_priv->cipher_iv_part.aes_ctr.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_SNOW3G_UEA2:
+		ciph_algo = PDCP_CIPHER_ALGO_SNOW3G;
+		en_priv->cipher_iv_part.zs.bearer = conf->pdcp_xfrm.bearer;
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	case RTE_CRYPTO_CIPHER_ZUC_EEA3:
+		ciph_algo = PDCP_CIPHER_ALGO_ZUC;
+		en_priv->cipher_iv_part.zs.bearer = conf->pdcp_xfrm.bearer;
+		en_priv->cipher_iv_part.zs.direction = direction;
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	if (a_xfrm != NULL) {
+		switch (a_xfrm->auth.algo) {
+		case RTE_CRYPTO_AUTH_NULL:
+			auth_algo = PDCP_AUTH_ALGO_NULL;
+			break;
+		case RTE_CRYPTO_AUTH_AES_CMAC:
+			auth_algo = PDCP_AUTH_ALGO_AES;
+			en_priv->auth_iv_part.aes_cmac.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c +5 -0
+			en_priv->auth_iv_part.aes_cmac.direction = direction;
+			break;
+		case RTE_CRYPTO_AUTH_SNOW3G_UIA2:
+			auth_algo = PDCP_AUTH_ALGO_SNOW3G;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c +6 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		case RTE_CRYPTO_AUTH_ZUC_EIA3:
+			auth_algo = PDCP_AUTH_ALGO_ZUC;
+			en_priv->auth_iv_part.zs.bearer = conf-
Quoted 1 line

pdcp_xfrm.bearer;

lib/pdcp/pdcp_process.c +11 -0
+			en_priv->auth_iv_part.zs.direction_64 = direction;
+			en_priv->auth_iv_part.zs.direction_112 = direction;
+			break;
+		default:
+			return -ENOTSUP;
+		}
+	} else {
+		auth_algo = PDCP_AUTH_ALGO_NULL;
+	}
+
+	static const iv_gen_t

iv_gen_map[PDCP_CIPHER_ALGO_MAX][PDCP_AUTH_ALGO_MAX] = {

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_null_null,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_null_aes_cmac,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_NULL][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_null_zs,

lib/pdcp/pdcp_process.c +2 -0
+
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_aes_ctr_null,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_aes_ctr_aes_cmac,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_AES][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_aes_ctr_zs,

lib/pdcp/pdcp_process.c +2 -0
+
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,
+

	[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_SNOW3G][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c +2 -0
+
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_NULL] =

pdcp_iv_gen_zs_null,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_AES] =

pdcp_iv_gen_zs_aes_cmac,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_SNOW3G] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c +1 -0
+		[PDCP_CIPHER_ALGO_ZUC][PDCP_AUTH_ALGO_ZUC] =

pdcp_iv_gen_zs_zs,

lib/pdcp/pdcp_process.c +7 -0
+	};
+
+	en_priv->iv_gen = iv_gen_map[ciph_algo][auth_algo];
+
+	return 0;
+}
+
 static inline void
 cop_prepare(const struct entity_priv *en_priv, struct rte_mbuf *mb, struct

rte_crypto_op *cop,

lib/pdcp/pdcp_process.c +4 -0
 	    uint8_t data_offset, uint32_t count, const bool is_auth)
@@ -909,6 +1189,10 @@ pdcp_process_func_set(struct rte_pdcp_entity
 *entity, const struct rte_pdcp_enti
 
 	en_priv = entity_priv_get(entity);
 
+	ret = pdcp_iv_gen_func_set(entity, conf);
+	if (ret)
+		return ret;
+
 	ret = pdcp_entity_priv_populate(en_priv, conf);
 	if (ret)

return ret;
--
2.25.1

#43 lore raw

PATCH v2 9/22 app/test: add lib pdcp tests

In reply to Anoob Joseph

Add tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.

---
 app/test/meson.build      |   1 +
 app/test/test_cryptodev.h |   3 +
 app/test/test_pdcp.c      | 729 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 733 insertions(+)
 create mode 100644 app/test/test_pdcp.c
app/test/meson.build +1 -0
index 52d9088578..0f658aa2ab 100644
@@ -96,6 +96,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +3 -0
index abd795f54a..89057dba22 100644
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+
 #define HEX_DUMP 0
 
 #define FALSE                           0
app/test/test_pdcp.c new file +729 -0

729 lines not on this page · raw message

Signature · 1 line
2.25.1
#44 lore raw

RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Quoted 17 lines
app/test/meson.build +1 -0
index 52d9088578..0f658aa2ab 100644
@@ -96,6 +96,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +0 -0
index abd795f54a..89057dba22 100644

app/test/test_cryptodev.h line 9

Quoted 6 lines
app/test/test_cryptodev.h +3 -0
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+

Can we remove these includes from here and add in test_pdcp.c directly?

Quoted 37 lines
app/test/test_cryptodev.h +8 -0
+	if (conf->is_integrity_protected) {
+		if (conf->entity.pdcp_xfrm.pkt_dir ==
 RTE_SECURITY_PDCP_UPLINK) {
+			conf->entity.crypto_xfrm = &conf->a_xfrm;
+
+			a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
+			a_xfrm.next = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +5 -0
+			c_xfrm.next = NULL;
+		} else {
+			conf->entity.crypto_xfrm = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+			c_xfrm.next = &conf->a_xfrm;
+
+			a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+			a_xfrm.next = NULL;
+		}
+	} else {
+		conf->entity.crypto_xfrm = &conf->c_xfrm;
+		c_xfrm.next = NULL;
+
+		if (conf->entity.pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

app/test/test_cryptodev.h +1 -0
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +2 -0
+		else
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +5 -0
+	}
+	/* Update xforms to match PDCP requirements */
+
+	if ((c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3 ||

app/test/test_cryptodev.h

Quoted 10 lines
app/test/test_cryptodev.h +10 -0
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2)))
+		c_xfrm.cipher.iv.length = 16;
+	else
+		c_xfrm.cipher.iv.length = 0;
+
+	if (conf->is_integrity_protected) {
+		if (a_xfrm.auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm.auth.digest_length = 0;
+		else
+			a_xfrm.auth.digest_length = 4;

This if-else is not needed. If is_integrity_protected, digest_length should always be 4. Also define a macro for MAC-I len. It is being used at multiple places. Similarly for IV length macro can be defined.

Quoted 23 lines
app/test/test_cryptodev.h +12 -0
+
+		if ((a_xfrm.auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm.auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2))
+			a_xfrm.auth.iv.length = 16;
+		else
+			a_xfrm.auth.iv.length = 0;
+	}
+
+	conf->c_xfrm = c_xfrm;
+	conf->a_xfrm = a_xfrm;
+
+	conf->entity.dev_id = (uint8_t)cryptodev_id_get(conf-
Quoted 1 line

is_integrity_protected,

app/test/test_cryptodev.h +3 -0
+			&conf->c_xfrm, &conf->a_xfrm);
+
+	if (pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_CONTROL ||

app/test/test_cryptodev.h +1 -0
+	    pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_DATA) {

app/test/test_cryptodev.h +3 -0
+		data = pdcp_test_data_in[index];
+		hfn = pdcp_test_hfn[index] << pdcp_test_data_sn_size[index];
+		sn = pdcp_sn_from_raw_get(data,

pdcp_test_data_sn_size[index]);

app/test/test_cryptodev.h

Quoted 2 lines
app/test/test_cryptodev.h +2 -0
+		count = hfn | sn;
+	}

The above logic can go inside lib PDCP as well.
This is specific to PDCP and not user dependent.
You can reuse the pdcp_xfrm.hfn as well.

#45 lore raw

RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Hi Akhil,

Please see inline.

Thanks,
Anoob

Quoted 33 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 1:34 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Quoted 20 lines
app/test/meson.build index renamed from app/test/meson.build +0 -0

52d9088578..0f658aa2ab 100644

app/test/meson.build +1 -0
@@ -96,6 +96,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +0 -0
index abd795f54a..89057dba22 100644
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
Quoted 5 lines

app/test/test_cryptodev.h line 9

Quoted 3 lines
app/test/test_cryptodev.h +3 -0
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+

Can we remove these includes from here and add in test_pdcp.c directly?

[Anoob] Why? 'test_cryptodev.h' already has many references to rte_cryptodev symbols. Not including the dependencies is not correct.

Quoted 45 lines

app/test/test_cryptodev.h

Quoted 8 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (conf->entity.pdcp_xfrm.pkt_dir ==
 RTE_SECURITY_PDCP_UPLINK) {
+			conf->entity.crypto_xfrm = &conf->a_xfrm;
+
+			a_xfrm.auth.op =

RTE_CRYPTO_AUTH_OP_GENERATE;

Quoted 36 lines
app/test/test_cryptodev.h +3 -0
+			a_xfrm.next = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +5 -0
+			c_xfrm.next = NULL;
+		} else {
+			conf->entity.crypto_xfrm = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+			c_xfrm.next = &conf->a_xfrm;
+
+			a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+			a_xfrm.next = NULL;
+		}
+	} else {
+		conf->entity.crypto_xfrm = &conf->c_xfrm;
+		c_xfrm.next = NULL;
+
+		if (conf->entity.pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

app/test/test_cryptodev.h +1 -0
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +2 -0
+		else
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+	}
+	/* Update xforms to match PDCP requirements */
+
+	if ((c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3 ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2)))
+		c_xfrm.cipher.iv.length = 16;
+	else
+		c_xfrm.cipher.iv.length = 0;
+
Quoted 8 lines

app/test/test_cryptodev.h

Quoted 5 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (a_xfrm.auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm.auth.digest_length = 0;
+		else
+			a_xfrm.auth.digest_length = 4;

This if-else is not needed. If is_integrity_protected, digest_length should always be 4.

[Anoob] I had explained this in v1 patch set. Will try again.

In PDCP, with AUTH_NULL it is expected to have 4 bytes of zeroized digest.

With AUTH_NULL, it is lib PDCP which would add zeroized digest. No PMD currently supported in DPDK supports non-zero digest with AUTH-NULL. Also, it is not specified what is the digest added in case of AUTH-NULL.

Quoted 3 lines

Also define a macro for MAC-I len. It is being used at multiple places. Similarly for IV length macro can be defined.

[Anoob] Agreed. You want me to introduce RTE_PDCP_MAC_I_LEN or something local would do?

Quoted 23 lines

app/test/test_cryptodev.h

Quoted 3 lines
app/test/test_cryptodev.h +3 -0
+
+		if ((a_xfrm.auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm.auth.algo ==

RTE_CRYPTO_AUTH_SNOW3G_UIA2))

Quoted 16 lines
app/test/test_cryptodev.h +9 -0
+			a_xfrm.auth.iv.length = 16;
+		else
+			a_xfrm.auth.iv.length = 0;
+	}
+
+	conf->c_xfrm = c_xfrm;
+	conf->a_xfrm = a_xfrm;
+
+	conf->entity.dev_id = (uint8_t)cryptodev_id_get(conf-
Quoted 1 line

is_integrity_protected,

app/test/test_cryptodev.h +3 -0
+			&conf->c_xfrm, &conf->a_xfrm);
+
+	if (pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_CONTROL ||

app/test/test_cryptodev.h +1 -0
+	    pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_DATA) {

app/test/test_cryptodev.h

Quoted 2 lines
app/test/test_cryptodev.h +2 -0
+		data = pdcp_test_data_in[index];
+		hfn = pdcp_test_hfn[index] <<

pdcp_test_data_sn_size[index];

Quoted 9 lines

app/test/test_cryptodev.h

Quoted 4 lines
app/test/test_cryptodev.h +1 -0
+		sn = pdcp_sn_from_raw_get(data,

pdcp_test_data_sn_size[index]);

app/test/test_cryptodev.h +2 -0
+		count = hfn | sn;
+	}

The above logic can go inside lib PDCP as well.
This is specific to PDCP and not user dependent.
You can reuse the pdcp_xfrm.hfn as well.

[Anoob] Sorry, what exactly can go into lib PDCP? This snippet is reading SN used in a test vector and constructs the count based on SN & HFN value from vector.

#46 lore raw

RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
app/test/meson.build index renamed from app/test/meson.build +0 -0

52d9088578..0f658aa2ab 100644

app/test/meson.build +1 -0
@@ -96,6 +96,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +0 -0
index abd795f54a..89057dba22 100644
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
Quoted 9 lines
Quoted 5 lines

app/test/test_cryptodev.h line 9

Quoted 3 lines
app/test/test_cryptodev.h +3 -0
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+

Can we remove these includes from here and add in test_pdcp.c directly?

[Anoob] Why? 'test_cryptodev.h' already has many references to rte_cryptodev symbols. Not including the dependencies is not correct.

In that case, it can be a separate patch. But not in this patch.

Quoted 54 lines
Quoted 45 lines

app/test/test_cryptodev.h

Quoted 8 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (conf->entity.pdcp_xfrm.pkt_dir ==
 RTE_SECURITY_PDCP_UPLINK) {
+			conf->entity.crypto_xfrm = &conf->a_xfrm;
+
+			a_xfrm.auth.op =

RTE_CRYPTO_AUTH_OP_GENERATE;

Quoted 36 lines
app/test/test_cryptodev.h +3 -0
+			a_xfrm.next = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +5 -0
+			c_xfrm.next = NULL;
+		} else {
+			conf->entity.crypto_xfrm = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+			c_xfrm.next = &conf->a_xfrm;
+
+			a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+			a_xfrm.next = NULL;
+		}
+	} else {
+		conf->entity.crypto_xfrm = &conf->c_xfrm;
+		c_xfrm.next = NULL;
+
+		if (conf->entity.pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

app/test/test_cryptodev.h +1 -0
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +2 -0
+		else
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+	}
+	/* Update xforms to match PDCP requirements */
+
+	if ((c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3 ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2)))
+		c_xfrm.cipher.iv.length = 16;
+	else
+		c_xfrm.cipher.iv.length = 0;
+
Quoted 8 lines

app/test/test_cryptodev.h

Quoted 5 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (a_xfrm.auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm.auth.digest_length = 0;
+		else
+			a_xfrm.auth.digest_length = 4;

This if-else is not needed. If is_integrity_protected, digest_length should always be 4.

Quoted 7 lines

[Anoob] I had explained this in v1 patch set. Will try again.

In PDCP, with AUTH_NULL it is expected to have 4 bytes of zeroized digest.

With AUTH_NULL, it is lib PDCP which would add zeroized digest. No PMD currently supported in DPDK supports non-zero digest with AUTH-NULL. Also, it is not specified what is the digest added in case of AUTH-NULL.

In auth_xform, digest_length is the expected length of digest coming out of crypto device. Now if the device is expected to support PDCP, and we are reusing the crypto APIs, We can specify the digest length required for NULL auth.
The PMDs capability can be updated accordingly.
You can add a comment in the rte_crypto_auth_xform specifically for NULL auth for PDCP case.

The reason, I am insisting on this is, for the user, while configuring auth_xform, it is setting digest length as 0 and when the packet is received the packet length is increased by digest. This will create confusion.
And it will also help in identifying the case of no integrity and null integrity.

Quoted 7 lines
Quoted 4 lines

Also define a macro for MAC-I len. It is being used at multiple places. Similarly for IV length macro can be defined.

[Anoob] Agreed. You want me to introduce RTE_PDCP_MAC_I_LEN or something local would do?

I am ok either way. Having defined in library would be better, to be used in lib and PMD as well.

Quoted 34 lines
Quoted 24 lines

app/test/test_cryptodev.h

Quoted 4 lines
app/test/test_cryptodev.h +3 -0
+
+		if ((a_xfrm.auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm.auth.algo ==

RTE_CRYPTO_AUTH_SNOW3G_UIA2))

Quoted 16 lines
app/test/test_cryptodev.h +9 -0
+			a_xfrm.auth.iv.length = 16;
+		else
+			a_xfrm.auth.iv.length = 0;
+	}
+
+	conf->c_xfrm = c_xfrm;
+	conf->a_xfrm = a_xfrm;
+
+	conf->entity.dev_id = (uint8_t)cryptodev_id_get(conf-
Quoted 1 line

is_integrity_protected,

app/test/test_cryptodev.h +3 -0
+			&conf->c_xfrm, &conf->a_xfrm);
+
+	if (pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_CONTROL ||

app/test/test_cryptodev.h +1 -0
+	    pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_DATA) {

app/test/test_cryptodev.h

Quoted 2 lines
app/test/test_cryptodev.h +2 -0
+		data = pdcp_test_data_in[index];
+		hfn = pdcp_test_hfn[index] <<

pdcp_test_data_sn_size[index];

Quoted 9 lines

app/test/test_cryptodev.h

Quoted 4 lines
app/test/test_cryptodev.h +1 -0
+		sn = pdcp_sn_from_raw_get(data,

pdcp_test_data_sn_size[index]);

app/test/test_cryptodev.h +2 -0
+		count = hfn | sn;
+	}

The above logic can go inside lib PDCP as well.
This is specific to PDCP and not user dependent.
You can reuse the pdcp_xfrm.hfn as well.

Quoted 2 lines

[Anoob] Sorry, what exactly can go into lib PDCP? This snippet is reading SN used in a test vector and constructs the count based on SN & HFN value from vector.

This count value is being used to establish entity. I am saying, instead of taking Count, take sn as input and in the libpdcp combine pdcp_xfrm.hfn and sn as needed to create count and store in entity_priv.
Just wanted to reduce the application headache to make bitshifting and ORing to SN.

#47 lore raw

RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Hi Akhil,

Please see inline.

Thanks,
Anoob

Quoted 39 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 5:36 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 09/22] app/test: add lib pdcp tests

Quoted 26 lines
Quoted 25 lines
Quoted 17 lines
app/test/meson.build index renamed from app/test/meson.build +0 -0

52d9088578..0f658aa2ab 100644

app/test/meson.build +1 -0
@@ -96,6 +96,7 @@ test_sources = files(
         'test_meter.c',
         'test_mcslock.c',
         'test_mp_secondary.c',
+        'test_pdcp.c',
         'test_per_lcore.c',
         'test_pflock.c',
         'test_pmd_perf.c',
app/test/test_cryptodev.h +0 -0
index abd795f54a..89057dba22 100644

app/test/test_cryptodev.h line 9

Quoted 6 lines
app/test/test_cryptodev.h +3 -0
@@ -4,6 +4,9 @@
 #ifndef TEST_CRYPTODEV_H_
 #define TEST_CRYPTODEV_H_
 
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+

Can we remove these includes from here and add in test_pdcp.c directly?

Quoted 4 lines
Quoted 3 lines

[Anoob] Why? 'test_cryptodev.h' already has many references to rte_cryptodev symbols. Not including the dependencies is not correct.

In that case, it can be a separate patch. But not in this patch.

[Anoob] Is your suggestion to push this specific change as a separate patch? I can do that if you suggest so.

Quoted 57 lines
Quoted 57 lines
Quoted 46 lines

app/test/test_cryptodev.h

Quoted 9 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (conf->entity.pdcp_xfrm.pkt_dir ==
 RTE_SECURITY_PDCP_UPLINK) {
+			conf->entity.crypto_xfrm = &conf->a_xfrm;
+
+			a_xfrm.auth.op =

RTE_CRYPTO_AUTH_OP_GENERATE;

Quoted 36 lines
app/test/test_cryptodev.h +3 -0
+			a_xfrm.next = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +5 -0
+			c_xfrm.next = NULL;
+		} else {
+			conf->entity.crypto_xfrm = &conf->c_xfrm;
+
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+			c_xfrm.next = &conf->a_xfrm;
+
+			a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+			a_xfrm.next = NULL;
+		}
+	} else {
+		conf->entity.crypto_xfrm = &conf->c_xfrm;
+		c_xfrm.next = NULL;
+
+		if (conf->entity.pdcp_xfrm.pkt_dir ==

RTE_SECURITY_PDCP_UPLINK)

app/test/test_cryptodev.h +1 -0
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_ENCRYPT;

app/test/test_cryptodev.h +2 -0
+		else
+			c_xfrm.cipher.op =

RTE_CRYPTO_CIPHER_OP_DECRYPT;

app/test/test_cryptodev.h +10 -0
+	}
+	/* Update xforms to match PDCP requirements */
+
+	if ((c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_AES_CTR) ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_ZUC_EEA3 ||
+	    (c_xfrm.cipher.algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2)))
+		c_xfrm.cipher.iv.length = 16;
+	else
+		c_xfrm.cipher.iv.length = 0;
+
Quoted 8 lines

app/test/test_cryptodev.h

Quoted 5 lines
app/test/test_cryptodev.h +5 -0
+	if (conf->is_integrity_protected) {
+		if (a_xfrm.auth.algo == RTE_CRYPTO_AUTH_NULL)
+			a_xfrm.auth.digest_length = 0;
+		else
+			a_xfrm.auth.digest_length = 4;

This if-else is not needed. If is_integrity_protected, digest_length should always be 4.

[Anoob] I had explained this in v1 patch set. Will try again.

Quoted 8 lines
Quoted 5 lines

In PDCP, with AUTH_NULL it is expected to have 4 bytes of zeroized digest.

With AUTH_NULL, it is lib PDCP which would add zeroized digest. No PMD currently supported in DPDK supports non-zero digest with AUTH-NULL. Also, it is not specified what is the digest added in case of AUTH-NULL.

In auth_xform, digest_length is the expected length of digest coming out of crypto device.

[Anoob] Yes. But the packet append is the duty lib PDCP. Crypto PMD is expected to just write the digest at a specific location.

Quoted 3 lines

Now if the device is expected to support PDCP, and we are reusing the crypto APIs, We can specify the digest length required for NULL auth. The PMDs capability can be updated accordingly.

[Anoob] Again, none of the current PMDs do a zeroized digest with NULL auth. And it is not a requirement as well. Here, we are doing PDCP offload and the crypto_xforms provided here are for specific crypto transformations.

Quoted 7 lines

You can add a comment in the rte_crypto_auth_xform specifically for NULL auth for PDCP case.

The reason, I am insisting on this is, for the user, while configuring auth_xform, it is setting digest length as 0 and when the packet is received the packet length is increased by digest. This will create confusion. And it will also help in identifying the case of no integrity and null integrity.

[Anoob] When working with protocol, the packet would change both at header and trailer. It is just that for PDCP, the trailer is only digest. For IPsec, the change is more than digest.

Quoted 47 lines
Quoted 8 lines
Quoted 5 lines

Also define a macro for MAC-I len. It is being used at multiple places. Similarly for IV length macro can be defined.

[Anoob] Agreed. You want me to introduce RTE_PDCP_MAC_I_LEN or something local would do?

I am ok either way. Having defined in library would be better, to be used in lib and PMD as well.

Quoted 34 lines
Quoted 24 lines

app/test/test_cryptodev.h

Quoted 4 lines
app/test/test_cryptodev.h +3 -0
+
+		if ((a_xfrm.auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
+		    (a_xfrm.auth.algo ==

RTE_CRYPTO_AUTH_SNOW3G_UIA2))

Quoted 16 lines
app/test/test_cryptodev.h +9 -0
+			a_xfrm.auth.iv.length = 16;
+		else
+			a_xfrm.auth.iv.length = 0;
+	}
+
+	conf->c_xfrm = c_xfrm;
+	conf->a_xfrm = a_xfrm;
+
+	conf->entity.dev_id = (uint8_t)cryptodev_id_get(conf-
Quoted 1 line

is_integrity_protected,

app/test/test_cryptodev.h +3 -0
+			&conf->c_xfrm, &conf->a_xfrm);
+
+	if (pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_CONTROL ||

app/test/test_cryptodev.h +1 -0
+	    pdcp_test_params[index].domain ==

RTE_SECURITY_PDCP_MODE_DATA) {

app/test/test_cryptodev.h

Quoted 2 lines
app/test/test_cryptodev.h +2 -0
+		data = pdcp_test_data_in[index];
+		hfn = pdcp_test_hfn[index] <<

pdcp_test_data_sn_size[index];

Quoted 9 lines

app/test/test_cryptodev.h

Quoted 4 lines
app/test/test_cryptodev.h +1 -0
+		sn = pdcp_sn_from_raw_get(data,

pdcp_test_data_sn_size[index]);

app/test/test_cryptodev.h +2 -0
+		count = hfn | sn;
+	}

The above logic can go inside lib PDCP as well.
This is specific to PDCP and not user dependent.
You can reuse the pdcp_xfrm.hfn as well.

Quoted 2 lines

[Anoob] Sorry, what exactly can go into lib PDCP? This snippet is reading SN used in a test vector and constructs the count based on SN &

Quoted 7 lines

HFN value from vector.

This count value is being used to establish entity. I am saying, instead of taking Count, take sn as input and in the libpdcp combine pdcp_xfrm.hfn and sn as needed to create count and store in entity_priv.
Just wanted to reduce the application headache to make bitshifting and ORing to SN.

[Anoob] I was not able to identify a use case where having two 32 bit values for HFN & SN would make sense. But then, it would align better with current rte_security specification. Will make the change in next version.

#48 lore raw

PATCH v2 10/22 test/pdcp: pdcp HFN tests in combined mode

In reply to Anoob Joseph

From: Volodymyr Fialko <[email protected]>

Add tests to verify HFN/SN behaviour.

---
 app/test/test_pdcp.c | 302 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 299 insertions(+), 3 deletions(-)
app/test/test_pdcp.c +299 -3
index cb88817004..fc49947ba2 100644
@@ -15,6 +15,9 @@
 #define CDEV_INVALID_ID UINT8_MAX
 #define NB_TESTS RTE_DIM(pdcp_test_params)
 
+/* According to formula(7.2.a Window_Size) */
+#define PDCP_WINDOW_SIZE(sn_size) (1 << (sn_size - 1))
+
 struct pdcp_testsuite_params {
 	struct rte_mempool *mbuf_pool;
 	struct rte_mempool *cop_pool;
@@ -35,12 +38,69 @@ struct pdcp_test_conf {
 	uint32_t output_len;
 };
 
+static int create_test_conf_from_index(const int index, struct pdcp_test_conf *conf);
+
+typedef int (*test_with_conf_t)(struct pdcp_test_conf *conf);
+
+static int
+run_test_foreach_known_vec(test_with_conf_t test, bool stop_on_first_pass)
+{
+	struct pdcp_test_conf test_conf;
+	bool all_tests_skipped = true;
+	uint32_t i;
+	int ret;
+
+	for (i = 0; i < NB_TESTS; i++) {
+		create_test_conf_from_index(i, &test_conf);
+		ret = test(&test_conf);
+
+		if (ret == TEST_FAILED) {
+			printf("[%03i] - %s - failed\n", i, pdcp_test_params[i].name);
+			return TEST_FAILED;
+		}
+
+		if ((ret == TEST_SKIPPED) || (ret == -ENOTSUP))
+			continue;
+
+		if (stop_on_first_pass)
+			return TEST_SUCCESS;
+
+		all_tests_skipped = false;
+	}
+
+	if (all_tests_skipped)
+		return TEST_SKIPPED;
+
+	return TEST_SUCCESS;
+}
+
+static int
+run_test_with_all_known_vec(const void *args)
+{
+	test_with_conf_t test = args;
+
+	return run_test_foreach_known_vec(test, false);
+}
+
 static inline int
 pdcp_hdr_size_get(enum rte_security_pdcp_sn_size sn_size)
 {
 	return RTE_ALIGN_MUL_CEIL(sn_size, 8) / 8;
 }
 
+static int
+pktmbuf_read_into(const struct rte_mbuf *m, void *buf, size_t buf_len)
+{
+	if (m->pkt_len > buf_len)
+		return -ENOMEM;
+
+	const void *read = rte_pktmbuf_read(m, 0, m->pkt_len, buf);
+	if (read != NULL && read != buf)
+		memcpy(buf, read, m->pkt_len);
+
+	return 0;
+}
+
 static int
 cryptodev_init(int dev_id)
 {
@@ -325,6 +385,21 @@ pdcp_sn_from_raw_get(const void *data, enum rte_security_pdcp_sn_size size)
 	return sn;
 }
 
+static void
+pdcp_sn_to_raw_set(void *data, uint32_t sn, int size)
+{
+	if (size == RTE_SECURITY_PDCP_SN_SIZE_12) {
+		struct rte_pdcp_up_data_pdu_sn_12_hdr *pdu_hdr = data;
+		pdu_hdr->sn_11_8 = ((sn & 0xf00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+	} else if (size == RTE_SECURITY_PDCP_SN_SIZE_18) {
+		struct rte_pdcp_up_data_pdu_sn_18_hdr *pdu_hdr = data;
+		pdu_hdr->sn_17_16 = ((sn & 0x30000) >> 16);
+		pdu_hdr->sn_15_8 = ((sn & 0xff00) >> 8);
+		pdu_hdr->sn_7_0 = (sn & 0xff);
+	}
+}
+
 static int
 create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 {
@@ -645,9 +720,17 @@ test_attempt_single(struct pdcp_test_conf *t_conf)
 		goto mbuf_free;
 	}
 
-	ret = pdcp_known_vec_verify(mbuf, t_conf->output, t_conf->output_len);
-	if (ret)
-		goto mbuf_free;
+	/* If expected output provided - verify, else - store for future use */
+	if (t_conf->output_len) {
+		ret = pdcp_known_vec_verify(mbuf, t_conf->output, t_conf->output_len);
+		if (ret)
+			goto mbuf_free;
+	} else {
+		ret = pktmbuf_read_into(mbuf, t_conf->output, RTE_PDCP_CTRL_PDU_SIZE_MAX);
+		if (ret)
+			goto mbuf_free;
+		t_conf->output_len = mbuf->pkt_len;
+	}
 
 	ret = rte_pdcp_entity_suspend(pdcp_entity, out_mb);
 	if (ret) {
@@ -664,6 +747,193 @@ test_attempt_single(struct pdcp_test_conf *t_conf)
 	return ret;
 }
 
+static void
+uplink_to_downlink_convert(const struct pdcp_test_conf *ul_cfg,
+			   struct pdcp_test_conf *dl_cfg)
+{
+	assert(ul_cfg->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK);
+
+	memcpy(dl_cfg, ul_cfg, sizeof(*dl_cfg));
+	dl_cfg->entity.pdcp_xfrm.pkt_dir = RTE_SECURITY_PDCP_DOWNLINK;
+	dl_cfg->entity.reverse_iv_direction = false;
+
+	if (dl_cfg->is_integrity_protected) {
+		dl_cfg->entity.crypto_xfrm = &dl_cfg->c_xfrm;
+
+		dl_cfg->c_xfrm.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+		dl_cfg->c_xfrm.next = &dl_cfg->a_xfrm;
+
+		dl_cfg->a_xfrm.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+		dl_cfg->a_xfrm.next = NULL;
+	} else {
+		dl_cfg->entity.crypto_xfrm = &dl_cfg->c_xfrm;
+		dl_cfg->c_xfrm.next = NULL;
+		dl_cfg->c_xfrm.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+	}
+
+	dl_cfg->entity.dev_id = (uint8_t)cryptodev_id_get(dl_cfg->is_integrity_protected,
+			&dl_cfg->c_xfrm, &dl_cfg->a_xfrm);
+
+	memcpy(dl_cfg->input, ul_cfg->output, ul_cfg->output_len);
+	dl_cfg->input_len = ul_cfg->output_len;
+
+	memcpy(dl_cfg->output, ul_cfg->input, ul_cfg->input_len);
+	dl_cfg->output_len = ul_cfg->input_len;
+}
+
+/*
+ * According to ETSI TS 138 323 V17.1.0, Section 5.2.2.1,
+ * SN could be divided into following ranges,
+ * relatively to current value of RX_DELIV state:
+ * +-------------+-------------+-------------+-------------+
+ * |  -Outside   |  -Window    |   +Window   |  +Outside   |
+ * |   (valid)   |  (Invalid)  |   (Valid)   |  (Invalid)  |
+ * +-------------+-------------^-------------+-------------+
+ *                             |
+ *                             v
+ *                        SN(RX_DELIV)
+ */
+enum sn_range_type {
+	SN_RANGE_MINUS_OUTSIDE,
+	SN_RANGE_MINUS_WINDOW,
+	SN_RANGE_PLUS_WINDOW,
+	SN_RANGE_PLUS_OUTSIDE,
+};
+
+#define PDCP_SET_COUNT(hfn, sn, size) ((hfn << size) | (sn & ((1 << size) - 1)))
+
+/*
+ * Take uplink test case as base, modify RX_DELIV in state and SN in input
+ */
+static int
+test_sn_range_type(enum sn_range_type type, struct pdcp_test_conf *conf)
+{
+	uint32_t rx_deliv_hfn, rx_deliv_sn, rx_deliv, new_hfn, new_sn;
+	const int domain = conf->entity.pdcp_xfrm.domain;
+	struct pdcp_test_conf dl_conf;
+	int ret, expected_ret;
+
+	if (conf->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		return TEST_SKIPPED;
+
+	if (domain != RTE_SECURITY_PDCP_MODE_CONTROL && domain != RTE_SECURITY_PDCP_MODE_DATA)
+		return TEST_SKIPPED;
+
+	const uint32_t sn_size = conf->entity.pdcp_xfrm.sn_size;
+	const uint32_t window_size = PDCP_WINDOW_SIZE(sn_size);
+	/* Max value of SN that could fit in `sn_size` bits */
+	const uint32_t max_sn = (1 << sn_size) - 1;
+	const uint32_t shift = (max_sn - window_size) / 2;
+	/* Could be any number up to `shift` value */
+	const uint32_t default_sn = RTE_MIN(2u, shift);
+
+	/* Initialize HFN as non zero value, to be able check values before */
+	rx_deliv_hfn = 0xa;
+
+	switch (type) {
+	case SN_RANGE_PLUS_WINDOW:
+		/* Within window size, HFN stay same */
+		new_hfn = rx_deliv_hfn;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn + 1;
+		expected_ret = TEST_SUCCESS;
+		break;
+	case SN_RANGE_MINUS_WINDOW:
+		/* Within window size, HFN stay same */
+		new_hfn = rx_deliv_hfn;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn - 1;
+		expected_ret = TEST_FAILED;
+		break;
+	case SN_RANGE_PLUS_OUTSIDE:
+		/* RCVD_SN >= SN(RX_DELIV) + Window_Size */
+		new_hfn = rx_deliv_hfn - 1;
+		rx_deliv_sn = default_sn;
+		new_sn = rx_deliv_sn + window_size;
+		expected_ret = TEST_FAILED;
+		break;
+	case SN_RANGE_MINUS_OUTSIDE:
+		/* RCVD_SN < SN(RX_DELIV) - Window_Size */
+		new_hfn = rx_deliv_hfn + 1;
+		rx_deliv_sn = window_size + default_sn;
+		new_sn = rx_deliv_sn - window_size - 1;
+		expected_ret = TEST_SUCCESS;
+		break;
+	default:
+		return TEST_FAILED;
+	}
+
+	rx_deliv = PDCP_SET_COUNT(rx_deliv_hfn, rx_deliv_sn, sn_size);
+
+	/* Configure Uplink to generate expected, encrypted packet */
+	pdcp_sn_to_raw_set(conf->input, new_sn, conf->entity.pdcp_xfrm.sn_size);
+	conf->entity.reverse_iv_direction = true;
+	conf->entity.count = PDCP_SET_COUNT(new_hfn, new_sn, sn_size);
+	conf->output_len = 0;
+	ret = test_attempt_single(conf);
+	if (ret != TEST_SUCCESS)
+		return ret;
+
+	/* Flip configuration to downlink */
+	uplink_to_downlink_convert(conf, &dl_conf);
+
+	/* Modify the rx_deliv to verify the expected behaviour */
+	dl_conf.entity.count = rx_deliv;
+	ret = test_attempt_single(&dl_conf);
+	if ((ret == TEST_SKIPPED) || (ret == -ENOTSUP))
+		return ret;
+
+	TEST_ASSERT_EQUAL(ret, expected_ret, "Unexpected result");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_sn_plus_window(struct pdcp_test_conf *t_conf)
+{
+	return test_sn_range_type(SN_RANGE_PLUS_WINDOW, t_conf);
+}
+
+static int
+test_sn_minus_window(struct pdcp_test_conf *t_conf)
+{
+	return test_sn_range_type(SN_RANGE_MINUS_WINDOW, t_conf);
+}
+
+static int
+test_sn_plus_outside(struct pdcp_test_conf *t_conf)
+{
+	return test_sn_range_type(SN_RANGE_PLUS_OUTSIDE, t_conf);
+}
+
+static int
+test_sn_minus_outside(struct pdcp_test_conf *t_conf)
+{
+	return test_sn_range_type(SN_RANGE_MINUS_OUTSIDE, t_conf);
+}
+
+static int
+test_combined(struct pdcp_test_conf *ul_conf)
+{
+	struct pdcp_test_conf dl_conf;
+	int ret;
+
+	if (ul_conf->entity.pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK)
+		return TEST_SKIPPED;
+
+	ul_conf->entity.reverse_iv_direction = true;
+	ul_conf->output_len = 0;
+
+	ret = test_attempt_single(ul_conf);
+	if (ret != TEST_SUCCESS)
+		return ret;
+
+	uplink_to_downlink_convert(ul_conf, &dl_conf);
+	ret = test_attempt_single(&dl_conf);
+
+	return ret;
+}
+
 static int
 run_test_for_one_known_vec(const void *arg)
 {
@@ -674,8 +944,34 @@ run_test_for_one_known_vec(const void *arg)
 	return test_attempt_single(&test_conf);
 }
 
+static struct unit_test_suite combined_mode_cases  = {
+	.suite_name = "PDCP combined mode",
+	.unit_test_cases = {
+		TEST_CASE_NAMED_WITH_DATA("combined mode", ut_setup_pdcp, ut_teardown_pdcp,
+			run_test_with_all_known_vec, test_combined),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static struct unit_test_suite hfn_sn_test_cases  = {
+	.suite_name = "PDCP HFN/SN",
+	.unit_test_cases = {
+		TEST_CASE_NAMED_WITH_DATA("SN plus window", ut_setup_pdcp, ut_teardown_pdcp,
+			run_test_with_all_known_vec, test_sn_plus_window),
+		TEST_CASE_NAMED_WITH_DATA("SN minus window", ut_setup_pdcp, ut_teardown_pdcp,
+			run_test_with_all_known_vec, test_sn_minus_window),
+		TEST_CASE_NAMED_WITH_DATA("SN plus outside", ut_setup_pdcp, ut_teardown_pdcp,
+			run_test_with_all_known_vec, test_sn_plus_outside),
+		TEST_CASE_NAMED_WITH_DATA("SN minus outside", ut_setup_pdcp, ut_teardown_pdcp,
+			run_test_with_all_known_vec, test_sn_minus_outside),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
 struct unit_test_suite *test_suites[] = {
 	NULL, /* Place holder for known_vector_cases */
+	&combined_mode_cases,
+	&hfn_sn_test_cases,
 	NULL /* End of suites list */
 };
 
Signature · 1 line
2.25.1
#49 lore raw

PATCH v2 11/22 doc: add PDCP library guide

In reply to Anoob Joseph

Add guide for PDCP library.

---
 .../img/pdcp_functional_overview.svg          |   1 +
 doc/guides/prog_guide/index.rst               |   1 +
 doc/guides/prog_guide/pdcp_lib.rst            | 246 ++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg
 create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
doc/guides/prog_guide/img/pdcp_functional_overview.svg new file +1 -0
new file mode 100644
index 0000000000..287daafc21
@@ -0,0 +1 @@
+<svg width="1280" height="720" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden"><defs><clipPath id="clip0"><rect x="0" y="0" width="1280" height="720"/></clipPath></defs><g clip-path="url(#clip0)"><rect x="0" y="0" width="1280" height="720" fill="#FFFFFF"/><rect x="202" y="100" width="369" height="457" fill="#A5A5A5" fill-opacity="0.501961"/><rect x="640" y="100" width="369" height="457" fill="#A5A5A5" fill-opacity="0.501961"/><path d="M605.5 73.5001 605.5 590.633" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M380.5 634 803.25 634 803.25 585.907 790.5 585.907 816 557.5 841.5 585.907 828.75 585.907 828.75 659.5 380.5 659.5Z" stroke="#787878" stroke-width="1.33333" stroke-miterlimit="8" fill="#A5A5A5" fill-rule="evenodd"/><rect x="362.5" y="557.5" width="28" height="102" stroke="#787878" stroke-width="1.33333" stroke-miterlimit="8" fill="#A5A5A5"/><rect x="412.5" y="671.5" width="370" height="32" stroke="#000000" stroke-linejoin="round" stroke-miterlimit="10" fill="none"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(492.364 694)">Radio Interface (<tspan font-size="19" x="137.5" y="0">Uu</tspan><tspan font-size="19" x="161.333" y="0">/PC5)</tspan><tspan font-size="19" x="-282.121" y="-653">UE/NG</tspan><tspan font-size="19" x="-222.955" y="-653">-</tspan><tspan font-size="19" x="-216.788" y="-653">RAN/UE A</tspan><tspan font-size="19" x="375.54" y="-653">NG</tspan>-<tspan font-size="19" x="409.706" y="-653">RAN/UE/UE B</tspan><tspan font-size="14" x="0.896851" y="-647">Transmitting </tspan><tspan font-size="14" x="1.31018" y="-631">PDCP entity</tspan><tspan font-size="14" x="167.401" y="-647">Receiving </tspan><tspan font-size="14" x="160.148" y="-631">PDCP entity</tspan></text><path d="M314.5 71.5001 431.364 71.6549" stroke="#000000" stroke-width="0.666667" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M331.5 71.5001C331.5 65.9772 349.633 61.5001 372 61.5001 394.368 61.5001 412.5 65.9772 412.5 71.5001 412.5 77.0229 394.368 81.5001 372 81.5001 349.633 81.5001 331.5 77.0229 331.5 71.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M353.5 90.5001 363.5 90.5001 363.5 48.5001 383.5 48.5001 383.5 90.5001 393.5 90.5001 373.5 110.5Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M877.364 82.6549 760.5 82.5001" stroke="#000000" stroke-width="0.666667" stroke-miterlimit="8" fill="none" fill-rule="evenodd"/><path d="M860.5 83.5001C860.5 89.0229 842.368 93.5001 820 93.5001 797.633 93.5001 779.5 89.0229 779.5 83.5001 779.5 77.9772 797.633 73.5001 820 73.5001 842.368 73.5001 860.5 77.9772 860.5 83.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><path d="M838.5 64.5 828.5 64.5 828.5 106.5 808.5 106.5 808.5 64.5 798.5 64.5 818.5 44.5001Z" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF" fill-rule="evenodd"/><rect x="244.5" y="128.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(302.494 150)">Transmission buffer:<tspan font-size="19" x="-4.67999" y="23">Sequence</tspan><tspan font-size="19" x="84.32" y="23">numberin</tspan>g</text><rect x="244.5" y="199.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(297.314 222)">Header or uplink data<tspan font-size="19" x="34.08" y="23">Compressio</tspan>n</text><rect x="682.5" y="141.5" width="285" height="55" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(735.782 164)">Header or uplink data<tspan font-size="19" x="24.2466" y="23">Decompressio</tspan>n</text><rect x="244.5" y="482.5" width="285" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(300.314 505)">Routing / Duplication</text><rect x="244.5" y="437.5" width="285" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(309.734 460)">Add PDCP header</text><rect x="244.5" y="383.5" width="189" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(298.62 406)">Ciphering</text><rect x="244.5" y="333.5" width="189" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(261.953 356)">Integrity protection</text><path d="M472.167 267.5 472.167 409.802 470.833 409.802 470.833 267.5ZM475.5 408.468 471.5 416.468 467.5 408.468Z"/><path d="M332.167 267.5 332.167 319.552 330.833 319.552 330.833 267.5ZM335.5 318.218 331.5 326.218 327.5 318.219Z"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(253.644 291)">Packets associated <tspan font-size="19" x="14.0067" y="23">to a PDCP SDU</tspan></text><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="matrix(6.12323e-17 1 -1 6.12323e-17 499.312 299)">Packets not <tspan font-size="19" x="-14" y="23">associated to a </tspan><tspan font-size="19" x="-2.75546e-15" y="45">PDCP SDU</tspan></text><rect x="682.5" y="482.5" width="285" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(728.535 505)">Remove PDCP Header</text><rect x="682.5" y="437.5" width="203" height="32" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(733.729 460)">Deciphering</text><rect x="682.5" y="389.5" width="203" height="33" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(702.159 412)">Integrity Verification</text><rect x="682.5" y="303.5" width="203" height="77" stroke="#000000" stroke-width="1.33333" stroke-miterlimit="8" fill="#FFFFFF"/><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="translate(712.729 325)">Reception buffer:<tspan font-size="19" x="24.6667" y="23">Reordering</tspan><tspan font-size="19" x="-13.1667" y="45">Duplicate discardin</tspan><tspan font-size="19" x="144.167" y="45">g</tspan><tspan font-size="19" x="-10.0989" y="-84">Packets associated </tspan><tspan font-size="19" x="3.90784" y="-61">to a PDCP SDU</tspan></text><text font-family="Arial,Arial_MSFontService,sans-serif" font-weight="400" font-size="19" transform="matrix(6.12323e-17 1 -1 6.12323e-17 960.34 294)">Packets not <tspan font-size="19" x="-14" y="23">associated to a </tspan><tspan font-size="19" x="1" y="45">PDCP SDU</tspan></text><path d="M0.666667-8.2074e-07 0.666763 78.6116-0.66657 78.6116-0.666667 8.2074e-07ZM4.00009 77.2782 0.000104987 85.2782-3.9999 77.2782Z" transform="matrix(1 0 0 -1 779.5 296.778)"/><path d="M0.666667-2.88742e-07 0.666769 235.734-0.666565 235.734-0.666667 2.88742e-07ZM4.0001 234.401 0.000104987 242.401-3.9999 234.401Z" transform="matrix(1 0 0 -1 931.5 453.901)"/></g></svg>
\ No newline at end of file
doc/guides/prog_guide/index.rst +1 -0
index 87333ee84a..6099ff63cd 100644
@@ -77,4 +77,5 @@ Programmer's Guide
     lto
     profile_app
     asan
+    pdcp_lib
     glossary
doc/guides/prog_guide/pdcp_lib.rst new file +246 -0

246 lines not on this page · raw message

Signature · 1 line
2.25.1
#50 lore raw

RE: [PATCH v2 11/22] doc: add PDCP library guide

Quoted 44 lines
doc/guides/prog_guide/pdcp_lib.rst new file +14 -0
new file mode 100644
index 0000000000..abd874f2cc
@@ -0,0 +1,246 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(C) 2023 Marvell.
+
+PDCP Protocol Processing Library
+================================
+
+DPDK provides a library for PDCP protocol processing. The library utilizes
+other DPDK libraries such as cryptodev, reorder, etc., to provide the
+application with a transparent and high performant PDCP protocol processing
+library.
+
+The library abstracts complete PDCP protocol processing conforming to
+``ETSI TS 138 323 V17.1.0 (2022-08)``.
+https://www.etsi.org/deliver/etsi_ts/138300_138399/138323/17.01.00_60/ts_

138323v170100p.pdf

doc/guides/prog_guide/pdcp_lib.rst new file +22 -0
+
+PDCP would involve the following operations,
+
+1. Transfer of user plane data
+2. Transfer of control plane data
+3. Header compression
+4. Uplink data compression
+5. Ciphering and integrity protection
+
+.. _figure_pdcp_functional_overview:
+
+.. figure:: img/pdcp_functional_overview.*
+
+   PDCP functional overview new
+
+PDCP library would abstract the protocol offload features of the cryptodev and
+would provide a uniform interface and consistent API usage to work with
+cryptodev irrespective of the protocol offload features supported.
+
+PDCP entity API
+---------------
+

doc/guides/prog_guide/pdcp_lib.rst line 46

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+PDCP library provides following control path APIs that is used to
+configure various PDCP entities,
+
+1. ``rte_pdcp_entity_establish()``
+2. ``rte_pdcp_entity_suspend()``
+3. ``rte_pdcp_entity_release()``
+
+A PDCP entity would translate to one ``rte_cryptodev_sym_session`` or
+``rte_security_session`` based on the config. The sessions would be created/
+destroyed while corresponding PDCP entity operations are performed.

Please explain the difference between suspend and release here.

Quoted 13 lines
doc/guides/prog_guide/pdcp_lib.rst new file +13 -0
+
+PDCP PDU (Protocol Data Unit)
+-----------------------------
+
+PDCP PDUs can be categorized as,
+
+1. Control PDU
+2. Data PDU
+
+Control PDUs are used for signalling between entities on either end and can be
+one of the following,
+
+1. PDCP status report

doc/guides/prog_guide/pdcp_lib.rst line 69

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+2. ROHC feedback
+3. EHC feedback
+
+Control PDUs are not ciphered or authenticated, and so such packets are not
+submitted to cryptodev for processing.
+
+Data PDUs are regular packets submitted by upper layers for transmission to
+other end. Such packets would need to be ciphered and authenticated based on
+the entity configuration.
+

Please move the PDCP PDU section above PDCP entity API section. So that all APIs are together.

Quoted 174 lines
doc/guides/prog_guide/pdcp_lib.rst new file +18 -0
+PDCP packet processing API for data PDU
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+PDCP processing is split into 2 parts. One before cryptodev processing
+(``rte_pdcp_pkt_pre_process()``) and one after cryptodev 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 belonging to same PDCP entity.
+
+Lib PDCP would allow application to use same API sequence while leveraging
+protocol offload features enabled by ``rte_security`` library. Lib PDCP would
+internally change the handles registered for ``pre_process`` and
+``post_process`` based on features enabled in the entity.
+
+Lib PDCP would create the required sessions on the device provided in entity to
+minimize the application requirements. Also, the crypto_op allocation and free
+would also be done internally by lib PDCP to allow the library to create
+crypto ops as required for the input packets. For example, when control PDUs

are
+received, no cryptodev enqueue-dequeue is expected for the same and lib PDCP

doc/guides/prog_guide/pdcp_lib.rst new file +52 -0
+is expected to handle it differently.
+
+Sample API usage
+----------------
+
+The ``rte_pdcp_entity_conf`` structure is used to pass the configuration
+parameters for entity creation.
+
+.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h
+   :language: c
+   :start-after: Structure rte_pdcp_entity_conf 8<
+   :end-before: >8 End of structure rte_pdcp_entity_conf.
+
+.. code-block:: c
+
+	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
+	struct rte_crypto_op *cop[MAX_BURST_SIZE];
+	struct rte_pdcp_group grp[MAX_BURST_SIZE];
+	struct rte_pdcp_entity *pdcp_entity;
+	int nb_max_out_mb, ret, nb_grp;
+	uint16_t nb_ops;
+
+	/* Create PDCP entity */
+	pdcp_entity = rte_pdcp_entity_establish(&conf);
+
+	/**
+	 * Allocate buffer for holding mbufs returned during PDCP suspend,
+	 * release & post-process APIs.
+	 */
+
+	/* Max packets that can be cached in entity + burst size */
+	nb_max_out_mb = pdcp_entity->max_pkt_cache + MAX_BURST_SIZE;
+	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
+	if (out_mb == NULL) {
+		/* Handle error */
+	}
+
+	while (1) {
+		/* Receive packet and form mbuf */
+
+		/**
+		 * Prepare packets for crypto operation. Following operations
+		 * would be done,
+		 *
+		 * Transmitting entity/UL (only data PDUs):
+		 *  - Perform compression
+		 *  - Assign sequence number
+		 *  - Add PDCP header
+		 *  - Create & prepare crypto_op
+		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
+		 *  - Save original PDCP SDU (during PDCP re-establishment,
+		 *    unconfirmed PDCP SDUs need to crypto processed again

and

doc/guides/prog_guide/pdcp_lib.rst new file +6 -0
+		 *    transmitted/re-transmitted)
+		 *
+		 *  Receiving entity/DL:
+		 *  - Any control PDUs received would be processed and
+		 *    appropriate actions taken. If data PDU, continue.
+		 *  - Determine sequence number (based on HFN & per packet

SN)

doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+		 *  - Prepare crypto_op
+		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
+		 */
+		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts, cop,
+						      nb_rx, &nb_err);
+		if (nb_err != 0) {
+			/* Handle error packets */
+		}
+
+		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop,

nb_success)

doc/guides/prog_guide/pdcp_lib.rst new file +60 -0
+				!= nb_success) {
+			/* Retry for enqueue failure packets */
+		}
+
+		...
+
+		nb_ops = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
+						  MAX_BURST_SIZE);
+		if (nb_ops == 0)
+			continue;
+
+		/**
+		 * Received a burst of completed crypto ops from cryptodev. It
+		 * may belong to various entities. Group similar ones together
+		 * for entity specific post-processing.
+		 */
+
+		/**
+		 * Groups similar entities together. Frees crypto op and based
+		 * on crypto_op status, set mbuf->ol_flags which would be
+		 * checked in rte_pdcp_pkt_post_process().
+		 */
+		nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);
+
+		for (i = 0; i != nb_grp; i++) {
+
+			/**
+			 * Post process packets after crypto completion.
+			 * Following operations would be done,
+			 *
+			 *  Transmitting entity/UL:
+			 *  - Check crypto result
+			 *
+			 *  Receiving entity/DL:
+			 *  - Check crypto operation status
+			 *  - Check for duplication (if yes, drop duplicate)
+			 *  - Perform decompression
+			 *  - Trim PDCP header
+			 *  - Hold packet (SDU) for in-order delivery (return
+			 *    completed packets as and when sequence is
+			 *    completed)
+			 *  - If not in sequence, cache the packet and start
+			 *    t-Reordering timer. When timer expires, the
+			 *    packets need to delivered to upper layers (not
+			 *    treated as error packets).
+			 */
+			nb_success = rte_pdcp_pkt_post_process(grp[i].id.ptr,
+							       grp[i].m, out_mb,
+							       grp[i].cnt,
+							       &nb_err);
+			if (nb_err != 0) {
+				/* Handle error packets */
+			}
+
+			/* Perform additional operations */
+
+			/**
+			 * Transmitting entity/UL
+			 * - If duplication is enabled, duplicate PDCP PDUs
+			 * - When lower layers confirm reception of a PDCP

PDU,

doc/guides/prog_guide/pdcp_lib.rst new file +21 -0
+			 *   it should be communicated to PDCP layer so that
+			 *   PDCP can drop the corresponding SDU
+			 */
+		}
+	}
+
+
+Supported features
+------------------
+
+- 12 bit & 18 bit sequence numbers
+- Uplink & downlink traffic
+- HFN increment
+- IV generation as required per algorithm
+
+Supported ciphering algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- NULL
+- AES-CTR
+- SNOW3G-CIPHER

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +9 -1
+- ZUC-CIPHER
+
+Supported integrity protection algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- NULL
+- AES-CMAC
+- SNOW3G-AUTH
+- ZUC-AUTH
--

Move Supported features and algos after PDCP PDU explanation. Sample sequence should be in the end.

#51 lore raw

RE: [PATCH v2 11/22] doc: add PDCP library guide

Hi Akhil,

Please see inline.

Thanks,
Anoob

Quoted 71 lines

-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 1:56 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 11/22] doc: add PDCP library guide

Quoted 31 lines
doc/guides/prog_guide/pdcp_lib.rst new file +15 -0
new file mode 100644
index 0000000000..abd874f2cc
@@ -0,0 +1,246 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(C) 2023 Marvell.
+
+PDCP Protocol Processing Library
+================================
+
+DPDK provides a library for PDCP protocol processing. The library
+utilizes other DPDK libraries such as cryptodev, reorder, etc., to
+provide the application with a transparent and high performant PDCP
+protocol processing library.
+
+The library abstracts complete PDCP protocol processing conforming to
+``ETSI TS 138 323 V17.1.0 (2022-08)``.
+https://www.etsi.org/deliver/etsi_ts/138300_138399/138323/17.01.00_60
+/ts_

138323v170100p.pdf

doc/guides/prog_guide/pdcp_lib.rst new file +8 -0
+
+PDCP would involve the following operations,
+
+1. Transfer of user plane data
+2. Transfer of control plane data
+3. Header compression
+4. Uplink data compression
+5. Ciphering and integrity protection

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+
+.. _figure_pdcp_functional_overview:
+
+.. figure:: img/pdcp_functional_overview.*
+
+   PDCP functional overview new
+
+PDCP library would abstract the protocol offload features of the
+cryptodev and would provide a uniform interface and consistent API
+usage to work with cryptodev irrespective of the protocol offload

features supported.

Quoted 4 lines
doc/guides/prog_guide/pdcp_lib.rst new file +4 -0
+
+PDCP entity API
+---------------
+

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+PDCP library provides following control path APIs that is used to
+configure various PDCP entities,
+
+1. ``rte_pdcp_entity_establish()``
+2. ``rte_pdcp_entity_suspend()``
+3. ``rte_pdcp_entity_release()``
+
+A PDCP entity would translate to one ``rte_cryptodev_sym_session`` or
+``rte_security_session`` based on the config. The sessions would be
+created/ destroyed while corresponding PDCP entity operations are

performed.

Quoted 1 line

Please explain the difference between suspend and release here.

[Anoob] Sure. Will do in next version.

Quoted 18 lines
Quoted 18 lines
doc/guides/prog_guide/pdcp_lib.rst new file +17 -0
+
+PDCP PDU (Protocol Data Unit)
+-----------------------------
+
+PDCP PDUs can be categorized as,
+
+1. Control PDU
+2. Data PDU
+
+Control PDUs are used for signalling between entities on either end
+and can be one of the following,
+
+1. PDCP status report
+2. ROHC feedback
+3. EHC feedback
+
+Control PDUs are not ciphered or authenticated, and so such packets
Quoted 8 lines

doc/guides/prog_guide/pdcp_lib.rst

Quoted 6 lines
doc/guides/prog_guide/pdcp_lib.rst new file +6 -0
+are not submitted to cryptodev for processing.
+
+Data PDUs are regular packets submitted by upper layers for
+transmission to other end. Such packets would need to be ciphered and
+authenticated based on the entity configuration.
+

Please move the PDCP PDU section above PDCP entity API section. So that all APIs are together.

[Anoob] PDCP PDU section is also talking about APIs. I'll rename above title from 'PDCP PDU(Protocol Data Unit)' to 'PDCP PDU(Protocol Data Unit) API' to make it more uniform.

Quoted 192 lines

doc/guides/prog_guide/pdcp_lib.rst

Quoted 11 lines
doc/guides/prog_guide/pdcp_lib.rst new file +9 -0
+PDCP packet processing API for data PDU
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+PDCP processing is split into 2 parts. One before cryptodev
+processing
+(``rte_pdcp_pkt_pre_process()``) and one after cryptodev 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 belonging to same PDCP entity.

doc/guides/prog_guide/pdcp_lib.rst

Quoted 5 lines
doc/guides/prog_guide/pdcp_lib.rst new file +5 -0
+
+Lib PDCP would allow application to use same API sequence while
+leveraging protocol offload features enabled by ``rte_security``
+library. Lib PDCP would internally change the handles registered for
+``pre_process`` and ``post_process`` based on features enabled in the

entity.

Quoted 32 lines
doc/guides/prog_guide/pdcp_lib.rst new file +6 -0
+
+Lib PDCP would create the required sessions on the device provided in
+entity to minimize the application requirements. Also, the crypto_op
+allocation and free would also be done internally by lib PDCP to
+allow the library to create crypto ops as required for the input
+packets. For example, when control PDUs

are

doc/guides/prog_guide/pdcp_lib.rst new file +2 -0
+received, no cryptodev enqueue-dequeue is expected for the same and
+lib

PDCP

doc/guides/prog_guide/pdcp_lib.rst new file +22 -0
+is expected to handle it differently.
+
+Sample API usage
+----------------
+
+The ``rte_pdcp_entity_conf`` structure is used to pass the
+configuration parameters for entity creation.
+
+.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h
+   :language: c
+   :start-after: Structure rte_pdcp_entity_conf 8<
+   :end-before: >8 End of structure rte_pdcp_entity_conf.
+
+.. code-block:: c
+
+	struct rte_mbuf **out_mb, *pkts[MAX_BURST_SIZE];
+	struct rte_crypto_op *cop[MAX_BURST_SIZE];
+	struct rte_pdcp_group grp[MAX_BURST_SIZE];
+	struct rte_pdcp_entity *pdcp_entity;
+	int nb_max_out_mb, ret, nb_grp;
+	uint16_t nb_ops;
+

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+	/* Create PDCP entity */
+	pdcp_entity = rte_pdcp_entity_establish(&conf);
+
+	/**
+	 * Allocate buffer for holding mbufs returned during PDCP suspend,
+	 * release & post-process APIs.
+	 */
+
+	/* Max packets that can be cached in entity + burst size */
+	nb_max_out_mb = pdcp_entity->max_pkt_cache +

MAX_BURST_SIZE;

Quoted 21 lines
doc/guides/prog_guide/pdcp_lib.rst new file +20 -0
+	out_mb = rte_malloc(NULL, nb_max_out_mb * sizeof(uintptr_t), 0);
+	if (out_mb == NULL) {
+		/* Handle error */
+	}
+
+	while (1) {
+		/* Receive packet and form mbuf */
+
+		/**
+		 * Prepare packets for crypto operation. Following operations
+		 * would be done,
+		 *
+		 * Transmitting entity/UL (only data PDUs):
+		 *  - Perform compression
+		 *  - Assign sequence number
+		 *  - Add PDCP header
+		 *  - Create & prepare crypto_op
+		 *  - Prepare IV for crypto operation (auth_gen, encrypt)
+		 *  - Save original PDCP SDU (during PDCP re-establishment,
+		 *    unconfirmed PDCP SDUs need to crypto processed again

and

doc/guides/prog_guide/pdcp_lib.rst

Quoted 6 lines
doc/guides/prog_guide/pdcp_lib.rst new file +6 -0
+		 *    transmitted/re-transmitted)
+		 *
+		 *  Receiving entity/DL:
+		 *  - Any control PDUs received would be processed and
+		 *    appropriate actions taken. If data PDU, continue.
+		 *  - Determine sequence number (based on HFN & per

packet

doc/guides/prog_guide/pdcp_lib.rst

Quoted 5 lines

SN)

doc/guides/prog_guide/pdcp_lib.rst new file +4 -0
+		 *  - Prepare crypto_op
+		 *  - Prepare IV for crypto operation (decrypt, auth_verify)
+		 */
+		nb_success = rte_pdcp_pkt_pre_process(pdcp_entity, pkts,

cop,

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +6 -0
+						      nb_rx, &nb_err);
+		if (nb_err != 0) {
+			/* Handle error packets */
+		}
+
+		if ((rte_cryptodev_enqueue_burst(dev_id, qp_id, cop,

nb_success)

doc/guides/prog_guide/pdcp_lib.rst new file +3 -0
+				!= nb_success) {
+			/* Retry for enqueue failure packets */
+		}

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+
+		...
+
+		nb_ops = rte_cryptodev_dequeue_burst(dev_id, qp_id, cop,
+						  MAX_BURST_SIZE);
+		if (nb_ops == 0)
+			continue;
+
+		/**
+		 * Received a burst of completed crypto ops from cryptodev.

It

doc/guides/prog_guide/pdcp_lib.rst

Quoted 1 line
doc/guides/prog_guide/pdcp_lib.rst new file +1 -0
+		 * may belong to various entities. Group similar ones

together

doc/guides/prog_guide/pdcp_lib.rst

Quoted 5 lines
doc/guides/prog_guide/pdcp_lib.rst new file +5 -0
+		 * for entity specific post-processing.
+		 */
+
+		/**
+		 * Groups similar entities together. Frees crypto op and

based

Quoted 18 lines
doc/guides/prog_guide/pdcp_lib.rst new file +18 -0
+		 * on crypto_op status, set mbuf->ol_flags which would be
+		 * checked in rte_pdcp_pkt_post_process().
+		 */
+		nb_grp = rte_pdcp_pkt_crypto_group(cop, pkts, grp, ret);
+
+		for (i = 0; i != nb_grp; i++) {
+
+			/**
+			 * Post process packets after crypto completion.
+			 * Following operations would be done,
+			 *
+			 *  Transmitting entity/UL:
+			 *  - Check crypto result
+			 *
+			 *  Receiving entity/DL:
+			 *  - Check crypto operation status
+			 *  - Check for duplication (if yes, drop duplicate)
+			 *  - Perform decompression

doc/guides/prog_guide/pdcp_lib.rst

Quoted 10 lines
doc/guides/prog_guide/pdcp_lib.rst new file +10 -0
+			 *  - Trim PDCP header
+			 *  - Hold packet (SDU) for in-order delivery (return
+			 *    completed packets as and when sequence is
+			 *    completed)
+			 *  - If not in sequence, cache the packet and start
+			 *    t-Reordering timer. When timer expires, the
+			 *    packets need to delivered to upper layers (not
+			 *    treated as error packets).
+			 */
+			nb_success =

rte_pdcp_pkt_post_process(grp[i].id.ptr,

Quoted 39 lines
doc/guides/prog_guide/pdcp_lib.rst new file +13 -0
+							       grp[i].m, out_mb,
+							       grp[i].cnt,
+							       &nb_err);
+			if (nb_err != 0) {
+				/* Handle error packets */
+			}
+
+			/* Perform additional operations */
+
+			/**
+			 * Transmitting entity/UL
+			 * - If duplication is enabled, duplicate PDCP PDUs
+			 * - When lower layers confirm reception of a PDCP

PDU,

doc/guides/prog_guide/pdcp_lib.rst new file +25 -0
+			 *   it should be communicated to PDCP layer so that
+			 *   PDCP can drop the corresponding SDU
+			 */
+		}
+	}
+
+
+Supported features
+------------------
+
+- 12 bit & 18 bit sequence numbers
+- Uplink & downlink traffic
+- HFN increment
+- IV generation as required per algorithm
+
+Supported ciphering algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- NULL
+- AES-CTR
+- SNOW3G-CIPHER
+- ZUC-CIPHER
+
+Supported integrity protection algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Quoted 8 lines
Quoted 6 lines

+

+- NULL
+- AES-CMAC
+- SNOW3G-AUTH
+- ZUC-AUTH

--

Move Supported features and algos after PDCP PDU explanation. Sample sequence should be in the end.

[Anoob] Agreed. Will make this change in next version.

#52 lore raw

PATCH v2 12/22 pdcp: add control PDU handling

In reply to Anoob Joseph

Add control PDU handling and implement status report generation. Status report generation works only when RX_DELIV = RX_NEXT.

---
 app/test/test_pdcp.c               |  1 +
 doc/guides/prog_guide/pdcp_lib.rst | 10 +++++++
 lib/pdcp/meson.build               |  2 ++
 lib/pdcp/pdcp_cnt.c                | 29 ++++++++++++++++++
 lib/pdcp/pdcp_cnt.h                | 14 +++++++++
 lib/pdcp/pdcp_ctrl_pdu.c           | 46 +++++++++++++++++++++++++++++
 lib/pdcp/pdcp_ctrl_pdu.h           | 15 ++++++++++
 lib/pdcp/pdcp_entity.h             | 15 ++++++++--
 lib/pdcp/pdcp_process.c            | 13 +++++++++
 lib/pdcp/rte_pdcp.c                | 47 +++++++++++++++++++++++++++++-
 lib/pdcp/rte_pdcp.h                | 31 ++++++++++++++++++++
 lib/pdcp/version.map               |  2 ++
 12 files changed, 222 insertions(+), 3 deletions(-)
 create mode 100644 lib/pdcp/pdcp_cnt.c
 create mode 100644 lib/pdcp/pdcp_cnt.h
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.c
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.h
app/test/test_pdcp.c +1 -0
index fc49947ba2..4ecb4d9572 100644
@@ -415,6 +415,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf)
 
 	conf->entity.sess_mpool = ts_params->sess_pool;
 	conf->entity.cop_pool = ts_params->cop_pool;
+	conf->entity.ctr_pdu_pool = ts_params->mbuf_pool;
 	conf->entity.pdcp_xfrm.bearer = pdcp_test_bearer[index];
 	conf->entity.pdcp_xfrm.en_ordering = 0;
 	conf->entity.pdcp_xfrm.remove_duplicates = 0;
doc/guides/prog_guide/pdcp_lib.rst +10 -0
index abd874f2cc..f23360dfc3 100644
@@ -67,6 +67,15 @@ Data PDUs are regular packets submitted by upper layers for transmission to
 other end. Such packets would need to be ciphered and authenticated based on
 the entity configuration.
 
+PDCP packet processing API for control PDU
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Control PDUs are used in PDCP as a communication channel between transmitting
+and receiving entities. When upper layer request for operations such
+re-establishment, receiving PDCP entity need to prepare a status report and
+send it to the other end. The API ``pdcp_ctrl_pdu_status_gen`` allows
+application to request the same.
+
 PDCP packet processing API for data PDU
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -228,6 +237,7 @@ Supported features
 - Uplink & downlink traffic
 - HFN increment
 - IV generation as required per algorithm
+- Control PDU generation
 
 Supported ciphering algorithms
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/pdcp/meson.build +2 -0
index 08679b743a..75d476bf6d 100644
@@ -8,7 +8,9 @@ if is_windows
 endif
 
 sources = files(
+        'pdcp_cnt.c',
         'pdcp_crypto.c',
+        'pdcp_ctrl_pdu.c',
         'pdcp_process.c',
         'rte_pdcp.c',
         )
lib/pdcp/pdcp_cnt.c new file +29 -0
new file mode 100644
index 0000000000..c9b952184b
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_pdcp.h>
+
+#include "pdcp_cnt.h"
+#include "pdcp_entity.h"
+
+int
+pdcp_cnt_ring_create(struct rte_pdcp_entity *en, const struct rte_pdcp_entity_conf *conf)
+{
+	struct entity_priv_dl_part *en_priv_dl;
+	uint32_t window_sz;
+
+	if (en == NULL || conf == NULL)
+		return -EINVAL;
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		return 0;
+
+	en_priv_dl = entity_dl_part_get(en);
+	window_sz = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
+
+	RTE_SET_USED(window_sz);
+	RTE_SET_USED(en_priv_dl);
+
+	return 0;
+}
lib/pdcp/pdcp_cnt.h new file +14 -0
new file mode 100644
index 0000000000..bbda478b55
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CNT_H
+#define PDCP_CNT_H
+
+#include <rte_common.h>
+
+#include "pdcp_entity.h"
+
+int pdcp_cnt_ring_create(struct rte_pdcp_entity *en, const struct rte_pdcp_entity_conf *conf);
+
+#endif /* PDCP_CNT_H */
lib/pdcp/pdcp_ctrl_pdu.c new file +46 -0

46 lines not on this page · raw message

lib/pdcp/pdcp_ctrl_pdu.h new file +15 -0
new file mode 100644
index 0000000000..a2424fbd10
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CTRL_PDU_H
+#define PDCP_CTRL_PDU_H
+
+#include <rte_mbuf.h>
+
+#include "pdcp_entity.h"
+
+int
+pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m);
+
+#endif /* PDCP_CTRL_PDU_H */
lib/pdcp/pdcp_entity.h +13 -2
index 3108795977..7b7e7f69dd 100644
@@ -109,6 +109,13 @@ union cipher_iv_partial {
 	uint64_t u64[2];
 };
 
+struct pdcp_cnt_bitmap {
+	/** Number of entries that can be stored. */
+	uint32_t size;
+	/** Bitmap of the count values already received.*/
+	struct rte_bitmap *bmp;
+};
+
 /*
  * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]
  */
@@ -136,9 +143,13 @@ struct entity_priv {
 		uint64_t is_ul_entity : 1;
 		/** Is NULL auth. */
 		uint64_t is_null_auth : 1;
+		/** Is status report required.*/
+		uint64_t is_status_report_required : 1;
 	} flags;
 	/** Crypto op pool. */
 	struct rte_mempool *cop_pool;
+	/** Control PDU pool. */
+	struct rte_mempool *ctr_pdu_pool;
 	/** PDCP header size. */
 	uint8_t hdr_sz;
 	/** PDCP AAD size. For AES-CMAC, additional message is prepended for the operation. */
@@ -148,8 +159,8 @@ struct entity_priv {
 };
 
 struct entity_priv_dl_part {
-	/* NOTE: when in-order-delivery is supported, post PDCP packets would need to cached. */
-	uint8_t dummy;
+	/** PDCP would need to track the count values that are already received.*/
+	struct pdcp_cnt_bitmap bitmap;
 };
 
 struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +13 -0
index 9c1a5e0669..267b3b7723 100644
@@ -1157,6 +1157,19 @@ pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct rte_pdcp_ent
 	if (a_xfrm != NULL && a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
 		en_priv->flags.is_null_auth = 1;
 
+	/**
+	 * flags.is_status_report_required
+	 *
+	 * Indicate whether status report is required.
+	 */
+	if (conf->status_report_required) {
+		/** Status report is required only for DL entities. */
+		if (conf->pdcp_xfrm.pkt_dir != RTE_SECURITY_PDCP_DOWNLINK)
+			return -EINVAL;
+
+		en_priv->flags.is_status_report_required = 1;
+	}
+
 	/**
 	 * hdr_sz
 	 *
lib/pdcp/rte_pdcp.c +46 -1

75 lines not on this page · raw message

lib/pdcp/rte_pdcp.h +31 -0
index 54f88e3fd3..d2db25d7d9 100644
@@ -16,6 +16,7 @@
 #include <rte_compat.h>
 #include <rte_common.h>
 #include <rte_mempool.h>
+#include <rte_pdcp_hdr.h>
 #include <rte_security.h>
 
 #ifdef __cplusplus
@@ -78,6 +79,8 @@ struct rte_pdcp_entity_conf {
 	struct rte_mempool *sess_mpool;
 	/** Crypto op pool.*/
 	struct rte_mempool *cop_pool;
+	/** Mbuf pool to be used for allocating control PDUs.*/
+	struct rte_mempool *ctr_pdu_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.
@@ -91,6 +94,15 @@ struct rte_pdcp_entity_conf {
 	uint8_t dev_id;
 	/** Reverse direction during IV generation. Can be used to simulate UE crypto processing.*/
 	bool reverse_iv_direction;
+	/**
+	 * Status report required (specified in TS 38.331).
+	 *
+	 * If PDCP entity is configured to send a PDCP status report, the upper layer application
+	 * may request a receiving PDCP entity to generate a PDCP status report using
+	 * ``rte_pdcp_ctrl_pdu_create``. In addition, PDCP status reports may be generated during
+	 * operations such as entity re-establishment.
+	 */
+	bool status_report_required;
 };
 /* >8 End of structure rte_pdcp_entity_conf. */
 
@@ -169,6 +181,25 @@ int
 rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
 			struct rte_mbuf *out_mb[]);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create control PDU packet of the `type` specified.
+ *
+ * @param pdcp_entity
+ *   Pointer to the PDCP entity for which the control PDU need to be generated.
+ * @param type
+ *   Type of control PDU to be generated.
+ * @return
+ *   - Control PDU generated, in case of success.
+ *   - NULL in case of failure. rte_errno will be set to error code.
+ */
+__rte_experimental
+struct rte_mbuf *
+rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,
+			    enum rte_pdcp_ctrl_pdu_type type);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
lib/pdcp/version.map +2 -0
index f9ff30600a..d0cf338e1f 100644
@@ -6,6 +6,8 @@ EXPERIMENTAL {
 	rte_pdcp_entity_release;
 	rte_pdcp_entity_suspend;
 
+	rte_pdcp_control_pdu_create;
+
 	rte_pdcp_pkt_post_process;
 	rte_pdcp_pkt_pre_process;
 
Signature · 1 line
2.25.1
#53 lore raw

RE: [PATCH v2 12/22] pdcp: add control PDU handling

Quoted 9 lines

Subject: [PATCH v2 12/22] pdcp: add control PDU handling

Add control PDU handling and implement status report generation. Status report generation works only when RX_DELIV = RX_NEXT.

---
 app/test/test_pdcp.c               |  1 +

Separate out test app changes from library changes.

Quoted 45 lines
 doc/guides/prog_guide/pdcp_lib.rst | 10 +++++++
 lib/pdcp/meson.build               |  2 ++
 lib/pdcp/pdcp_cnt.c                | 29 ++++++++++++++++++
 lib/pdcp/pdcp_cnt.h                | 14 +++++++++
 lib/pdcp/pdcp_ctrl_pdu.c           | 46 +++++++++++++++++++++++++++++
 lib/pdcp/pdcp_ctrl_pdu.h           | 15 ++++++++++
 lib/pdcp/pdcp_entity.h             | 15 ++++++++--
 lib/pdcp/pdcp_process.c            | 13 +++++++++
 lib/pdcp/rte_pdcp.c                | 47 +++++++++++++++++++++++++++++-
 lib/pdcp/rte_pdcp.h                | 31 ++++++++++++++++++++
 lib/pdcp/version.map               |  2 ++
 12 files changed, 222 insertions(+), 3 deletions(-)
 create mode 100644 lib/pdcp/pdcp_cnt.c
 create mode 100644 lib/pdcp/pdcp_cnt.h
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.c
 create mode 100644 lib/pdcp/pdcp_ctrl_pdu.h
app/test/test_pdcp.c +1 -0
index fc49947ba2..4ecb4d9572 100644
@@ -415,6 +415,7 @@ create_test_conf_from_index(const int index, struct
 pdcp_test_conf *conf)
 
 	conf->entity.sess_mpool = ts_params->sess_pool;
 	conf->entity.cop_pool = ts_params->cop_pool;
+	conf->entity.ctr_pdu_pool = ts_params->mbuf_pool;
 	conf->entity.pdcp_xfrm.bearer = pdcp_test_bearer[index];
 	conf->entity.pdcp_xfrm.en_ordering = 0;
app/test/test_pdcp.c +0 -0
 	conf->entity.pdcp_xfrm.remove_duplicates = 0;
doc/guides/prog_guide/pdcp_lib.rst +0 -0
index abd874f2cc..f23360dfc3 100644
@@ -67,6 +67,15 @@ Data PDUs are regular packets submitted by upper layers

for transmission to
other end. Such packets would need to be ciphered and authenticated based on the entity configuration.

doc/guides/prog_guide/pdcp_lib.rst +4 -0
+PDCP packet processing API for control PDU
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Control PDUs are used in PDCP as a communication channel between

transmitting

doc/guides/prog_guide/pdcp_lib.rst Data PDUs are regular packets submitted by upper layers for transmission to · line 77

Quoted 4 lines
doc/guides/prog_guide/pdcp_lib.rst +4 -0
+and receiving entities. When upper layer request for operations such
+re-establishment, receiving PDCP entity need to prepare a status report and
+send it to the other end. The API ``pdcp_ctrl_pdu_status_gen`` allows
+application to request the same.

pdcp_ctrl_pdu_status_gen() - Is this a user visible API? I believe it is not exposed. How can application request that?

Quoted 17 lines
doc/guides/prog_guide/pdcp_lib.rst +2 -0
+
 PDCP packet processing API for data PDU
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -228,6 +237,7 @@ Supported features
 - Uplink & downlink traffic
 - HFN increment
 - IV generation as required per algorithm
+- Control PDU generation
 
 Supported ciphering algorithms
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/pdcp/meson.build +0 -0
index 08679b743a..75d476bf6d 100644

lib/pdcp/meson.build if is_windows · line 11

Quoted 4 lines
lib/pdcp/meson.build +1 -0
@@ -8,7 +8,9 @@ if is_windows
 endif
 
 sources = files(
+        'pdcp_cnt.c',

pdcp_cnt seems to be something related to count.
And it is not related to this patch probably.

Quoted 141 lines
lib/pdcp/meson.build +1 -0
         'pdcp_crypto.c',
+        'pdcp_ctrl_pdu.c',
         'pdcp_process.c',
         'rte_pdcp.c',
         )
lib/pdcp/pdcp_cnt.c new file +11 -0
new file mode 100644
index 0000000000..c9b952184b
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_pdcp.h>
+
+#include "pdcp_cnt.h"
+#include "pdcp_entity.h"
+
+int
+pdcp_cnt_ring_create(struct rte_pdcp_entity *en, const struct

rte_pdcp_entity_conf *conf)

lib/pdcp/pdcp_cnt.c new file +18 -0
+{
+	struct entity_priv_dl_part *en_priv_dl;
+	uint32_t window_sz;
+
+	if (en == NULL || conf == NULL)
+		return -EINVAL;
+
+	if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
+		return 0;
+
+	en_priv_dl = entity_dl_part_get(en);
+	window_sz = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
+
+	RTE_SET_USED(window_sz);
+	RTE_SET_USED(en_priv_dl);
+
+	return 0;
+}
lib/pdcp/pdcp_cnt.h new file +12 -0
new file mode 100644
index 0000000000..bbda478b55
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CNT_H
+#define PDCP_CNT_H
+
+#include <rte_common.h>
+
+#include "pdcp_entity.h"
+
+int pdcp_cnt_ring_create(struct rte_pdcp_entity *en, const struct

rte_pdcp_entity_conf *conf);

lib/pdcp/pdcp_cnt.h new file +2 -0
+
+#endif /* PDCP_CNT_H */
lib/pdcp/pdcp_ctrl_pdu.c new file +37 -0
new file mode 100644
index 0000000000..feb05fd863
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+#include <rte_pdcp_hdr.h>
+
+#include "pdcp_ctrl_pdu.h"
+#include "pdcp_entity.h"
+
+static __rte_always_inline void
+pdcp_hdr_fill(struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr, uint32_t rx_deliv)
+{
+	pdu_hdr->d_c = RTE_PDCP_PDU_TYPE_CTRL;
+	pdu_hdr->pdu_type = RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT;
+	pdu_hdr->r = 0;
+	pdu_hdr->fmc = rte_cpu_to_be_32(rx_deliv);
+}
+
+int
+pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m)
+{
+	struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr;
+	uint32_t rx_deliv;
+	int pdu_sz;
+
+	if (!en_priv->flags.is_status_report_required)
+		return -EINVAL;
+
+	pdu_sz = sizeof(struct rte_pdcp_up_ctrl_pdu_hdr);
+
+	rx_deliv = en_priv->state.rx_deliv;
+
+	/* Zero missing PDUs - status report contains only FMC */
+	if (rx_deliv >= en_priv->state.rx_next) {
+		pdu_hdr = (struct rte_pdcp_up_ctrl_pdu_hdr

*)rte_pktmbuf_append(m, pdu_sz);

lib/pdcp/pdcp_ctrl_pdu.c new file +9 -0
+		if (pdu_hdr == NULL)
+			return -ENOMEM;
+		pdcp_hdr_fill(pdu_hdr, rx_deliv);
+
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
lib/pdcp/pdcp_ctrl_pdu.h new file +15 -0
new file mode 100644
index 0000000000..a2424fbd10
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef PDCP_CTRL_PDU_H
+#define PDCP_CTRL_PDU_H
+
+#include <rte_mbuf.h>
+
+#include "pdcp_entity.h"
+
+int
+pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m);
+
+#endif /* PDCP_CTRL_PDU_H */
lib/pdcp/pdcp_entity.h +0 -0
index 3108795977..7b7e7f69dd 100644

lib/pdcp/pdcp_entity.h union cipher_iv_partial { · line 117

Quoted 9 lines
lib/pdcp/pdcp_entity.h +6 -0
@@ -109,6 +109,13 @@ union cipher_iv_partial {
 	uint64_t u64[2];
 };
 
+struct pdcp_cnt_bitmap {
+	/** Number of entries that can be stored. */
+	uint32_t size;
+	/** Bitmap of the count values already received.*/
+	struct rte_bitmap *bmp;
+};

This pdcp_cnt_bitmap is not related to control PDU. Right? I believe the patch split is not proper here.

Quoted 111 lines
lib/pdcp/pdcp_entity.h +5 -0
+
 /*
  * Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul]
  */
@@ -136,9 +143,13 @@ struct entity_priv {
 		uint64_t is_ul_entity : 1;
 		/** Is NULL auth. */
 		uint64_t is_null_auth : 1;
+		/** Is status report required.*/
+		uint64_t is_status_report_required : 1;
 	} flags;
 	/** Crypto op pool. */
 	struct rte_mempool *cop_pool;
+	/** Control PDU pool. */
+	struct rte_mempool *ctr_pdu_pool;
 	/** PDCP header size. */
 	uint8_t hdr_sz;
 	/** PDCP AAD size. For AES-CMAC, additional message is prepended for

the operation. */

lib/pdcp/pdcp_entity.h +0 -1
@@ -148,8 +159,8 @@ struct entity_priv {
 };
 
 struct entity_priv_dl_part {
-	/* NOTE: when in-order-delivery is supported, post PDCP packets would

need to cached. */

lib/pdcp/pdcp_entity.h +1 -1
-	uint8_t dummy;
+	/** PDCP would need to track the count values that are already

received.*/

lib/pdcp/pdcp_entity.h +1 -0
+	struct pdcp_cnt_bitmap bitmap;
 };
 
 struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +13 -0
index 9c1a5e0669..267b3b7723 100644
@@ -1157,6 +1157,19 @@ pdcp_entity_priv_populate(struct entity_priv
 *en_priv, const struct rte_pdcp_ent
 	if (a_xfrm != NULL && a_xfrm->auth.algo ==
 RTE_CRYPTO_AUTH_NULL)
 		en_priv->flags.is_null_auth = 1;
 
+	/**
+	 * flags.is_status_report_required
+	 *
+	 * Indicate whether status report is required.
+	 */
+	if (conf->status_report_required) {
+		/** Status report is required only for DL entities. */
+		if (conf->pdcp_xfrm.pkt_dir !=
 RTE_SECURITY_PDCP_DOWNLINK)
+			return -EINVAL;
+
+		en_priv->flags.is_status_report_required = 1;
+	}
+
lib/pdcp/pdcp_process.c +0 -0
 	/**
 	 * hdr_sz
 	 *
lib/pdcp/rte_pdcp.c +3 -1
index 8914548dbd..5cd3f5ca31 100644
@@ -6,7 +6,9 @@
 #include <rte_pdcp.h>
 #include <rte_malloc.h>
 
+#include "pdcp_cnt.h"
 #include "pdcp_crypto.h"
+#include "pdcp_ctrl_pdu.h"
 #include "pdcp_entity.h"
 #include "pdcp_process.h"
 
@@ -34,7 +36,7 @@ rte_pdcp_entity_establish(const struct
 rte_pdcp_entity_conf *conf)
 	struct entity_priv *en_priv;
 	int ret, entity_size;
 
-	if (conf == NULL || conf->cop_pool == NULL) {
+	if (conf == NULL || conf->cop_pool == NULL || conf->ctr_pdu_pool ==
 NULL) {
 		rte_errno = -EINVAL;
lib/pdcp/rte_pdcp.c +1 -0
 		return NULL;
 	}
@@ -79,6 +81,7 @@ rte_pdcp_entity_establish(const struct
 rte_pdcp_entity_conf *conf)
 	en_priv->state.rx_deliv = conf->count;
 	en_priv->state.tx_next = conf->count;
 	en_priv->cop_pool = conf->cop_pool;
+	en_priv->ctr_pdu_pool = conf->ctr_pdu_pool;
 
 	/* Setup crypto session */
lib/pdcp/rte_pdcp.c +4 -0
 	ret = pdcp_crypto_sess_create(entity, conf);
@@ -89,6 +92,10 @@ rte_pdcp_entity_establish(const struct
 rte_pdcp_entity_conf *conf)
 	if (ret)
 		goto crypto_sess_destroy;
 
+	ret = pdcp_cnt_ring_create(entity, conf);
+	if (ret)
+		goto crypto_sess_destroy;
+
 	return entity;
 

crypto_sess_destroy:

lib/pdcp/rte_pdcp.c +1 -0
@@ -136,3 +143,41 @@ rte_pdcp_entity_suspend(struct rte_pdcp_entity
 *pdcp_entity,
 
 	return 0;
 }
+

lib/pdcp/rte_pdcp.c rte_pdcp_entity_suspend(struct rte_pdcp_entity · line 156

Quoted 10 lines
lib/pdcp/rte_pdcp.c +10 -0
+struct rte_mbuf *
+rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,
+			    enum rte_pdcp_ctrl_pdu_type type)
+{
+	struct entity_priv *en_priv;
+	struct rte_mbuf *m;
+	int ret;
+
+	if (pdcp_entity == NULL) {
+		rte_errno = -EINVAL;

rte_errno should be positive values.

Quoted 40 lines
lib/pdcp/rte_pdcp.c +27 -0
+		return NULL;
+	}
+
+	en_priv = entity_priv_get(pdcp_entity);
+
+	m = rte_pktmbuf_alloc(en_priv->ctr_pdu_pool);
+	if (m == NULL) {
+		rte_errno = -ENOMEM;
+		return NULL;
+	}
+
+	switch (type) {
+	case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT:
+		ret = pdcp_ctrl_pdu_status_gen(en_priv, m);
+		break;
+	default:
+		ret = -ENOTSUP;
+	}
+
+	if (ret) {
+		rte_pktmbuf_free(m);
+		rte_errno = ret;
+		return NULL;
+	}
+
+	return m;
+}
lib/pdcp/rte_pdcp.h +1 -0
index 54f88e3fd3..d2db25d7d9 100644
@@ -16,6 +16,7 @@
 #include <rte_compat.h>
 #include <rte_common.h>
 #include <rte_mempool.h>
+#include <rte_pdcp_hdr.h>
 #include <rte_security.h>
 
 #ifdef __cplusplus

lib/pdcp/rte_pdcp.h struct rte_pdcp_entity_conf { · line 83

Quoted 5 lines
lib/pdcp/rte_pdcp.h +2 -0
@@ -78,6 +79,8 @@ struct rte_pdcp_entity_conf {
 	struct rte_mempool *sess_mpool;
 	/** Crypto op pool.*/
 	struct rte_mempool *cop_pool;
+	/** Mbuf pool to be used for allocating control PDUs.*/
+	struct rte_mempool *ctr_pdu_pool;

Please use same prefix for all control pdu stuff.
I see cnt, ctr, ctrl, control is being used.
I think "control" for top level API and "ctrl" for parameters should be fine.

Quoted 18 lines
lib/pdcp/rte_pdcp.h +0 -0
 	/**
 	 * 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.

lib/pdcp/rte_pdcp.h +0 -0
@@ -91,6 +94,15 @@ struct rte_pdcp_entity_conf {
 	uint8_t dev_id;
 	/** Reverse direction during IV generation. Can be used to simulate UE

crypto processing.*/

lib/pdcp/rte_pdcp.h +4 -0
 	bool reverse_iv_direction;
+	/**
+	 * Status report required (specified in TS 38.331).
+	 *
+	 * If PDCP entity is configured to send a PDCP status report, the upper

layer application

lib/pdcp/rte_pdcp.h +1 -0
+	 * may request a receiving PDCP entity to generate a PDCP status report

using

lib/pdcp/rte_pdcp.h +1 -0
+	 * ``rte_pdcp_ctrl_pdu_create``. In addition, PDCP status reports may be

generated during

lib/pdcp/rte_pdcp.h struct rte_pdcp_entity_conf { · line 105

Quoted 3 lines
lib/pdcp/rte_pdcp.h +3 -0
+	 * operations such as entity re-establishment.
+	 */
+	bool status_report_required;

rte_pdcp_ctrl_pdu_create -> rte_pdcp_control_pdu_create

Please specify that a PDU will be generated for status report. Otherwise, it seems some structure would be returned for status report But there is no mention of that. This will avoid confusion.

Quoted 44 lines

};
/* >8 End of structure rte_pdcp_entity_conf. */

lib/pdcp/rte_pdcp.h +19 -0
@@ -169,6 +181,25 @@ int
 rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
 			struct rte_mbuf *out_mb[]);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create control PDU packet of the `type` specified.
+ *
+ * @param pdcp_entity
+ *   Pointer to the PDCP entity for which the control PDU need to be generated.
+ * @param type
+ *   Type of control PDU to be generated.
+ * @return
+ *   - Control PDU generated, in case of success.
+ *   - NULL in case of failure. rte_errno will be set to error code.
+ */
+__rte_experimental
+struct rte_mbuf *
+rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,
+			    enum rte_pdcp_ctrl_pdu_type type);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
lib/pdcp/version.map +2 -1
index f9ff30600a..d0cf338e1f 100644
@@ -6,6 +6,8 @@ EXPERIMENTAL {
 	rte_pdcp_entity_release;
 	rte_pdcp_entity_suspend;
 
+	rte_pdcp_control_pdu_create;
+
 	rte_pdcp_pkt_post_process;
 	rte_pdcp_pkt_pre_process;
 
--

2.25.1