lib: add pdcp protocol
Subsystems (2)
RE: [PATCH v2 12/22] pdcp: add control PDU handling
In reply to Akhil GoyalHi Akhil,
Please see inline.
Thanks,
Anoob
Quoted 18 lines
-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 2:45 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 12/22] pdcp: add control PDU handlingQuoted 5 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.
Quoted 6 lines
Quoted 4 lines
Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>--- app/test/test_pdcp.c | 1 +Separate out test app changes from library changes.
[Anoob] Agreed. Will make the change in next version.
Quoted 39 lines
Quoted 39 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 mode100644
lib/pdcp/pdcp_cnt.ccreate mode 100644lib/pdcp/pdcp_cnt.hcreate mode 100644lib/pdcp/pdcp_ctrl_pdu.ccreate mode 100644lib/pdcp/pdcp_ctrl_pdu.happ/test/test_pdcp.c index renamed from app/test/test_pdcp.c +0
-0
fc49947ba2..4ecb4d9572100644app/test/test_pdcp.c +1
-0@@ -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; diff --gita/doc/guides/prog_guide/pdcp_lib.rstb/doc/guides/prog_guide/pdcp_lib.rst
indexabd874f2cc..f23360dfc3100644doc/guides/prog_guide/pdcp_lib.rst +0
-0@@ -67,6 +67,15 @@ Data PDUs are regular packets submitted by upperlayers for transmission to other end. Such packets would need to be ciphered and authenticated based on the entity configuration.
Quoted 13 lines
doc/guides/prog_guide/pdcp_lib.rst
Quoted 9 lines
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 betweentransmitting
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?
[Anoob] Quoted wrong API. It should be 'rte_pdcp_control_pdu_create()'. Will have this corrected in next version.
Quoted 21 lines
Quoted 21 lines
+
PDCP packet processing API for data PDU
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~doc/guides/prog_guide/pdcp_lib.rst +1
-0@@ -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 index renamed from lib/pdcp/meson.build +0
-0
08679b743a..75d476bf6d100644lib/pdcp/meson.build +0
-0@@ -8,7 +8,9 @@ if is_windows endif
Quoted 5 lines
lib/pdcp/meson.build if is_windows · line 11
Quoted 2 lines
lib/pdcp/meson.build +1
-0sources = files( + 'pdcp_cnt.c',
pdcp_cntseems to be something related to count.
And it is not related to this patch probably.
[Anoob] 'pdcp_cnt' tracks the sequence number of the received packets etc. This info is required for generating status report which is one of the control PDUs supported.
Quoted 142 lines
Quoted 72 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 mode renamed from lib/pdcp/pdcp_cnt.c +0
-0100644 index 0000000000..c9b952184b
lib/pdcp/pdcp_cnt.c new file +11
-0@@ -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 mode renamed from lib/pdcp/pdcp_cnt.h +0
-0100644 index 0000000000..bbda478b55
lib/pdcp/pdcp_cnt.h new file +12
-0@@ -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 renamed from lib/pdcp/pdcp_ctrl_pdu.c +0
-0file mode 100644 index 0000000000..feb05fd863
lib/pdcp/pdcp_ctrl_pdu.c new file +6
-0@@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(C) 2023 Marvell. +*/ + +#include <rte_byteorder.h> +#include <rte_mbuf.h> lib/pdcp/pdcp_ctrl_pdu.c line 16
Quoted 10 lines
lib/pdcp/pdcp_ctrl_pdu.c new file +10
-0+#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;Quoted 59 lines
lib/pdcp/pdcp_ctrl_pdu.c new file +20
-0+ 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 renamed from lib/pdcp/pdcp_ctrl_pdu.h +0
-0file mode 100644 index 0000000000..a2424fbd10
lib/pdcp/pdcp_ctrl_pdu.h new file +16
-0@@ -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 index renamed from lib/pdcp/pdcp_entity.h +0
-03108795977..7b7e7f69dd 100644
lib/pdcp/pdcp_entity.h +0
-0@@ -109,6 +109,13 @@ union cipher_iv_partial {uint64_t u64[2 ]; };
Quoted 9 lines
lib/pdcp/pdcp_entity.h union cipher_iv_partial { · line 117
Quoted 6 lines
lib/pdcp/pdcp_entity.h +6
-0+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_bitmapis not related to control PDU. Right? I believe the patch split is not proper here.
[Anoob] Bitmap is required for generating status report. With this patch, we are adding support for control PDU handling and adding basic support for status report generation.
Quoted 162 lines
Quoted 9 lines
lib/pdcp/pdcp_entity.h +1
-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;lib/pdcp/pdcp_entity.h struct entity_priv { · line 155
Quoted 10 lines
lib/pdcp/pdcp_entity.h +4
-0+/** 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
lib/pdcp/pdcp_entity.h
Quoted 4 lines
the operation. */ @@ -148,8 +159,8 @@ struct
entity_priv{ };struct
entity_priv_dl_part{lib/pdcp/pdcp_entity.h +0
-1-/* NOTE: when in-order-delivery is supported, post PDCP packets would
Quoted 50 lines
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 index renamed from lib/pdcp/pdcp_process.c +0
-0
9c1a5e0669..267b3b7723100644lib/pdcp/pdcp_process.c +13
-0@@ -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 index renamed from lib/pdcp/rte_pdcp.c +0
-0
8914548dbd..5cd3f5ca31100644lib/pdcp/rte_pdcp.c +2
-0@@ -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" lib/pdcp/rte_pdcp.c rte_pdcp_entity_establish(const struct · line 40
Quoted 6 lines
lib/pdcp/rte_pdcp.c +1
-1@@ -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==
Quoted 29 lines
lib/pdcp/rte_pdcp.c +0
-0NULL) { rte_errno = -EINVAL ;lib/pdcp/rte_pdcp.c +1
-0return 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 */ ret =
pdcp_crypto_sess_create(entity, conf); @@ -89,6 +92,10 @@rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)lib/pdcp/rte_pdcp.c +4
-0if (ret) goto crypto_sess_destroy; + ret =pdcp_cnt_ring_create (entity, conf); +if (ret) + goto crypto_sess_destroy; +return entity; crypto_sess_destroy:@@ -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_errnoshould be positive values.Quoted 38 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 index renamed from lib/pdcp/rte_pdcp.h +0
-0
54f88e3fd3..d2db25d7d9100644lib/pdcp/rte_pdcp.h +1
-0@@ -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>
Quoted 11 lines
lib/pdcp/rte_pdcp.h struct rte_pdcp_entity_conf { · line 83
Quoted 7 lines
lib/pdcp/rte_pdcp.h +2
-0#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;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.
[Anoob] Agreed. Will make this change in next version.
Quoted 29 lines
lib/pdcp/rte_pdcp.h struct rte_pdcp_entity_conf {
Quoted 4 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
Quoted 18 lines
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 +5
-0bool 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 +2
-0+ * may request a receiving PDCP entity to generate a PDCP status +reportusing
lib/pdcp/rte_pdcp.h +2
-0+ * ``rte_pdcp_ctrl_pdu_create``. In addition, PDCP status reports +may begenerated 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
Quoted 3 lines
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.
[Anoob] Agreed. Will update documentation of rte_pdcp_control_pdu_create() to denote that it is lib PDCP which would allocate the packet.
Quoted 47 lines
Quoted 7 lines
};
/* >8 End of structurerte_pdcp_entity_conf. */lib/pdcp/rte_pdcp.h +0
-0@@ -169,6 +181,25 @@ int rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,lib/pdcp/rte_pdcp.h int · line 191
Quoted 10 lines
lib/pdcp/rte_pdcp.h +8
-0struct 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.
Quoted 29 lines
lib/pdcp/rte_pdcp.h +11
-1+* @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 diff --git a/lib/pdcp/version.map b/lib/pdcp/version.map index
f9ff30600a..d0cf338e1f100644lib/pdcp/version.map +2
-1@@ -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
PATCH v2 13/22 pdcp: implement t-Reordering and packet buffering
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add in-order delivery of packets in PDCP. Delivery of packets in-order relies on t-Reordering timer.
When 'out-of-order delivery' is disabled, PDCP will buffer all received packets that are out of order. The t-Reordering timer determines the time period these packets would be held in the buffer, waiting for any missing packets to arrive.
Introduce packet buffering and state variables which indicate status of the timer.
--- lib/pdcp/meson.build | 3 +- lib/pdcp/pdcp_entity.h | 19 +++++++ lib/pdcp/pdcp_process.c | 123 +++++++++++++++++++++++++++++++--------- lib/pdcp/pdcp_reorder.c | 27 +++++++++ lib/pdcp/pdcp_reorder.h | 62 ++++++++++++++++++++ lib/pdcp/rte_pdcp.c | 53 +++++++++++++++-- lib/pdcp/rte_pdcp.h | 6 +- 7 files changed, 257 insertions(+), 36 deletions(-) create mode 100644 lib/pdcp/pdcp_reorder.c create mode 100644 lib/pdcp/pdcp_reorder.h
lib/pdcp/meson.build +2 -1
@@ -12,9 +12,10 @@ sources = files( 'pdcp_crypto.c', 'pdcp_ctrl_pdu.c', 'pdcp_process.c', + 'pdcp_reorder.c', 'rte_pdcp.c', ) headers = files('rte_pdcp.h') indirect_headers += files('rte_pdcp_group.h') -deps += ['mbuf', 'net', 'cryptodev', 'security'] +deps += ['mbuf', 'net', 'cryptodev', 'security', 'reorder']
lib/pdcp/pdcp_entity.h +19 -0
@@ -11,6 +11,8 @@#include <rte_pdcp.h> #include <rte_security.h> +#include "pdcp_reorder.h" +struct entity_priv ;#define PDCP_HFN_MIN 0
@@ -109,6 +111,17 @@ union cipher_iv_partial {uint64_t u64[2 ]; }; +enum timer_state { +TIMER_STOP , +TIMER_RUNNING , +TIMER_EXPIRED , +}; + +struct pdcp_t_reordering { +/** Represent timer state */ +enum timer_state state; +}; +struct pdcp_cnt_bitmap {/** Number of entries that can be stored. */ uint32_t size;
@@ -145,6 +158,8 @@ struct entity_priv { uint64_t is_null_auth : 1;/** Is status report required.*/ uint64_t is_status_report_required : 1; +/** Is out-of-order delivery enabled */ + uint64_t is_out_of_order_delivery : 1; } flags;/** Crypto op pool. */ struct rte_mempool *cop_pool;
@@ -161,6 +176,10 @@ struct entity_priv {struct entity_priv_dl_part {/** PDCP would need to track the count values that are already received.*/ struct pdcp_cnt_bitmap bitmap; +/** t-Reordering handles */ +struct pdcp_t_reordering t_reorder; +/** Reorder packet buffer */ +struct pdcp_reorder reorder; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +95 -28
206 lines not on this page · raw message
lib/pdcp/pdcp_reorder.c new file +27 -0
@@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(C) 2023 Marvell. +*/ + +#include <rte_errno.h> +#include <rte_reorder.h> + +#include "pdcp_reorder.h" + +int +pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +{ + reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); +if (reorder->buf ==NULL ) +return -rte_errno; + + reorder->window_size = window_size; + reorder->is_active = false; + +return 0 ; +} + +void +pdcp_reorder_destroy (const struct pdcp_reorder *reorder) +{ +rte_reorder_free (reorder->buf); +}
lib/pdcp/pdcp_reorder.h new file +62 -0
62 lines not on this page · raw message
lib/pdcp/rte_pdcp.c +48 -5
99 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +4 -2
@@ -103,6 +103,8 @@ struct rte_pdcp_entity_conf {* operations such as entity re-establishment. */ bool status_report_required; +/** Enable out of order delivery. */ +bool out_of_order_delivery; };/* >8 End of structure rte_pdcp_entity_conf. */
@@ -259,8 +261,8 @@ rte_pdcp_pkt_pre_process(const struct rte_pdcp_entity *entity,* @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. +* The address of an array that can hold up to *rte_pdcp_entity.max_pkt_cache* +* 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
Signature · 1 line
2.25.1
PATCH v2 14/22 test/pdcp: add in-order delivery cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases to verify behaviour when in-order delivery is enabled and packets arrive in out-of-order. PDCP library is expected to buffer the packets and return packets in-order when the missing packet arrives.
--- app/test/test_pdcp.c | 195 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+)
app/test/test_pdcp.c +195 -0
@@ -15,6 +15,15 @@#define CDEV_INVALID_ID UINT8_MAX#define NB_TESTS RTE_DIM(pdcp_test_params) +/* Assert that condition is true, or goto the mark */ +#define ASSERT_TRUE_OR_GOTO (cond, mark, ...) do {\ + if (!(cond)) { \ + RTE_LOG(ERR, USER1, "Error at: %s:%d\n", __func__, __LINE__); \ + RTE_LOG(ERR, USER1, __VA_ARGS__); \ + goto mark; \ + } \ +} while (0) +/* According to formula(7.2.a Window_Size) */ #define PDCP_WINDOW_SIZE (sn_size) (1 << (sn_size - 1))
@@ -82,6 +91,14 @@ run_test_with_all_known_vec(const void *args)return run_test_foreach_known_vec (test, false); } +static int +run_test_with_all_known_vec_until_first_pass (const void *args) +{ +test_with_conf_t test = args; + +return run_test_foreach_known_vec (test, true); +} +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -868,6 +885,7 @@ test_sn_range_type(enum sn_range_type type, struct pdcp_test_conf *conf)/* Configure Uplink to generate expected, encrypted packet */ pdcp_sn_to_raw_set (conf->input, new_sn, conf->entity.pdcp_xfrm.sn_size); + conf->entity.out_of_order_delivery = true; conf->entity.reverse_iv_direction = true; conf->entity.count =PDCP_SET_COUNT (new_hfn, new_sn, sn_size); conf->output_len =0 ;
@@ -913,6 +931,168 @@ test_sn_minus_outside(struct pdcp_test_conf *t_conf)return test_sn_range_type (SN_RANGE_MINUS_OUTSIDE , t_conf); } +static struct rte_mbuf * +generate_packet_for_dl_with_sn (struct pdcp_test_conf ul_conf,uint32_t sn) +{ +int ret; + + ul_conf.entity.count = sn; + ul_conf.entity.out_of_order_delivery = true; + ul_conf.entity.reverse_iv_direction = true; + ul_conf.output_len =0 ; + + ret =test_attempt_single (&ul_conf); +if (ret !=TEST_SUCCESS ) +return NULL ; + +return mbuf_from_data_create (ul_conf.output, ul_conf.output_len); +} + +static bool +array_asc_sorted_check (struct rte_mbuf *m[],uint32_t len,enum rte_security_pdcp_sn_size sn_size) +{ +uint32_t i; + +if (len <2 ) +return true; + +for (i =0 ; i < (len -1 ); i++) { + if (pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i], void *), sn_size) > + pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i + 1], void *), sn_size)) +return false; + } + +return true; +} + +static int +test_reorder_gap_fill (struct pdcp_test_conf *ul_conf) +{ +struct rte_mbuf *m0 =NULL , *m1 =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = start_count; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + +const uint32_t sn_size = dl_conf.entity.pdcp_xfrm.sn_size; + cdev_id = dl_conf.entity.dev_id; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Generate packet to fill the existing gap */ + m0 =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m0 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1] +* Gap filled, all packets should be returned +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m0,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m0 =NULL ;/* Packet was moved to out_mb */ + +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit, +"Error occurred during packet drain\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m0); +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} + +static int +test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +struct rte_mbuf *m1 =NULL , **out_mb =NULL ; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +const int rx_deliv =0 ; +int ret =TEST_FAILED ; +size_t i, nb_out; +uint8_t cdev_id; + +const uint32_t sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +const uint32_t window_size =PDCP_WINDOW_SIZE (sn_size); + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = rx_deliv; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + +ASSERT_TRUE_OR_GOTO (pdcp_entity->max_pkt_cache >= window_size, exit, +"PDCP max packet cache is too small" ); + cdev_id = dl_conf.entity.dev_id; + out_mb =rte_zmalloc (NULL , pdcp_entity->max_pkt_cache *sizeof (uintptr_t ),0 ); +ASSERT_TRUE_OR_GOTO (out_mb !=NULL , exit, +"Could not allocate buffer for holding out_mb buffers\n" ); + +/* Send packets with SN > RX_DELIV to create a gap */ +for (i = rx_deliv +1 ; i < window_size; i++) { + m1 =generate_packet_for_dl_with_sn (*ul_conf, i); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + } + + m1 =generate_packet_for_dl_with_sn (*ul_conf, rx_deliv); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Insert missing packet */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success == window_size, exit, +"Packet count mismatch (received: %i, expected: %i)\n" , + nb_success, window_size); + m1 =NULL ; + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +rte_free (out_mb); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -969,10 +1149,25 @@ static struct unit_test_suite hfn_sn_test_cases = { } }; +static struct unit_test_suite reorder_test_cases = { + .suite_name ="PDCP reorder" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_buffer_full_window_size_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_reorder_buffer_full_window_size_sn_12), +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, + &reorder_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
PATCH v2 15/22 pdcp: add timer callback handlers
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP has a windowing mechanism which allows only packets that fall in a reception window. The pivot point for this window is RX_REORD which happens to be the first missing or next expected packet. If the missing packet is not received after a specified time, then the RX_REORD state variable needs to be moved up to slide the reception window. PDCP relies on timers for such operations.
The timer needs to be armed when PDCP library doesn't receive all packets in-order and starts buffering packets that arrived after a missing packet. The timer needs to be cancelled when a missing packet is received.
To avoid dependency on particular timer implementation, PDCP library allows application to register two callbacks, timer_start() and timer_stop() that will be called later by library.
--- lib/pdcp/pdcp_entity.h | 2 ++ lib/pdcp/pdcp_process.c | 2 ++ lib/pdcp/rte_pdcp.c | 1 + lib/pdcp/rte_pdcp.h | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
@@ -120,6 +120,8 @@ enum timer_state {struct pdcp_t_reordering {/** Represent timer state */ enum timer_state state; +/** User defined callback handles */ +struct rte_pdcp_t_reordering handle; };struct pdcp_cnt_bitmap {
lib/pdcp/pdcp_process.c +2 -0
@@ -874,6 +874,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (t_reorder->state ==TIMER_RUNNING && en_priv->state.rx_deliv >= en_priv->state.rx_reord) { t_reorder->state =TIMER_STOP ; + t_reorder->handle.stop (t_reorder->handle.timer, t_reorder->handle.args);/* Stop reorder buffer, only if it's empty */ if (en_priv->state.rx_deliv == en_priv->state.rx_next)pdcp_reorder_stop (reorder);
@@ -888,6 +889,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, en_priv->state.rx_reord = en_priv->state.rx_next;/* Start t-Reordering */ t_reorder->state =TIMER_RUNNING ; + t_reorder->handle.start (t_reorder->handle.timer, t_reorder->handle.args); }return processed;
lib/pdcp/rte_pdcp.c +1 -0
@@ -36,6 +36,7 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cstruct entity_priv_dl_part *dl =entity_dl_part_get (entity); entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); + dl->t_reorder.handle = conf->t_reordering;return pdcp_reorder_create (&dl->reorder, window_size); }
lib/pdcp/rte_pdcp.h +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.25.1
RE: [PATCH v2 15/22] pdcp: add timer callback handlers
lib/pdcp/rte_pdcp.h struct rte_pdcp_entity { · line 110
Quoted 8 lines
lib/pdcp/rte_pdcp.h +8
-0+struct rte_pdcp_t_reordering { +/** Timer pointer, stored for later use in callback functions */ +void *timer; +/** Timer arguments, stored for later use in callback functions */ +void *args; +/** Timer start callback handle */ +rte_pdcp_t_reordering_start_cb_t start; +/** Timer start callback handle */
start->stop
Quoted 3 lines
lib/pdcp/rte_pdcp.h +3
-0+rte_pdcp_t_reordering_stop_cb_t stop; +}; +
PATCH v2 16/22 pdcp: add timer expiry handle
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
The PDCP protocol requires usage of timers to keep track of how long an out-of-order packet should be buffered while waiting for missing packets. Applications can register a desired timer implementation with the PDCP library. Once the timer expires, the application will be notified, and further handling of the event will be performed in the PDCP library.
When the timer expires, the PDCP library will return the cached packets, and PDCP internal state variables (like RX_REORD, RX_DELIV etc) will be updated accordingly.
--- doc/guides/prog_guide/pdcp_lib.rst | 29 ++++++++++++++++++ lib/pdcp/pdcp_process.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 31 +++++++++++++++++++ lib/pdcp/version.map | 2 ++ 4 files changed, 111 insertions(+)
doc/guides/prog_guide/pdcp_lib.rst +29 -0
@@ -229,6 +229,35 @@ parameters for entity creation. } } +Timers +------ + +PDCP utilizes a reception window mechanism to limit the bits of COUNT value +transmitted in the packet. It utilizes state variables such as RX_REORD, +RX_DELIV to define the window and uses RX_DELIV as the lower pivot point of the +window. + +RX_DELIV would be updated only when packets are received in-order. Any missing +packet would mean RX_DELIV won't be updated. A timer, t-Reordering, helps PDCP +to slide the window if the missing packet is not received in a specified time +duration. + +While starting and stopping the timer need to be done by lib PDCP, application +could register its own timer implementation. This is to make sure application +can choose between timers such as rte_timer and rte_event based timers. Starting +and stopping of timer would happen during pre & post process API. + +When the t-Reordering timer expires, application would receive the expiry event. +To perform the PDCP handling of the expiry event, +``rte_pdcp_t_reordering_expiry_handle`` can be used. Expiry handling would +involve sliding the window by updating state variables and passing the expired +packets to the application. + +.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h + :language: c + :start-after: Structure rte_pdcp_t_reordering 8< + :end-before: >8 End of structure rte_pdcp_t_reordering. + Supported features ------------------
lib/pdcp/pdcp_process.c +49 -0
52 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +31 -0
@@ -100,6 +100,7 @@ typedef void (*rte_pdcp_t_reordering_stop_cb_t)(void *timer, void *args);* * Configuration provided by user, that PDCP library will invoke according to timer behaviour. */ +/* Structure rte_pdcp_t_reordering 8< */ struct rte_pdcp_t_reordering {/** Timer pointer, stored for later use in callback functions */ void *timer;
@@ -110,6 +111,7 @@ struct rte_pdcp_t_reordering {/** Timer start callback handle */ rte_pdcp_t_reordering_stop_cb_t stop; }; +/* >8 End of structure rte_pdcp_t_reordering. */ /** * PDCP entity configuration to be used for establishing an entity.
@@ -327,6 +329,35 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,return entity->post_process (entity, in_mb, out_mb, num, nb_err); } +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* 5.2.2.2 Actions when a t-Reordering expires +* +* When t-Reordering timer expires, PDCP is required to slide the reception +* window by updating state variables such as RX_REORD & RX_DELIV. PDCP would +* need to deliver some of the buffered packets based on the state variables and +* conditions described. +* +* The expiry handle need to be invoked by the application when t-Reordering +* timer expires. In addition to returning buffered packets, it may also restart +* timer based on the state variables. +* +* @param entity +* Pointer to the *rte_pdcp_entity* for which the timer expired. +* @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. Used to return buffered packets that are +* expired. +* @return +* Number of packets returned in *out_mb* buffer. +*/ +__rte_experimental +uint16_t +rte_pdcp_t_reordering_expiry_handle (const struct rte_pdcp_entity *entity, +struct rte_mbuf *out_mb[]); +#include <rte_pdcp_group.h> #ifdef __cplusplus
lib/pdcp/version.map +2 -0
@@ -11,5 +11,7 @@ EXPERIMENTAL { rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_t_reordering_expiry_handle; + local: *; };
Signature · 1 line
2.25.1
RE: [PATCH v2 16/22] pdcp: add timer expiry handle
Quoted 81 lines
Subject: [PATCH v2 16/22] pdcp: add timer expiry handle
From: Volodymyr Fialko <[email protected]>
The PDCP protocol requires usage of timers to keep track of how long an out-of-order packet should be buffered while waiting for missing packets. Applications can register a desired timer implementation with the PDCP library. Once the timer expires, the application will be notified, and further handling of the event will be performed in the PDCP library.
When the timer expires, the PDCP library will return the cached packets, and PDCP internal state variables (like
RX_REORD,RX_DELIVetc) will be updated accordingly.Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>--- doc/guides/prog_guide/pdcp_lib.rst | 29 ++++++++++++++++++ lib/pdcp/pdcp_process.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 31 +++++++++++++++++++ lib/pdcp/version.map | 2 ++ 4 files changed, 111 insertions(+)doc/guides/prog_guide/pdcp_lib.rst +6
-0@@ -229,6 +229,35 @@ parameters for entity creation. } } +Timers +------ + +PDCP utilizes a reception window mechanism to limit the bits of COUNT value +transmitted in the packet. It utilizes state variables such as RX_REORD, +RX_DELIV to define the window and uses RX_DELIV as the lower pivot point ofthe
doc/guides/prog_guide/pdcp_lib.rst +3
-0+window. + +RX_DELIV would be updated only when packets are received in-order. Anymissing
+packet would meanRX_DELIVwon't be updated. A timer, t-Reordering, helps PDCPdoc/guides/prog_guide/pdcp_lib.rst +6
-0+to slide the window if the missing packet is not received in a specified time +duration. + +While starting and stopping the timer need to be done by lib PDCP, application +could register its own timer implementation. This is to make sure application +can choose between timers such as rte_timer and rte_event based timers.Starting
doc/guides/prog_guide/pdcp_lib.rst +3
-0+and stopping of timer would happen during pre & post process API. + +When the t-Reordering timer expires, application would receive the expiryevent.
doc/guides/prog_guide/pdcp_lib.rst +10
-0+To perform the PDCP handling of the expiry event, +``rte_pdcp_t_reordering_expiry_handle`` can be used. Expiry handling would +involve sliding the window by updating state variables and passing the expired +packets to the application. + +.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h + :language: c + :start-after: Structure rte_pdcp_t_reordering 8< + :end-before: >8 End of structure rte_pdcp_t_reordering. + Supported features ------------------lib/pdcp/pdcp_process.c +3
-0@@ -1285,3 +1285,52 @@ pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_enti return 0; } + +uint16_t +rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity,
Quoted 1 line
struct
rte_mbuf*out_mb[])
Move this public API implementation to rte_pdcp.c
Quoted 129 lines
lib/pdcp/pdcp_process.c +10
-0+{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); +uint16_t capacity = entity->max_pkt_cache; +uint16_t nb_out, nb_seq; + +/* 5.2.2.2 Actions when a t-Reordering expires */ + +/* +* - deliver to upper layers in ascending order of the associated COUNT value after
lib/pdcp/pdcp_process.c +4
-0+* performing header decompression, if not decompressed before: +*/ + +/* - all stored PDCP SDU(s) with associated COUNT value(s) <
RX_REORD; */lib/pdcp/pdcp_process.c +1
-0+ nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, capacity,
en_priv->state.rx_reord);lib/pdcp/pdcp_process.c +5
-0+ capacity -= nb_out; + out_mb = &out_mb[nb_out]; + +/* +* - all stored PDCP SDU(s) with consecutively associated COUNT value(s) starting from
lib/pdcp/pdcp_process.c +3
-0+* RX_REORD; +*/ + nb_seq = pdcp_reorder_get_sequential(&dl->reorder, out_mb,capacity);
lib/pdcp/pdcp_process.c +4
-0+ nb_out += nb_seq; + +/* +* - update RX_DELIV to the COUNT value of the first PDCP SDU which has not been delivered
lib/pdcp/pdcp_process.c +13
-0+* to upper layers, with COUNT value >= RX_REORD; +*/ + en_priv->state.rx_deliv = en_priv->state.rx_reord + nb_seq; + +/* +* - if RX_DELIV < RX_NEXT: +* - update RX_REORD to RX_NEXT; +* - start t-Reordering. +*/ +if (en_priv->state.rx_deliv < en_priv->state.rx_next) { + en_priv->state.rx_reord = en_priv->state.rx_next; + dl->t_reorder.state =TIMER_RUNNING ; + dl->t_reorder.handle.start(dl->t_reorder.handle.timer, dl-Quoted 1 line
t_reorder.handle.args);
lib/pdcp/pdcp_process.c +6
-0+ }else { + dl->t_reorder.state =TIMER_EXPIRED ; + } + +return nb_out; +}lib/pdcp/rte_pdcp.h +0
-0@@ -100,6 +100,7 @@ typedef void (*rte_pdcp_t_reordering_stop_cb_t)(void *timer, void *args); * * Configuration provided by user, that PDCP library will invoke according totimer behaviour.
*/lib/pdcp/rte_pdcp.h +10
-0+/* Structure rte_pdcp_t_reordering 8< */ struct rte_pdcp_t_reordering {/** Timer pointer, stored for later use in callback functions */ void *timer;@@ -110,6 +111,7 @@ struct rte_pdcp_t_reordering {/** Timer start callback handle */ rte_pdcp_t_reordering_stop_cb_t stop; }; +/* >8 End of structure rte_pdcp_t_reordering. */ /** * PDCP entity configuration to be used for establishing an entity. @@ -327,6 +329,35 @@ rte_pdcp_pkt_post_process(const structrte_pdcp_entity *entity, return entity->post_process(entity, in_mb, out_mb, num, nb_err); } +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* 5.2.2.2 Actions when a t-Reordering expires +* +* When t-Reordering timer expires, PDCP is required to slide the reception +* window by updating state variables such as RX_REORD & RX_DELIV. PDCP would
+ * need to deliver some of the buffered packets based on the state variables and
+ * conditions described.
+ *
+ * The expiry handle need to be invoked by the application when t-Reordering
+ * timer expires. In addition to returning buffered packets, it may also restart
+ * timer based on the state variables.
+ *
+ * @param entity
+ * Pointer to the *rte_pdcp_entity* for which the timer expired.
+ * @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. Used to return buffered packets that are
+ * expired.
+ * @return
+ * Number of packets returned in *out_mb* buffer.
+ */lib/pdcp/rte_pdcp.h +5
-0+__rte_experimental +uint16_t +rte_pdcp_t_reordering_expiry_handle (const struct rte_pdcp_entity *entity, +struct rte_mbuf *out_mb[]); +#include <rte_pdcp_group.h> #ifdef __cpluspluslib/pdcp/version.map +2
-1@@ -11,5 +11,7 @@ EXPERIMENTAL { rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_t_reordering_expiry_handle; + local: *; }; --2.25.1
RE: [PATCH v2 16/22] pdcp: add timer expiry handle
Hi Akhil,
Please see inline.
Thanks,
Anoob
Quoted 96 lines
-----Original Message-----
From: Akhil Goyal <[email protected]>
Sent: Thursday, May 18, 2023 3:13 PM
To: Anoob Joseph <[email protected]>; Thomas Monjalon <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>
Cc: Volodymyr Fialko <[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [PATCH v2 16/22] pdcp: add timer expiry handleQuoted 9 lines
Subject: [PATCH v2 16/22] pdcp: add timer expiry handle
From: Volodymyr Fialko <[email protected]>
The PDCP protocol requires usage of timers to keep track of how long an out-of-order packet should be buffered while waiting for missing packets. Applications can register a desired timer implementation with the PDCP library. Once the timer expires, the application will be notified, and further handling of the event will be performed in the PDCP
library.
Quoted 39 lines
When the timer expires, the PDCP library will return the cached packets, and PDCP internal state variables (like
RX_REORD,RX_DELIVetc) will be updated accordingly.Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>--- doc/guides/prog_guide/pdcp_lib.rst | 29 ++++++++++++++++++ lib/pdcp/pdcp_process.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 31 +++++++++++++++++++ lib/pdcp/version.map | 2 ++ 4 files changed, 111 insertions(+)doc/guides/prog_guide/pdcp_lib.rst +7
-0@@ -229,6 +229,35 @@ parameters for entity creation. } } +Timers +------ + +PDCP utilizes a reception window mechanism to limit the bits of COUNT +value transmitted in the packet. It utilizes state variables such as +RX_REORD, RX_DELIV to define the window and uses RX_DELIV as the +lower pivot point ofthe
doc/guides/prog_guide/pdcp_lib.rst +4
-0+window. + +RX_DELIV would be updated only when packets are received in-order. +Anymissing
doc/guides/prog_guide/pdcp_lib.rst +2
-0+packet would mean RX_DELIV won't be updated. A timer, t-Reordering, +helpsPDCP
doc/guides/prog_guide/pdcp_lib.rst
Quoted 6 lines
doc/guides/prog_guide/pdcp_lib.rst +6
-0+to slide the window if the missing packet is not received in a +specified time duration. + +While starting and stopping the timer need to be done by lib PDCP, +application could register its own timer implementation. This is to +make sure application can choose between timers such as rte_timer and
rte_eventbased timers.Quoted 26 lines
Starting
doc/guides/prog_guide/pdcp_lib.rst +4
-0+and stopping of timer would happen during pre & post process API. + +When the t-Reordering timer expires, application would receive the +expiryevent.
doc/guides/prog_guide/pdcp_lib.rst +10
-0+To perform the PDCP handling of the expiry event, +``rte_pdcp_t_reordering_expiry_handle`` can be used. Expiry handling +would involve sliding the window by updating state variables and +passing the expired packets to the application. + +.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h + :language: c + :start-after: Structure rte_pdcp_t_reordering 8< + :end-before: >8 End of structure rte_pdcp_t_reordering. + Supported features ------------------lib/pdcp/pdcp_process.c index renamed from lib/pdcp/pdcp_process.c +0
-0
9ba07d5255..91b87a2a81100644lib/pdcp/pdcp_process.c +0
-0@@ -1285,3 +1285,52 @@ pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_enti
Quoted 9 lines
Quoted 7 lines
lib/pdcp/pdcp_process.c +4
-0return 0 ; } + +uint16_t +rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity +*entity,struct
rte_mbuf*out_mb[])Move this public API implementation to
rte_pdcp.c
[Anoob] Agreed. Will make this change in next version.
Quoted 139 lines
Quoted 31 lines
lib/pdcp/pdcp_process.c +11
-0+{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); +uint16_t capacity = entity->max_pkt_cache; +uint16_t nb_out, nb_seq; + +/* 5.2.2.2 Actions when a t-Reordering expires */ + +/* +* - deliver to upper layers in ascending order of the associated +COUNT value after
lib/pdcp/pdcp_process.c +4
-0+* performing header decompression, if not decompressed before: +*/ + +/* - all stored PDCP SDU(s) with associated COUNT value(s) <
RX_REORD; */lib/pdcp/pdcp_process.c +1
-0+ nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, capacity,
en_priv->state.rx_reord);lib/pdcp/pdcp_process.c +5
-0+ capacity -= nb_out; + out_mb = &out_mb[nb_out]; + +/* +* - all stored PDCP SDU(s) with consecutively associated COUNT value(s) starting from
lib/pdcp/pdcp_process.c +3
-0+* RX_REORD; +*/ + nb_seq = pdcp_reorder_get_sequential(&dl->reorder, out_mb,capacity);
lib/pdcp/pdcp_process.c pdcp_process_func_set(struct rte_pdcp_entity *entity, const struct rte_pdcp_enti
Quoted 4 lines
lib/pdcp/pdcp_process.c +4
-0+ nb_out += nb_seq; + +/* +* - update RX_DELIV to the COUNT value of the first PDCP SDU which
Quoted 67 lines
has not been delivered
lib/pdcp/pdcp_process.c +13
-0+* to upper layers, with COUNT value >= RX_REORD; +*/ + en_priv->state.rx_deliv = en_priv->state.rx_reord + nb_seq; + +/* +* - if RX_DELIV < RX_NEXT: +* - update RX_REORD to RX_NEXT; +* - start t-Reordering. +*/ +if (en_priv->state.rx_deliv < en_priv->state.rx_next) { + en_priv->state.rx_reord = en_priv->state.rx_next; + dl->t_reorder.state =TIMER_RUNNING ; + dl->t_reorder.handle.start(dl->t_reorder.handle.timer, dl-Quoted 1 line
t_reorder.handle.args);
lib/pdcp/pdcp_process.c +6
-0+ }else { + dl->t_reorder.state =TIMER_EXPIRED ; + } + +return nb_out; +}lib/pdcp/rte_pdcp.h index renamed from lib/pdcp/rte_pdcp.h +0
-0
55e57c3b9b..c077acce63100644lib/pdcp/rte_pdcp.h +0
-0@@ -100,6 +100,7 @@ typedef void(*rte_pdcp_t_reordering_stop_cb_t)(void
*timer, void *args);
*
* Configuration provided by user, that PDCP library will invoke
according to timer behaviour.
*/lib/pdcp/rte_pdcp.h +12
-0+/* Structure rte_pdcp_t_reordering 8< */ struct rte_pdcp_t_reordering {/** Timer pointer, stored for later use in callback functions */ void *timer;@@ -110,6 +111,7 @@ struct rte_pdcp_t_reordering {/** Timer start callback handle */ rte_pdcp_t_reordering_stop_cb_t stop; }; +/* >8 End of structure rte_pdcp_t_reordering. */ /** * PDCP entity configuration to be used for establishing an entity. @@ -327,6 +329,35 @@ rte_pdcp_pkt_post_process(const structrte_pdcp_entity *entity, return entity->post_process(entity, in_mb, out_mb, num, nb_err); } +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* 5.2.2.2 Actions when a t-Reordering expires +* +* When t-Reordering timer expires, PDCP is required to slide the +reception +* window by updating state variables such as RX_REORD & RX_DELIV. +PDCP would
+ * need to deliver some of the buffered packets based on the state
+ variables
and
+ * conditions described.
+ *
+ * The expiry handle need to be invoked by the application when
+ t-Reordering
+ * timer expires. In addition to returning buffered packets, it may
+ also restartQuoted 8 lines
+ * timer based on the state variables.
+ *
+ * @param entity
+ * Pointer to the *rte_pdcp_entity* for which the timer expired.
+ * @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. Used to return buffered packetsthat are
lib/pdcp/rte_pdcp.h rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,
Quoted 7 lines
+ * expired.
+ * @return
+ * Number of packets returned in *out_mb* buffer.
+ */lib/pdcp/rte_pdcp.h +3
-0+__rte_experimental +uint16_t +rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity*entity,
Quoted 19 lines
lib/pdcp/rte_pdcp.h +2
-0+ struct rte_mbuf *out_mb[]); +#include <rte_pdcp_group.h> #ifdef __cpluspluslib/pdcp/version.map index renamed from lib/pdcp/version.map +0
-0
d0cf338e1f..89b0463be6100644lib/pdcp/version.map +2
-1@@ -11,5 +11,7 @@ EXPERIMENTAL { rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_t_reordering_expiry_handle; + local: *; }; --2.25.1
PATCH v2 17/22 test/pdcp: add timer expiry cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases for handling the expiry with rte_timer and rte_event_timer.
--- app/test/test_pdcp.c | 325 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+)
app/test/test_pdcp.c +325 -0
@@ -3,15 +3,22 @@*/ #include <rte_errno.h> +#include <rte_eventdev.h> +#include <rte_event_timer_adapter.h> #include <rte_malloc.h> #include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include <rte_timer.h> #include "test.h" #include "test_cryptodev.h" #include "test_cryptodev_security_pdcp_test_vectors.h" +#define NSECPERSEC 1E9#define NB_DESC 1024 +#define TIMER_ADAPTER_ID 0 +#define TEST_EV_QUEUE_ID 0 +#define TEST_EV_PORT_ID 0#define CDEV_INVALID_ID UINT8_MAX#define NB_TESTS RTE_DIM(pdcp_test_params)
@@ -32,10 +39,19 @@ struct pdcp_testsuite_params {struct rte_mempool *cop_pool;struct rte_mempool *sess_pool;bool cdevs_used[RTE_CRYPTO_MAX_DEVS ]; +int evdev; +struct rte_event_timer_adapter *timdev; +bool timer_is_running; +uint64_t min_resolution_ns; };static struct pdcp_testsuite_params testsuite_params; +struct test_rte_timer_args { +int status; +struct rte_pdcp_entity *pdcp_entity; +}; +struct pdcp_test_conf {struct rte_pdcp_entity_conf entity;struct rte_crypto_sym_xform c_xfrm;
@@ -99,6 +115,30 @@ run_test_with_all_known_vec_until_first_pass(const void *args)return run_test_foreach_known_vec (test, true); } +static void +pdcp_timer_start_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = true; +} + +static void +pdcp_timer_stop_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = false; +} + +static struct rte_pdcp_t_reordering t_reorder_timer = { + .timer = &testsuite_params.timer_is_running, + .start = pdcp_timer_start_cb, + .stop = pdcp_timer_stop_cb, +}; +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -437,6 +477,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf) conf->entity.pdcp_xfrm.en_ordering =0 ; conf->entity.pdcp_xfrm.remove_duplicates =0 ; conf->entity.pdcp_xfrm.domain = pdcp_test_params[index].domain; + conf->entity.t_reordering = t_reorder_timer;if (pdcp_test_packet_direction[index] ==PDCP_DIR_UPLINK ) conf->entity.pdcp_xfrm.pkt_dir =RTE_SECURITY_PDCP_UPLINK ;
@@ -1018,6 +1059,8 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)/* Check that packets in correct order */ ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == false, exit, +"Timer should be stopped after full drain\n" ); ret =TEST_SUCCESS ; exit:
@@ -1093,6 +1136,170 @@ test_reorder_buffer_full_window_size_sn_12(const struct pdcp_test_conf *ul_conf)return ret; } +static void +event_timer_start_cb (void *timer,void *args) +{ +struct rte_event_timer *evtims = args; +int ret =0 ; + + ret =rte_event_timer_arm_burst (timer, &evtims,1 ); +assert (ret ==1 ); +} + +static int +test_expiry_with_event_timer (const struct pdcp_test_conf *ul_conf) +{ +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_event event; + +const int start_count =0 ; +struct rte_event_timer evtim = { + .ev.op =RTE_EVENT_OP_NEW , + .ev.queue_id =TEST_EV_QUEUE_ID , + .ev.sched_type =RTE_SCHED_TYPE_ATOMIC , + .ev.priority =RTE_EVENT_DEV_PRIORITY_NORMAL , + .ev.event_type =RTE_EVENT_TYPE_TIMER , + .state =RTE_EVENT_TIMER_NOT_ARMED , + .timeout_ticks =1 , + }; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = start_count; + dl_conf.entity.t_reordering.args = &evtim; + dl_conf.entity.t_reordering.timer = testsuite_params.timdev; + dl_conf.entity.t_reordering.start = event_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + evtim.ev.event_ptr = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +while (n !=1 ) { +rte_delay_us (testsuite_params.min_resolution_ns /1000 ); + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit, +"Dequeued unexpected timer expiry event: %i\n" , n); + } + +ASSERT_TRUE_OR_GOTO (event.event_type ==RTE_EVENT_TYPE_TIMER , exit,"Unexpected event type\n" ); + +/* Handle expiry event */ + n =rte_pdcp_t_reordering_expiry_handle (event.event_ptr, out_mb); +ASSERT_TRUE_OR_GOTO (n ==1 , exit,"Unexpected number of expired packets :%i\n" , n); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} + +static void +test_rte_timer_expiry_handle (struct rte_timer *tim,void *arg) +{ +struct test_rte_timer_args *tim_data = arg; +struct rte_mbuf *out_mb[1 ] = {0 }; +uint16_t n; + +RTE_SET_USED (tim); + + n =rte_pdcp_t_reordering_expiry_handle (tim_data->pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, n); + + tim_data->status = n ==1 ? n :-1 ; +} + +static void +test_rte_timer_start_cb (void *timer,void *args) +{ +rte_timer_reset_sync (timer,1 ,SINGLE ,rte_lcore_id (), test_rte_timer_expiry_handle, args); +} + +static int +test_expiry_with_rte_timer (const struct pdcp_test_conf *ul_conf) +{ +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct test_rte_timer_args timer_args; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_timer timer = {0 }; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Set up a timer */ +rte_timer_init (&timer); + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = start_count; + dl_conf.entity.t_reordering.args = &timer_args; + dl_conf.entity.t_reordering.timer = &timer; + dl_conf.entity.t_reordering.start = test_rte_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + timer_args.status =0 ; + timer_args.pdcp_entity = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Verify that expire was handled correctly */ +rte_timer_manage (); +while (timer_args.status !=1 ) { +rte_delay_us (1 ); +rte_timer_manage (); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit,"Bad expire handle status %i\n" , + timer_args.status); + } + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1115,6 +1322,116 @@ test_combined(struct pdcp_test_conf *ul_conf)return ret; } +static inline void +eventdev_conf_default_set (struct rte_event_dev_config *dev_conf,struct rte_event_dev_info *info) +{ +memset (dev_conf,0 ,sizeof (struct rte_event_dev_config )); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports =1 ; + dev_conf->nb_event_queues =1 ; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = info->max_num_events; +} + +static inline int +eventdev_setup (void ) +{ +struct rte_event_dev_config dev_conf; +struct rte_event_dev_info info; +int ret, evdev =0 ; + +if (!rte_event_dev_count ()) +return TEST_SKIPPED ; + + ret =rte_event_dev_info_get (evdev, &info); +TEST_ASSERT_SUCCESS (ret,"Failed to get event dev info" ); +TEST_ASSERT (info.max_num_events <0 || info.max_num_events >=1 , +"ERROR max_num_events=%d < max_events=%d" , info.max_num_events,1 ); + +eventdev_conf_default_set (&dev_conf, &info); + ret =rte_event_dev_configure (evdev, &dev_conf); +TEST_ASSERT_SUCCESS (ret,"Failed to configure eventdev" ); + + ret =rte_event_queue_setup (evdev,TEST_EV_QUEUE_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup queue=%d" ,TEST_EV_QUEUE_ID ); + +/* Configure event port */ + ret =rte_event_port_setup (evdev,TEST_EV_PORT_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup port=%d" ,TEST_EV_PORT_ID ); + ret =rte_event_port_link (evdev,TEST_EV_PORT_ID ,NULL ,NULL ,0 ); +TEST_ASSERT (ret >=0 ,"Failed to link all queues port=%d" ,TEST_EV_PORT_ID ); + + ret =rte_event_dev_start (evdev); +TEST_ASSERT_SUCCESS (ret,"Failed to start device" ); + + testsuite_params.evdev = evdev; + +return TEST_SUCCESS ; +} + +static int +event_timer_setup (void ) +{ +struct rte_event_timer_adapter_info info; +struct rte_event_timer_adapter *timdev; +uint32_t caps =0 ; + +struct rte_event_timer_adapter_conf config = { + .event_dev_id = testsuite_params.evdev, + .timer_adapter_id =TIMER_ADAPTER_ID , + .timer_tick_ns =NSECPERSEC , + .max_tmo_ns =10 *NSECPERSEC , + .nb_timers =10 , + .flags =0 , + }; + +TEST_ASSERT_SUCCESS (rte_event_timer_adapter_caps_get (testsuite_params.evdev, &caps), +"Failed to get adapter capabilities" ); + +if (!(caps &RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT )) +return TEST_SKIPPED ; + + timdev =rte_event_timer_adapter_create (&config); + +TEST_ASSERT_NOT_NULL (timdev,"Failed to create event timer ring" ); + + testsuite_params.timdev = timdev; + +TEST_ASSERT_EQUAL (rte_event_timer_adapter_start (timdev),0 , +"Failed to start event timer adapter" ); + +rte_event_timer_adapter_get_info (timdev, &info); + testsuite_params.min_resolution_ns = info.min_resolution_ns; + +return TEST_SUCCESS ; +} + +static int +ut_setup_pdcp_event_timer (void ) +{ +int ret; + ret =eventdev_setup (); +if (ret) +return ret; +return event_timer_setup (); +} + +static void +ut_teardown_pdcp_event_timer (void ) +{ +struct rte_event_timer_adapter *timdev = testsuite_params.timdev; +int evdev = testsuite_params.evdev; + +rte_event_dev_stop (evdev); +rte_event_dev_close (evdev); + +rte_event_timer_adapter_stop (timdev); +rte_event_timer_adapter_free (timdev); +} +static int run_test_for_one_known_vec (const void *arg) {
@@ -1159,6 +1476,14 @@ static struct unit_test_suite reorder_test_cases = { ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass, test_reorder_buffer_full_window_size_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_event_timer" , + ut_setup_pdcp_event_timer, ut_teardown_pdcp_event_timer, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_event_timer), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_rte_timer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_rte_timer), TEST_CASES_END() /**< NULL terminate unit test array */ } };
Signature · 1 line
2.25.1
PATCH v2 18/22 test/pdcp: add timer restart case
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test to cover the case when t-reordering timer should be restarted on the same packet.
--- app/test/test_pdcp.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
app/test/test_pdcp.c +67 -0
@@ -1072,6 +1072,70 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)return ret; } +static int +test_reorder_gap_in_reorder_buffer (const struct pdcp_test_conf *ul_conf) +{ +struct rte_mbuf *m =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +int ret =TEST_FAILED , nb_out, i; +struct pdcp_test_conf dl_conf; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = start_count; + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + +const uint32_t sn_size = dl_conf.entity.pdcp_xfrm.sn_size; + cdev_id = dl_conf.entity.dev_id; + +/* Create two gaps [NULL, m1, NULL, m3]*/ +for (i =0 ; i <2 ; i++) { + m =generate_packet_for_dl_with_sn (*ul_conf, start_count +2 * i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m =NULL ;/* Packet was moved to PDCP lib */ + } + +/* Generate packet to fill the first gap */ + m =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1, NULL, m3] +* Only first gap should be filled, timer should be restarted for second gap +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m =NULL ; +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), + exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == true, exit, +"Timer should be restarted after partial drain" ); + + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) {
@@ -1472,6 +1536,9 @@ static struct unit_test_suite reorder_test_cases = {TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_in_reorder_buffer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_in_reorder_buffer), TEST_CASE_NAMED_WITH_DATA("test_reorder_buffer_full_window_size_sn_12", ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass,
Signature · 1 line
2.25.1
PATCH v2 19/22 pdcp: add support for status report
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Implement status report generation for PDCP entity.
--- lib/pdcp/pdcp_cnt.c | 158 ++++++++++++++++++++++++++++++++++++--- lib/pdcp/pdcp_cnt.h | 11 ++- lib/pdcp/pdcp_ctrl_pdu.c | 34 ++++++++- lib/pdcp/pdcp_ctrl_pdu.h | 3 +- lib/pdcp/pdcp_entity.h | 2 + lib/pdcp/pdcp_process.c | 21 +++++- lib/pdcp/rte_pdcp.c | 32 ++++++-- 7 files changed, 233 insertions(+), 28 deletions(-)
lib/pdcp/pdcp_cnt.c +147 -11
@@ -2,28 +2,164 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_pdcp.h> #include "pdcp_cnt.h" +#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#define SLAB_BYTE_SIZE (RTE_BITMAP_SLAB_BIT_SIZE / 8) + +uint32_t +pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf) +{ +uint32_t n_bits =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); + +return rte_bitmap_get_memory_footprint (n_bits); +} +int -pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) { -struct entity_priv_dl_part *en_priv_dl; -uint32_t window_sz; +uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); -if (en ==NULL || conf ==NULL ) + dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); +if (dl->bitmap.bmp ==NULL )return -EINVAL ; -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) -return 0 ; + dl->bitmap.size = window_size; - en_priv_dl =entity_dl_part_get (en); - window_sz =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); +return 0 ; +} -RTE_SET_USED (window_sz); -RTE_SET_USED (en_priv_dl); +void +pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +rte_bitmap_set (bitmap.bmp, count % bitmap.size); +} -return 0 ; +bool +pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +return rte_bitmap_get (bitmap.bmp, count % bitmap.size); +} + +void +pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop) +{ +uint32_t i; + +for (i = start; i < stop; i++) +rte_bitmap_clear (bitmap.bmp, i % bitmap.size); +} + +uint16_t +pdcp_cnt_get_bitmap_size (uint32_t pending_bytes) +{ +/* +* Round up bitmap size to slab size to operate only on slabs sizes, instead of individual +* bytes +*/ +return RTE_ALIGN_MUL_CEIL (pending_bytes,SLAB_BYTE_SIZE ); +} + +static __rte_always_inline uint64_t +leftover_get (uint64_t slab,uint32_t shift,uint64_t mask) +{ +return (slab & mask) << shift; +} + +void +pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len) +{ +uint64_t slab =0 , next_slab =0 , leftover; +uint32_t zeros, report_len, diff; +uint32_t slab_id, next_slab_id; +uint32_t pos =0 , next_pos =0 ; + +const uint32_t start_count = state.rx_deliv +1 ; +const uint32_t nb_slabs = bitmap.size /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t nb_data_slabs = data_len /SLAB_BYTE_SIZE ; +const uint32_t start_slab_id = start_count /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t stop_slab_id = (start_slab_id + nb_data_slabs) % nb_slabs; +const uint32_t shift = start_count %RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t leftover_shift = shift ?RTE_BITMAP_SLAB_BIT_SIZE - shift :0 ; +const uint8_t *data_end =RTE_PTR_ADD (data, data_len +SLAB_BYTE_SIZE ); + +/* NOTE: Mask required to workaround case - when shift is not needed */ +const uint64_t leftover_mask = shift ? ~0 :0 ; + +/* NOTE: implement scan init at to set custom position */ +__rte_bitmap_scan_init (bitmap.bmp); +while (true) { +assert (rte_bitmap_scan (bitmap.bmp, &pos, &slab) ==1 ); + slab_id = pos /RTE_BITMAP_SLAB_BIT_SIZE ; +if (slab_id >= start_slab_id) +break ; + } + + report_len = nb_data_slabs; + +if (slab_id > start_slab_id) { +/* Zero slabs at beginning */ + zeros = (slab_id - start_slab_id -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + leftover =leftover_get (slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + report_len -= (slab_id - start_slab_id); + } + +while (report_len) { +rte_bitmap_scan (bitmap.bmp, &next_pos, &next_slab); + next_slab_id = next_pos /RTE_BITMAP_SLAB_BIT_SIZE ; + diff = (next_slab_id + nb_slabs - slab_id) % nb_slabs; + +/* If next_slab_id == slab_id - overlap */ + diff += !(next_slab_id ^ slab_id) * nb_slabs; + +/* Size check - next slab is outsize of size range */ +if (diff > report_len) { + next_slab =0 ; + next_slab_id = stop_slab_id; + diff = report_len; + } + + report_len -= diff; + +/* Calculate gap between slabs, taking wrap around into account */ + zeros = (next_slab_id + nb_slabs - slab_id -1 ) % nb_slabs; +if (zeros) { +/* Non continues slabs, align them individually */ + slab >>= shift; +memcpy (data, &slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + +/* Fill zeros between slabs */ + zeros = (zeros -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + +/* Align beginning of next slab */ + leftover =leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + }else { +/* Continues slabs, combine them */ +uint64_t new_slab = (slab >> shift) | +leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &new_slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + } + + slab = next_slab; + pos = next_pos; + slab_id = next_slab_id; + + }; + +assert (data < data_end); }
lib/pdcp/pdcp_cnt.h +10 -1
@@ -9,6 +9,15 @@#include "pdcp_entity.h" -int pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf); +uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); + +void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +void pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop); + +uint16_t pdcp_cnt_get_bitmap_size (uint32_t pending_bytes); +void pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len);#endif /* PDCP_CNT_H */
lib/pdcp/pdcp_ctrl_pdu.c +30 -4
@@ -8,6 +8,14 @@#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#include "pdcp_cnt.h" + +static inline uint16_t +round_up_bits (uint32_t bits) +{ +/* round up to the next multiple of 8 */ +return RTE_ALIGN_MUL_CEIL (bits,8 ) /8 ; +} static __rte_always_inline voidpdcp_hdr_fill (struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr,uint32_t rx_deliv)
@@ -19,11 +27,13 @@ pdcp_hdr_fill(struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr, uint32_t rx_deliv) }int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m) +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m) {struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr; -uint32_t rx_deliv; -int pdu_sz; +uint32_t rx_deliv, actual_sz; +uint16_t pdu_sz, bitmap_sz; +uint8_t *data;if (!en_priv->flags.is_status_report_required)return -EINVAL ;
@@ -42,5 +52,21 @@ pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m)return 0 ; } -return -ENOTSUP ; + actual_sz =RTE_MIN (round_up_bits (en_priv->state.rx_next - rx_deliv -1 ), +RTE_PDCP_CTRL_PDU_SIZE_MAX - pdu_sz); + bitmap_sz =pdcp_cnt_get_bitmap_size (actual_sz); + + data = (uint8_t *)rte_pktmbuf_append (m, pdu_sz + bitmap_sz); +if (data ==NULL ) +return -ENOMEM ; + + m->pkt_len = pdu_sz + actual_sz; + m->data_len = pdu_sz + actual_sz; + +pdcp_hdr_fill ((struct rte_pdcp_up_ctrl_pdu_hdr *)data, rx_deliv); + + data =RTE_PTR_ADD (data, pdu_sz); +pdcp_cnt_report_fill (dl->bitmap, en_priv->state, data, bitmap_sz); + +return 0 ; }
lib/pdcp/pdcp_ctrl_pdu.h +2 -1
@@ -10,6 +10,7 @@#include "pdcp_entity.h" int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m); +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m);#endif /* PDCP_CTRL_PDU_H */
lib/pdcp/pdcp_entity.h +2 -0
@@ -182,6 +182,8 @@ struct entity_priv_dl_part {struct pdcp_t_reordering t_reorder;/** Reorder packet buffer */ struct pdcp_reorder reorder; +/** Bitmap memory region */ +uint8_t bitmap_mem[0 ]; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +18 -3
@@ -9,6 +9,7 @@#include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include "pdcp_cnt.h" #include "pdcp_crypto.h" #include "pdcp_entity.h" #include "pdcp_process.h"
@@ -809,6 +810,16 @@ pdcp_packet_strip(struct rte_mbuf *mb, const uint32_t hdr_trim_sz, const bool tr } } +static inline void +pdcp_rx_deliv_set (const struct rte_pdcp_entity *entity,uint32_t rx_deliv) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +pdcp_cnt_bitmap_range_clear (dl->bitmap, en_priv->state.rx_deliv, rx_deliv); + en_priv->state.rx_deliv = rx_deliv; +} + static inline int pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, const uint32_t count, struct rte_mbuf *mb,
@@ -829,11 +840,15 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (count >= en_priv->state.rx_next) en_priv->state.rx_next = count +1 ; +if (unlikely (pdcp_cnt_bitmap_is_set (dl->bitmap, count))) +return -EEXIST ; + +pdcp_cnt_bitmap_set (dl->bitmap, count);pdcp_packet_strip (mb, hdr_trim_sz, trim_mac);if (en_priv->flags.is_out_of_order_delivery) { out_mb[0 ] = mb; - en_priv->state.rx_deliv = count +1 ; +pdcp_rx_deliv_set (entity, count +1 );return 1 ; }
@@ -860,7 +875,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, }/* Processed should never exceed the window size */ - en_priv->state.rx_deliv = count + processed; +pdcp_rx_deliv_set (entity, count + processed); }else {if (!reorder->is_active)
@@ -1317,7 +1332,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* - update RX_DELIV to the COUNT value of the first PDCP SDU which has not been delivered * to upper layers, with COUNT value >= RX_REORD; */ - en_priv->state.rx_deliv = en_priv->state.rx_reord + nb_seq; +pdcp_rx_deliv_set (entity, en_priv->state.rx_reord + nb_seq);/* * - if RX_DELIV < RX_NEXT:
lib/pdcp/rte_pdcp.c +24 -8
@@ -12,6 +12,8 @@#include "pdcp_entity.h" #include "pdcp_process.h" +static int bitmap_mem_offset; +static int pdcp_entity_size_get (const struct rte_pdcp_entity_conf *conf) {
@@ -19,9 +21,12 @@ pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) size =sizeof (struct rte_pdcp_entity ) +sizeof (struct entity_priv ); -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +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 =RTE_CACHE_LINE_ROUNDUP (size); + bitmap_mem_offset = size; + size +=pdcp_cnt_bitmap_get_memory_footprint (conf); + }else if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) size +=sizeof (struct entity_priv_ul_part );else return -EINVAL ;
@@ -34,11 +39,24 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_c {const uint32_t window_size =pdcp_window_size_get (conf->pdcp_xfrm.sn_size);struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +void *bitmap_mem; +int ret; entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); dl->t_reorder.handle = conf->t_reordering; -return pdcp_reorder_create (&dl->reorder, window_size); + ret =pdcp_reorder_create (&dl->reorder, window_size); +if (ret) +return ret; + + bitmap_mem =RTE_PTR_ADD (entity, bitmap_mem_offset); + ret =pdcp_cnt_bitmap_create (dl, bitmap_mem, window_size); +if (ret) { +pdcp_reorder_destroy (&dl->reorder); +return ret; + } + +return 0 ; } struct rte_pdcp_entity *
@@ -110,10 +128,6 @@ rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) goto crypto_sess_destroy; } - ret =pdcp_cnt_ring_create (entity, conf); -if (ret) - goto crypto_sess_destroy; -return entity; crypto_sess_destroy:
@@ -192,6 +206,7 @@ struct rte_mbuf * rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, enum rte_pdcp_ctrl_pdu_type type) { +struct entity_priv_dl_part *dl;struct entity_priv *en_priv;struct rte_mbuf *m;int ret;
@@ -202,6 +217,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, } en_priv =entity_priv_get (pdcp_entity); + dl =entity_dl_part_get (pdcp_entity); m =rte_pktmbuf_alloc (en_priv->ctr_pdu_pool);if (m ==NULL ) {
@@ -211,7 +227,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,switch (type) {case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT : - ret =pdcp_ctrl_pdu_status_gen (en_priv, m); + ret =pdcp_ctrl_pdu_status_gen (en_priv, dl, m);break ;default : ret = -ENOTSUP ;
Signature · 1 line
2.25.1
PATCH v2 20/22 pdcp: allocate reorder buffer alongside with entity
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Instead of allocating reorder buffer separately on heap, allocate memory for it together with rest of entity, and then only initialize buffer via rte_reorder_init().
--- lib/pdcp/pdcp_cnt.c | 9 +++---- lib/pdcp/pdcp_cnt.h | 3 ++- lib/pdcp/pdcp_entity.h | 2 +- lib/pdcp/pdcp_reorder.c | 11 ++------ lib/pdcp/pdcp_reorder.h | 12 ++++++--- lib/pdcp/rte_pdcp.c | 58 ++++++++++++++++++++++++++--------------- 6 files changed, 55 insertions(+), 40 deletions(-)
lib/pdcp/pdcp_cnt.c +4 -5
@@ -20,15 +20,14 @@ pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf *conf) }int -pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size) { -uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); - - dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); + dl->bitmap.bmp =rte_bitmap_init (nb_elem, bitmap_mem, mem_size);if (dl->bitmap.bmp ==NULL )return -EINVAL ; - dl->bitmap.size = window_size; + dl->bitmap.size = nb_elem;return 0 ; }
lib/pdcp/pdcp_cnt.h +2 -1
@@ -10,7 +10,8 @@#include "pdcp_entity.h" uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); -int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size);void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);
lib/pdcp/pdcp_entity.h +1 -1
@@ -132,7 +132,7 @@ struct pdcp_cnt_bitmap { };/* -* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] +* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] [reorder/bitmap] */ struct entity_priv {
lib/pdcp/pdcp_reorder.c +2 -9
@@ -8,20 +8,13 @@#include "pdcp_reorder.h" int -pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size) { - reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); + reorder->buf =rte_reorder_init (mem, mem_size,"reorder_buffer" , nb_elem);if (reorder->buf ==NULL )return -rte_errno; - reorder->window_size = window_size; reorder->is_active = false;return 0 ; } - -void -pdcp_reorder_destroy (const struct pdcp_reorder *reorder) -{ -rte_reorder_free (reorder->buf); -}
lib/pdcp/pdcp_reorder.h +9 -3
@@ -9,12 +9,18 @@struct pdcp_reorder {struct rte_reorder_buffer *buf; -uint32_t window_size;bool is_active; }; -int pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size); -void pdcp_reorder_destroy (const struct pdcp_reorder *reorder); +int pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size); + +/* NOTE: replace with `rte_reorder_memory_footprint_get` after DPDK 23.07 */ +#define SIZE_OF_REORDER_BUFFER (4 * RTE_CACHE_LINE_SIZE) +static inline size_t +pdcp_reorder_memory_footprint_get (size_t nb_elem) +{ +return SIZE_OF_REORDER_BUFFER + (2 * nb_elem *sizeof (struct rte_mbuf *)); +} static inline uint32_t pdcp_reorder_get_sequential(struct pdcp_reorder *reorder, struct rte_mbuf **mbufs,
lib/pdcp/rte_pdcp.c +37 -21
123 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v2 21/22 pdcp: add thread safe processing
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP state has to be guarded for:
- Uplink pre_process:
- tx_next atomic increment
- Downlink pre_process:
- rx_deliv - read
- Downlink post_process:
- rx_deliv, rx_reorder, rx_next - read/write
- bitmask/reorder buffer - read/write
When application requires thread safe processing, the state variables need to be updated atomically. Add config option to select this option per entity.
--- lib/pdcp/pdcp_entity.h | 46 +++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 34 +++++++++++++++++++++++++++--- lib/pdcp/rte_pdcp.c | 2 ++ lib/pdcp/rte_pdcp.h | 2 ++ 4 files changed, 81 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_entity.h +46 -0
@@ -10,6 +10,7 @@#include <rte_mempool.h> #include <rte_pdcp.h> #include <rte_security.h> +#include <rte_spinlock.h> #include "pdcp_reorder.h"
@@ -162,6 +163,8 @@ struct entity_priv { uint64_t is_status_report_required : 1;/** Is out-of-order delivery enabled */ uint64_t is_out_of_order_delivery : 1; +/** Is thread safety disabled */ + uint64_t is_thread_safety_disabled : 1; } flags;/** Crypto op pool. */ struct rte_mempool *cop_pool;
@@ -175,6 +178,8 @@ struct entity_priv {uint8_t dev_id; }; +typedef rte_spinlock_t pdcp_lock_t ; +struct entity_priv_dl_part {/** PDCP would need to track the count values that are already received.*/ struct pdcp_cnt_bitmap bitmap;
@@ -182,6 +187,8 @@ struct entity_priv_dl_part {struct pdcp_t_reordering t_reorder;/** Reorder packet buffer */ struct pdcp_reorder reorder; +/* Lock to protect concurrent updates */ +pdcp_lock_t lock;/** Bitmap memory region */ uint8_t bitmap_mem[0 ]; };
@@ -257,4 +264,43 @@ pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size)return (1 << (32 - sn_size)) -1 ; } +static inline uint32_t +pdcp_atomic_inc (const struct entity_priv *en_priv,uint32_t *val) +{ +if (en_priv->flags.is_thread_safety_disabled) +return (*val)++; +else +return __atomic_fetch_add (val,1 , __ATOMIC_RELAXED); +} + +static inline void +pdcp_lock_init (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_init (&dl->lock); +} + +static inline void +pdcp_lock_lock (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_lock (&dl->lock); +} + +static inline void +pdcp_lock_unlock (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_unlock (&dl->lock); +} +#endif /* PDCP_ENTITY_H */
lib/pdcp/pdcp_process.c +31 -3
@@ -369,7 +369,7 @@ pdcp_pre_process_uplane_sn_12_ul_set_sn(struct entity_priv *en_priv, struct rte_return false;/* Update sequence num in the PDU header */ - *count = en_priv->state.tx_next++; + *count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (*count,RTE_SECURITY_PDCP_SN_SIZE_12 ); pdu_hdr->d_c =RTE_PDCP_PDU_TYPE_DATA ;
@@ -451,7 +451,7 @@ pdcp_pre_process_uplane_sn_18_ul_set_sn(struct entity_priv *en_priv, struct rte_return false;/* Update sequence num in the PDU header */ - *count = en_priv->state.tx_next++; + *count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (*count,RTE_SECURITY_PDCP_SN_SIZE_18 ); pdu_hdr->d_c =RTE_PDCP_PDU_TYPE_DATA ;
@@ -561,7 +561,7 @@ pdcp_pre_process_cplane_sn_12_ul(const struct rte_pdcp_entity *entity, struct rtmemset (mac_i,0 ,PDCP_MAC_I_LEN );/* Update sequence number in the PDU header */ - count = en_priv->state.tx_next++; + count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (count,RTE_SECURITY_PDCP_SN_SIZE_12 ); pdu_hdr->sn_11_8 = ((sn &0xf00 ) >>8 );
@@ -654,7 +654,9 @@ pdcp_pre_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity, nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -714,7 +716,9 @@ pdcp_pre_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity, nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -775,7 +779,9 @@ pdcp_pre_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity, struct rt nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -925,6 +931,8 @@ pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity,struct rte_mbuf *mb;uint32_t count; +pdcp_lock_lock (entity); +for (i =0 ; i < num; i++) { mb = in_mb[i];if (unlikely (mb->ol_flags &RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED ))
@@ -954,6 +962,8 @@ pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -994,6 +1004,7 @@ pdcp_post_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity,int32_t rsn =0 ;uint32_t count; +pdcp_lock_lock (entity);for (i =0 ; i < num; i++) { mb = in_mb[i];
@@ -1026,6 +1037,8 @@ pdcp_post_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -1066,6 +1079,8 @@ pdcp_post_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity,uint32_t count;int32_t rsn; +pdcp_lock_lock (entity); +for (i =0 ; i < num; i++) { mb = in_mb[i];if (unlikely (mb->ol_flags &RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED ))
@@ -1091,6 +1106,8 @@ pdcp_post_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -1254,6 +1271,13 @@ pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct rte_pdcp_ent*/ en_priv->flags.is_out_of_order_delivery = conf->out_of_order_delivery; +/** +* flags.disable_thread_safety +* +* Indicate whether the thread safety is disabled for PDCP entity. +*/ + en_priv->flags.is_thread_safety_disabled = conf->disable_thread_safety; +/** * hdr_sz *
@@ -1316,6 +1340,8 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* performing header decompression, if not decompressed before: */ +pdcp_lock_lock (entity); +/* - all stored PDCP SDU(s) with associated COUNT value(s) < RX_REORD; */ nb_out =pdcp_reorder_up_to_get (&dl->reorder, out_mb, capacity, en_priv->state.rx_reord); capacity -= nb_out;
@@ -1347,5 +1373,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct dl->t_reorder.state =TIMER_EXPIRED ; } +pdcp_lock_unlock (entity); +return nb_out; }
lib/pdcp/rte_pdcp.c +2 -0
@@ -72,6 +72,8 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cif (ret)return ret; +pdcp_lock_init (entity); +return 0 ; }
lib/pdcp/rte_pdcp.h +2 -0
@@ -137,6 +137,8 @@ struct rte_pdcp_entity_conf {bool is_slrb;/** Enable security offload on the device specified. */ bool en_sec_offload; +/** Disable usage of synchronization primitives for entity. */ +bool disable_thread_safety;/** 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.*/
Signature · 1 line
2.25.1
PATCH v2 22/22 test/pdcp: add PDCP status report cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Test PDCP status report generation.
--- app/test/test_pdcp.c | 310 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+)
app/test/test_pdcp.c +310 -0
@@ -2,6 +2,7 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_errno.h> #include <rte_eventdev.h> #include <rte_event_timer_adapter.h>
@@ -43,6 +44,9 @@ struct pdcp_testsuite_params {struct rte_event_timer_adapter *timdev;bool timer_is_running;uint64_t min_resolution_ns; +struct rte_pdcp_up_ctrl_pdu_hdr *status_report; +uint32_t status_report_bitmask_capacity; +uint8_t *ctrl_pdu_buf; };static struct pdcp_testsuite_params testsuite_params;
@@ -139,6 +143,18 @@ static struct rte_pdcp_t_reordering t_reorder_timer = { .stop = pdcp_timer_stop_cb, }; +static inline void +bitmask_set_bit (uint8_t *mask,uint32_t bit) +{ + mask[bit /8 ] |= (1 << bit %8 ); +} + +static inline bool +bitmask_is_bit_set (const uint8_t *mask,uint32_t bit) +{ +return mask[bit /8 ] & (1 << (bit %8 )); +} +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -285,6 +301,21 @@ testsuite_setup(void) goto cop_pool_free; } +/* Allocate memory for longest possible status report */ + ts_params->status_report_bitmask_capacity =RTE_PDCP_CTRL_PDU_SIZE_MAX - +sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ); + ts_params->status_report =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->status_report ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report\n" ); + goto cop_pool_free; + } + + ts_params->ctrl_pdu_buf =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->ctrl_pdu_buf ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report data\n" ); + goto cop_pool_free; + } +return 0 ; cop_pool_free:
@@ -293,6 +324,8 @@ testsuite_setup(void) mbuf_pool_free:rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf);return TEST_FAILED ; }
@@ -315,6 +348,9 @@ testsuite_teardown(void)rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; + +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf); } static int
@@ -1364,6 +1400,244 @@ test_expiry_with_rte_timer(const struct pdcp_test_conf *ul_conf)return ret; } +static struct rte_pdcp_up_ctrl_pdu_hdr * +pdcp_status_report_init (uint32_t fmc) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; + + hdr->d_c =RTE_PDCP_PDU_TYPE_CTRL ; + hdr->pdu_type =RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ; + hdr->fmc =rte_cpu_to_be_32 (fmc); + hdr->r =0 ; +memset (hdr->bitmap,0 , testsuite_params.status_report_bitmask_capacity); + +return hdr; +} + +static uint32_t +pdcp_status_report_len (void ) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; +uint32_t i; + +for (i = testsuite_params.status_report_bitmask_capacity; i !=0 ; i--) { +if (hdr->bitmap[i -1 ]) +return i; + } + +return 0 ; +} + +static int +pdcp_status_report_verify (struct rte_mbuf *status_report, +const struct rte_pdcp_up_ctrl_pdu_hdr *expected_hdr,uint32_t expected_len) +{ +uint32_t received_len =rte_pktmbuf_pkt_len (status_report); +uint8_t *received_buf = testsuite_params.ctrl_pdu_buf; +int ret; + + ret =pktmbuf_read_into (status_report, received_buf,RTE_PDCP_CTRL_PDU_SIZE_MAX ); +TEST_ASSERT_SUCCESS (ret,"Failed to copy status report pkt into continuous buffer" ); + +debug_hexdump (stdout,"Received:" , received_buf, received_len); +debug_hexdump (stdout,"Expected:" , expected_hdr, expected_len); + +TEST_ASSERT_EQUAL (expected_len, received_len, +"Mismatch in packet lengths [expected: %d, received: %d]" , + expected_len, received_len); + +TEST_ASSERT_BUFFERS_ARE_EQUAL (received_buf, expected_hdr, expected_len, +"Generated packet not as expected" ); + +return 0 ; +} + +static int +test_status_report_gen (const struct pdcp_test_conf *ul_conf, +const struct rte_pdcp_up_ctrl_pdu_hdr *hdr, +uint32_t bitmap_len) +{ +struct rte_mbuf *status_report =NULL , **out_mb, *m; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint32_t nb_pkts =0 , i; +uint8_t cdev_id; + +const uint32_t start_count =rte_be_to_cpu_32 (hdr->fmc); + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.count = start_count; + dl_conf.entity.status_report_required = true; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + out_mb =calloc (pdcp_entity->max_pkt_cache,sizeof (uintptr_t )); + +for (i =0 ; i < bitmap_len *8 ; i++) { +if (!bitmask_is_bit_set (hdr->bitmap, i)) +continue ; + + m =generate_packet_for_dl_with_sn (*ul_conf, start_count + i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + + } + + m =NULL ; + +/* Check status report */ + status_report =rte_pdcp_control_pdu_create (pdcp_entity, +RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ); +ASSERT_TRUE_OR_GOTO (status_report !=NULL , exit,"Could not generate status report\n" ); + +const uint32_t expected_len =sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ) + bitmap_len; + +ASSERT_TRUE_OR_GOTO (pdcp_status_report_verify (status_report, hdr, expected_len) ==0 , exit, +"Report verification failure\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_free (m); +rte_pktmbuf_free (status_report); +rte_pktmbuf_free_bulk (out_mb, nb_pkts); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +free (out_mb); +return ret; +} + +static void +ctrl_pdu_hdr_packet_set (struct rte_pdcp_up_ctrl_pdu_hdr *hdr,uint32_t pkt_count) +{ +bitmask_set_bit (hdr->bitmap, pkt_count -rte_be_to_cpu_32 (hdr->fmc) -1 ); +} + +static int +test_status_report_fmc_only (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (42 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_first_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_second_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_full_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE +1 ; +int i; + +for (i =0 ; i <RTE_BITMAP_SLAB_BIT_SIZE ; i++) +ctrl_pdu_hdr_packet_set (hdr, start_offset + i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_non_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); +ctrl_pdu_hdr_packet_set (hdr,3 *RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_max_length_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr; +const uint32_t fmc =0 ; +uint32_t i; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + ul_conf->entity.pdcp_xfrm.sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + + hdr =pdcp_status_report_init (fmc); + +const uint32_t max_count =RTE_MIN ((RTE_PDCP_CTRL_PDU_SIZE_MAX -sizeof (hdr)) *8 , + (uint32_t )PDCP_WINDOW_SIZE (RTE_SECURITY_PDCP_SN_SIZE_12 )); + + i = fmc +2 ;/* set first count to have a gap, to enable packet buffering */ + +for (; i < max_count; i++) +ctrl_pdu_hdr_packet_set (hdr, i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_different_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (63 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,64 +1 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_same_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (2 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,4 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1555,11 +1829,47 @@ static struct unit_test_suite reorder_test_cases = { } }; +static struct unit_test_suite status_report_test_cases = { + .suite_name ="PDCP status report" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_status_report_fmc_only" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_fmc_only), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_first_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_first_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_second_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_second_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_full_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_full_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_non_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_non_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_max_length_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_status_report_max_length_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_different_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_different_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_same_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_same_slab), +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, &reorder_test_cases, + &status_report_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
v3 cover lib: add pdcp protocol
In reply to Anoob JosephAdd 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 v3:
- Addressed review comments (Akhil)
- Addressed build failure in CI (tests with lib eventdev disabled)
- Addressed checkpatch issues
- Set only positive values to rte_errno (Akhil)
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 : 112/160 passed, 0/160 skipped, 0/160 failed, 48/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: 48 + Tests Passed : 131
+ 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 for status report
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 | 1979 +++++++++++++++++ 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 | 293 +++ lib/meson.build | 1 + lib/net/meson.build | 1 + lib/net/rte_pdcp_hdr.h | 147 ++ lib/pdcp/meson.build | 21 + lib/pdcp/pdcp_cnt.c | 164 ++ lib/pdcp/pdcp_cnt.h | 24 + lib/pdcp/pdcp_crypto.c | 238 ++ lib/pdcp/pdcp_crypto.h | 20 + 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 | 1317 +++++++++++ lib/pdcp/pdcp_process.h | 26 + lib/pdcp/pdcp_reorder.c | 20 + lib/pdcp/pdcp_reorder.h | 68 + lib/pdcp/rte_pdcp.c | 317 +++ lib/pdcp/rte_pdcp.h | 381 ++++ lib/pdcp/rte_pdcp_group.h | 131 ++ lib/pdcp/version.map | 20 + 27 files changed, 5572 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
PATCH v3 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 | 147 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 lib/net/rte_pdcp_hdr.h
doc/api/doxy-api-index.md +2 -1
@@ -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
@@ -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 +147 -0
147 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 2/22 lib: add pdcp protocol
In reply to Anoob JosephAdd 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 | 113 ++++++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 138 +++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 13 +++ lib/pdcp/rte_pdcp.c | 141 ++++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 167 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 10 +++ 12 files changed, 639 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 +113 -0
113 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
@@ -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 +141 -0
141 lines not on this page · raw message
lib/pdcp/rte_pdcp.h new file +167 -0
167 lines not on this page · raw message
lib/pdcp/version.map new file +10 -0
@@ -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
PATCH v3 3/22 pdcp: add pre and post-process
In reply to Anoob JosephPDCP 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
@@ -22,6 +22,21 @@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. *
@@ -33,6 +48,10 @@ extern "C" {* plane depending on which radio bearer it is carrying data for. */ 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
@@ -160,6 +179,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
@@ -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
PATCH v3 4/22 pdcp: add packet group
In reply to Anoob JosephCrypto 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 | 131 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 3 + 4 files changed, 137 insertions(+) create mode 100644 lib/pdcp/rte_pdcp_group.h
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']
lib/pdcp/rte_pdcp.h +2 -0
@@ -257,6 +257,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 +131 -0
131 lines not on this page · raw message
lib/pdcp/version.map +3 -0
@@ -2,12 +2,15 @@ EXPERIMENTAL { global: # added in 23.07 + rte_pdcp_en_from_cop; + rte_pdcp_entity_establish; rte_pdcp_entity_release; rte_pdcp_entity_suspend; rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_pkt_crypto_group; local: *; };
Signature · 1 line
2.25.1
PATCH v3 5/22 pdcp: add crypto session create and destroy
In reply to Anoob JosephAdd 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 | 223 ++++++++++++++++++++++++++++++++++++++++- lib/pdcp/pdcp_crypto.h | 5 + 2 files changed, 225 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_crypto.c +220 -3
@@ -2,20 +2,237 @@* 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 <rte_pdcp_hdr.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 =RTE_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 ) { +/* rte_errno is set as positive values of 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 +5 -0
@@ -5,8 +5,13 @@#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 +int pdcp_crypto_sess_create (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf);
Signature · 1 line
2.25.1
PATCH v3 6/22 pdcp: add pre and post process for UL
In reply to Anoob JosephAdd 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 | 24 +++ lib/pdcp/pdcp_process.c | 330 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+)
lib/pdcp/pdcp_entity.h +24 -0
@@ -92,22 +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
PATCH v3 7/22 pdcp: add pre and post process for DL
In reply to Anoob JosephAdd routines to perform pre & post processing for down link entities.
--- lib/pdcp/pdcp_entity.h | 2 + lib/pdcp/pdcp_process.c | 454 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 456 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
@@ -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 +454 -0
475 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 8/22 pdcp: add IV generation routines
In reply to Anoob JosephFor 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
@@ -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
PATCH v3 9/22 app/test: add lib pdcp tests
In reply to Anoob JosephAdd 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 | 730 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 734 insertions(+) create mode 100644 app/test/test_pdcp.c
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 +3 -0
@@ -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 +730 -0
730 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 10/22 test/pdcp: pdcp HFN tests in combined mode
In reply to Anoob JosephFrom: 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
@@ -16,6 +16,9 @@#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16 +/* 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;
@@ -36,12 +39,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) {
@@ -326,6 +386,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) {
@@ -646,9 +721,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) {
@@ -665,6 +748,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, 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 ; + } + +/* 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.pdcp_xfrm.hfn = new_hfn; + conf->entity.sn = new_sn; + 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.pdcp_xfrm.hfn = rx_deliv_hfn; + dl_conf.entity.sn = rx_deliv_sn; + 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) {
@@ -675,8 +945,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
PATCH v3 11/22 doc: add PDCP library guide
In reply to Anoob JosephAdd guide for PDCP library.
--- .../img/pdcp_functional_overview.svg | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/pdcp_lib.rst | 254 ++++++++++++++++++ 3 files changed, 256 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
@@ -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>
doc/guides/prog_guide/index.rst +1 -0
@@ -77,4 +77,5 @@ Programmer's Guide lto profile_app asan + pdcp_lib glossary
doc/guides/prog_guide/pdcp_lib.rst new file +254 -0
254 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 12/22 pdcp: add control PDU handling for status report
In reply to Anoob JosephAdd control PDU handling and implement status report generation. Status report generation works only when RX_DELIV = RX_NEXT.
--- doc/guides/prog_guide/pdcp_lib.rst | 9 ++++++ 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 | 33 +++++++++++++++++++++ lib/pdcp/version.map | 2 ++ 11 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
doc/guides/prog_guide/pdcp_lib.rst +9 -0
@@ -76,6 +76,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 ``rte_pdcp_control_pdu_create`` allows +application to request the same. + PDCP packet processing API for data PDU ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/pdcp/meson.build +2 -0
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 *ctrl_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
@@ -1158,6 +1158,19 @@ pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct rte_pdcp_entif (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 +33 -0
@@ -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
@@ -79,6 +80,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 *ctrl_pdu_pool;/** * SN value to be used. 32 bit count value to be used for the first * packet would be derived based on HFN (`rte_security_pdcp_xform.hfn`)
@@ -98,6 +101,16 @@ struct rte_pdcp_entity_conf {* 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_control_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. */
@@ -179,6 +192,26 @@ 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. The control PDU packet +* would be allocated from *rte_pdcp_entity_conf.ctrl_pdu_pool* by lib PDCP. +* +* @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
@@ -2,6 +2,8 @@ EXPERIMENTAL { global: # added in 23.07 + rte_pdcp_control_pdu_create; + rte_pdcp_en_from_cop; rte_pdcp_entity_establish;
Signature · 1 line
2.25.1
PATCH v3 13/22 pdcp: implement t-Reordering and packet buffering
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add in-order delivery of packets in PDCP. Delivery of packets in-order relies on t-Reordering timer.
When 'out-of-order delivery' is disabled, PDCP will buffer all received packets that are out of order. The t-Reordering timer determines the time period these packets would be held in the buffer, waiting for any missing packets to arrive.
Introduce packet buffering and state variables which indicate status of the timer.
--- lib/pdcp/meson.build | 3 +- lib/pdcp/pdcp_entity.h | 19 +++++++ lib/pdcp/pdcp_process.c | 123 +++++++++++++++++++++++++++++++--------- lib/pdcp/pdcp_reorder.c | 27 +++++++++ lib/pdcp/pdcp_reorder.h | 62 ++++++++++++++++++++ lib/pdcp/rte_pdcp.c | 53 +++++++++++++++-- lib/pdcp/rte_pdcp.h | 6 +- 7 files changed, 257 insertions(+), 36 deletions(-) create mode 100644 lib/pdcp/pdcp_reorder.c create mode 100644 lib/pdcp/pdcp_reorder.h
lib/pdcp/meson.build +2 -1
@@ -12,9 +12,10 @@ sources = files( 'pdcp_crypto.c', 'pdcp_ctrl_pdu.c', 'pdcp_process.c', + 'pdcp_reorder.c', 'rte_pdcp.c', ) headers = files('rte_pdcp.h') indirect_headers += files('rte_pdcp_group.h') -deps += ['mbuf', 'net', 'cryptodev', 'security'] +deps += ['mbuf', 'net', 'cryptodev', 'security', 'reorder']
lib/pdcp/pdcp_entity.h +19 -0
@@ -11,6 +11,8 @@#include <rte_pdcp.h> #include <rte_security.h> +#include "pdcp_reorder.h" +struct entity_priv ;#define PDCP_HFN_MIN 0
@@ -109,6 +111,17 @@ union cipher_iv_partial {uint64_t u64[2 ]; }; +enum timer_state { +TIMER_STOP , +TIMER_RUNNING , +TIMER_EXPIRED , +}; + +struct pdcp_t_reordering { +/** Represent timer state */ +enum timer_state state; +}; +struct pdcp_cnt_bitmap {/** Number of entries that can be stored. */ uint32_t size;
@@ -145,6 +158,8 @@ struct entity_priv { uint64_t is_null_auth : 1;/** Is status report required.*/ uint64_t is_status_report_required : 1; +/** Is out-of-order delivery enabled */ + uint64_t is_out_of_order_delivery : 1; } flags;/** Crypto op pool. */ struct rte_mempool *cop_pool;
@@ -161,6 +176,10 @@ struct entity_priv {struct entity_priv_dl_part {/** PDCP would need to track the count values that are already received.*/ struct pdcp_cnt_bitmap bitmap; +/** t-Reordering handles */ +struct pdcp_t_reordering t_reorder; +/** Reorder packet buffer */ +struct pdcp_reorder reorder; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +95 -28
206 lines not on this page · raw message
lib/pdcp/pdcp_reorder.c new file +27 -0
@@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(C) 2023 Marvell. +*/ + +#include <rte_errno.h> +#include <rte_reorder.h> + +#include "pdcp_reorder.h" + +int +pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +{ + reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); +if (reorder->buf ==NULL ) +return -rte_errno; + + reorder->window_size = window_size; + reorder->is_active = false; + +return 0 ; +} + +void +pdcp_reorder_destroy (const struct pdcp_reorder *reorder) +{ +rte_reorder_free (reorder->buf); +}
lib/pdcp/pdcp_reorder.h new file +62 -0
62 lines not on this page · raw message
lib/pdcp/rte_pdcp.c +48 -5
99 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +4 -2
@@ -111,6 +111,8 @@ struct rte_pdcp_entity_conf {* as entity re-establishment. */ bool status_report_required; +/** Enable out of order delivery. */ +bool out_of_order_delivery; };/* >8 End of structure rte_pdcp_entity_conf. */
@@ -271,8 +273,8 @@ rte_pdcp_pkt_pre_process(const struct rte_pdcp_entity *entity,* @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. +* The address of an array that can hold up to *rte_pdcp_entity.max_pkt_cache* +* 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
Signature · 1 line
2.25.1
PATCH v3 14/22 test/pdcp: add in-order delivery cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases to verify behaviour when in-order delivery is enabled and packets arrive in out-of-order. PDCP library is expected to buffer the packets and return packets in-order when the missing packet arrives.
--- app/test/test_pdcp.c | 223 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+)
app/test/test_pdcp.c +223 -0
@@ -16,6 +16,15 @@#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16 +/* Assert that condition is true, or goto the mark */ +#define ASSERT_TRUE_OR_GOTO (cond, mark, ...) do {\ + if (!(cond)) { \ + RTE_LOG(ERR, USER1, "Error at: %s:%d\n", __func__, __LINE__); \ + RTE_LOG(ERR, USER1, __VA_ARGS__); \ + goto mark; \ + } \ +} while (0) +/* According to formula(7.2.a Window_Size) */ #define PDCP_WINDOW_SIZE (sn_size) (1 << (sn_size - 1))
@@ -83,6 +92,38 @@ run_test_with_all_known_vec(const void *args)return run_test_foreach_known_vec (test, false); } +static int +run_test_with_all_known_vec_until_first_pass (const void *args) +{ +test_with_conf_t test = args; + +return run_test_foreach_known_vec (test, true); +} + +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 int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -416,6 +457,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.ctrl_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 ;
@@ -866,6 +908,7 @@ test_sn_range_type(enum sn_range_type type, struct pdcp_test_conf *conf)/* Configure Uplink to generate expected, encrypted packet */ pdcp_sn_to_raw_set (conf->input, new_sn, conf->entity.pdcp_xfrm.sn_size); + conf->entity.out_of_order_delivery = true; conf->entity.reverse_iv_direction = true; conf->entity.pdcp_xfrm.hfn = new_hfn; conf->entity.sn = new_sn;
@@ -913,6 +956,171 @@ test_sn_minus_outside(struct pdcp_test_conf *t_conf)return test_sn_range_type (SN_RANGE_MINUS_OUTSIDE , t_conf); } +static struct rte_mbuf * +generate_packet_for_dl_with_sn (struct pdcp_test_conf ul_conf,uint32_t count) +{ +enum rte_security_pdcp_sn_size sn_size = ul_conf.entity.pdcp_xfrm.sn_size; +int ret; + + ul_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (count, sn_size); + ul_conf.entity.sn =pdcp_sn_from_count_get (count, sn_size); + ul_conf.entity.out_of_order_delivery = true; + ul_conf.entity.reverse_iv_direction = true; + ul_conf.output_len =0 ; + + ret =test_attempt_single (&ul_conf); +if (ret !=TEST_SUCCESS ) +return NULL ; + +return mbuf_from_data_create (ul_conf.output, ul_conf.output_len); +} + +static bool +array_asc_sorted_check (struct rte_mbuf *m[],uint32_t len,enum rte_security_pdcp_sn_size sn_size) +{ +uint32_t i; + +if (len <2 ) +return true; + +for (i =0 ; i < (len -1 ); i++) { + if (pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i], void *), sn_size) > + pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i + 1], void *), sn_size)) +return false; + } + +return true; +} + +static int +test_reorder_gap_fill (struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m0 =NULL , *m1 =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Generate packet to fill the existing gap */ + m0 =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m0 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1] +* Gap filled, all packets should be returned +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m0,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m0 =NULL ;/* Packet was moved to out_mb */ + +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit, +"Error occurred during packet drain\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m0); +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} + +static int +test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +const uint32_t window_size =PDCP_WINDOW_SIZE (sn_size); +struct rte_mbuf *m1 =NULL , **out_mb =NULL ; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +const int rx_deliv =0 ; +int ret =TEST_FAILED ; +size_t i, nb_out; +uint8_t cdev_id; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (rx_deliv, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (rx_deliv, sn_size); + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + +ASSERT_TRUE_OR_GOTO (pdcp_entity->max_pkt_cache >= window_size, exit, +"PDCP max packet cache is too small" ); + cdev_id = dl_conf.entity.dev_id; + out_mb =rte_zmalloc (NULL , pdcp_entity->max_pkt_cache *sizeof (uintptr_t ),0 ); +ASSERT_TRUE_OR_GOTO (out_mb !=NULL , exit, +"Could not allocate buffer for holding out_mb buffers\n" ); + +/* Send packets with SN > RX_DELIV to create a gap */ +for (i = rx_deliv +1 ; i < window_size; i++) { + m1 =generate_packet_for_dl_with_sn (*ul_conf, i); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + } + + m1 =generate_packet_for_dl_with_sn (*ul_conf, rx_deliv); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Insert missing packet */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success == window_size, exit, +"Packet count mismatch (received: %i, expected: %i)\n" , + nb_success, window_size); + m1 =NULL ; + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +rte_free (out_mb); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -969,10 +1177,25 @@ static struct unit_test_suite hfn_sn_test_cases = { } }; +static struct unit_test_suite reorder_test_cases = { + .suite_name ="PDCP reorder" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_buffer_full_window_size_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_reorder_buffer_full_window_size_sn_12), +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, + &reorder_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
PATCH v3 15/22 pdcp: add timer callback handlers
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP has a windowing mechanism which allows only packets that fall in a reception window. The pivot point for this window is RX_REORD which happens to be the first missing or next expected packet. If the missing packet is not received after a specified time, then the RX_REORD state variable needs to be moved up to slide the reception window. PDCP relies on timers for such operations.
The timer needs to be armed when PDCP library doesn't receive all packets in-order and starts buffering packets that arrived after a missing packet. The timer needs to be cancelled when a missing packet is received.
To avoid dependency on particular timer implementation, PDCP library allows application to register two callbacks, timer_start() and timer_stop() that will be called later by library.
--- lib/pdcp/pdcp_entity.h | 2 ++ lib/pdcp/pdcp_process.c | 2 ++ lib/pdcp/rte_pdcp.c | 1 + lib/pdcp/rte_pdcp.h | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
@@ -120,6 +120,8 @@ enum timer_state {struct pdcp_t_reordering {/** Represent timer state */ enum timer_state state; +/** User defined callback handles */ +struct rte_pdcp_t_reordering handle; };struct pdcp_cnt_bitmap {
lib/pdcp/pdcp_process.c +2 -0
@@ -882,6 +882,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (t_reorder->state ==TIMER_RUNNING && en_priv->state.rx_deliv >= en_priv->state.rx_reord) { t_reorder->state =TIMER_STOP ; + t_reorder->handle.stop (t_reorder->handle.timer, t_reorder->handle.args);/* Stop reorder buffer, only if it's empty */ if (en_priv->state.rx_deliv == en_priv->state.rx_next)pdcp_reorder_stop (reorder);
@@ -896,6 +897,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, en_priv->state.rx_reord = en_priv->state.rx_next;/* Start t-Reordering */ t_reorder->state =TIMER_RUNNING ; + t_reorder->handle.start (t_reorder->handle.timer, t_reorder->handle.args); }return processed;
lib/pdcp/rte_pdcp.c +1 -0
@@ -36,6 +36,7 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cstruct entity_priv_dl_part *dl =entity_dl_part_get (entity); entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); + dl->t_reorder.handle = conf->t_reordering;return pdcp_reorder_create (&dl->reorder, window_size); }
lib/pdcp/rte_pdcp.h +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 16/22 pdcp: add timer expiry handle
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
The PDCP protocol requires usage of timers to keep track of how long an out-of-order packet should be buffered while waiting for missing packets. Applications can register a desired timer implementation with the PDCP library. Once the timer expires, the application will be notified, and further handling of the event will be performed in the PDCP library.
When the timer expires, the PDCP library will return the cached packets, and PDCP internal state variables (like RX_REORD, RX_DELIV etc) will be updated accordingly.
--- doc/guides/prog_guide/pdcp_lib.rst | 30 ++++++++++++++++++ lib/pdcp/rte_pdcp.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 31 +++++++++++++++++++ lib/pdcp/version.map | 2 ++ 4 files changed, 112 insertions(+)
doc/guides/prog_guide/pdcp_lib.rst +30 -0
@@ -130,6 +130,36 @@ Supported integrity protection algorithms - SNOW3G-AUTH - ZUC-AUTH +Timers +------ + +PDCP utilizes a reception window mechanism to limit the bits of COUNT value +transmitted in the packet. It utilizes state variables such as RX_REORD, +RX_DELIV to define the window and uses RX_DELIV as the lower pivot point of the +window. + +RX_DELIV would be updated only when packets are received in-order. Any missing +packet would mean RX_DELIV won't be updated. A timer, t-Reordering, helps PDCP +to slide the window if the missing packet is not received in a specified time +duration. + +While starting and stopping the timer need to be done by lib PDCP, application +could register its own timer implementation. This is to make sure application +can choose between timers such as rte_timer and rte_event based timers. Starting +and stopping of timer would happen during pre & post process API. + +When the t-Reordering timer expires, application would receive the expiry event. +To perform the PDCP handling of the expiry event, +``rte_pdcp_t_reordering_expiry_handle`` can be used. Expiry handling would +involve sliding the window by updating state variables and passing the expired +packets to the application. + +.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h + :language: c + :start-after: Structure rte_pdcp_t_reordering 8< + :end-before: >8 End of structure rte_pdcp_t_reordering. + + Sample API usage ----------------
lib/pdcp/rte_pdcp.c +49 -0
52 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +31 -0
@@ -101,6 +101,7 @@ typedef void (*rte_pdcp_t_reordering_stop_cb_t)(void *timer, void *args);* * Configuration provided by user, that PDCP library will invoke according to timer behaviour. */ +/* Structure rte_pdcp_t_reordering 8< */ struct rte_pdcp_t_reordering {/** Timer pointer, stored for later use in callback functions */ void *timer;
@@ -111,6 +112,7 @@ struct rte_pdcp_t_reordering {/** Timer stop callback handle */ rte_pdcp_t_reordering_stop_cb_t stop; }; +/* >8 End of structure rte_pdcp_t_reordering. */ /** * PDCP entity configuration to be used for establishing an entity.
@@ -339,6 +341,35 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,return entity->post_process (entity, in_mb, out_mb, num, nb_err); } +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* 5.2.2.2 Actions when a t-Reordering expires +* +* When t-Reordering timer expires, PDCP is required to slide the reception +* window by updating state variables such as RX_REORD & RX_DELIV. PDCP would +* need to deliver some of the buffered packets based on the state variables and +* conditions described. +* +* The expiry handle need to be invoked by the application when t-Reordering +* timer expires. In addition to returning buffered packets, it may also restart +* timer based on the state variables. +* +* @param entity +* Pointer to the *rte_pdcp_entity* for which the timer expired. +* @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. Used to return buffered packets that are +* expired. +* @return +* Number of packets returned in *out_mb* buffer. +*/ +__rte_experimental +uint16_t +rte_pdcp_t_reordering_expiry_handle (const struct rte_pdcp_entity *entity, +struct rte_mbuf *out_mb[]); +#include <rte_pdcp_group.h> #ifdef __cplusplus
lib/pdcp/version.map +2 -0
@@ -14,5 +14,7 @@ EXPERIMENTAL { rte_pdcp_pkt_pre_process; rte_pdcp_pkt_crypto_group; + rte_pdcp_t_reordering_expiry_handle; + local: *; };
Signature · 1 line
2.25.1
PATCH v3 17/22 test/pdcp: add timer expiry cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases for handling the expiry with rte_timer and rte_event_timer.
--- app/test/test_pdcp.c | 350 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+)
app/test/test_pdcp.c +350 -0
@@ -3,15 +3,24 @@*/ #include <rte_errno.h> +#ifdef RTE_LIB_EVENTDEV +#include <rte_eventdev.h> +#include <rte_event_timer_adapter.h> +#endif /* RTE_LIB_EVENTDEV */ #include <rte_malloc.h> #include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include <rte_timer.h> #include "test.h" #include "test_cryptodev.h" #include "test_cryptodev_security_pdcp_test_vectors.h" +#define NSECPERSEC 1E9#define NB_DESC 1024 +#define TIMER_ADAPTER_ID 0 +#define TEST_EV_QUEUE_ID 0 +#define TEST_EV_PORT_ID 0#define CDEV_INVALID_ID UINT8_MAX#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16
@@ -33,10 +42,21 @@ struct pdcp_testsuite_params {struct rte_mempool *cop_pool;struct rte_mempool *sess_pool;bool cdevs_used[RTE_CRYPTO_MAX_DEVS ]; +int evdev; +#ifdef RTE_LIB_EVENTDEV +struct rte_event_timer_adapter *timdev; +#endif /* RTE_LIB_EVENTDEV */ +bool timer_is_running; +uint64_t min_resolution_ns; };static struct pdcp_testsuite_params testsuite_params; +struct test_rte_timer_args { +int status; +struct rte_pdcp_entity *pdcp_entity; +}; +struct pdcp_test_conf {struct rte_pdcp_entity_conf entity;struct rte_crypto_sym_xform c_xfrm;
@@ -124,6 +144,30 @@ 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 void +pdcp_timer_start_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = true; +} + +static void +pdcp_timer_stop_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = false; +} + +static struct rte_pdcp_t_reordering t_reorder_timer = { + .timer = &testsuite_params.timer_is_running, + .start = pdcp_timer_start_cb, + .stop = pdcp_timer_stop_cb, +}; +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -462,6 +506,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf) conf->entity.pdcp_xfrm.en_ordering =0 ; conf->entity.pdcp_xfrm.remove_duplicates =0 ; conf->entity.pdcp_xfrm.domain = pdcp_test_params[index].domain; + conf->entity.t_reordering = t_reorder_timer;if (pdcp_test_packet_direction[index] ==PDCP_DIR_UPLINK ) conf->entity.pdcp_xfrm.pkt_dir =RTE_SECURITY_PDCP_UPLINK ;
@@ -1046,6 +1091,8 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)/* Check that packets in correct order */ ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == false, exit, +"Timer should be stopped after full drain\n" ); ret =TEST_SUCCESS ; exit:
@@ -1121,6 +1168,181 @@ test_reorder_buffer_full_window_size_sn_12(const struct pdcp_test_conf *ul_conf)return ret; } +#ifdef RTE_LIB_EVENTDEV +static void +event_timer_start_cb (void *timer,void *args) +{ +struct rte_event_timer *evtims = args; +int ret =0 ; + + ret =rte_event_timer_arm_burst (timer, &evtims,1 ); +assert (ret ==1 ); +} +#endif /* RTE_LIB_EVENTDEV */ + +static int +test_expiry_with_event_timer (const struct pdcp_test_conf *ul_conf) +{ +#ifdef RTE_LIB_EVENTDEV +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_event event; + +const int start_count =0 ; +struct rte_event_timer evtim = { + .ev.op =RTE_EVENT_OP_NEW , + .ev.queue_id =TEST_EV_QUEUE_ID , + .ev.sched_type =RTE_SCHED_TYPE_ATOMIC , + .ev.priority =RTE_EVENT_DEV_PRIORITY_NORMAL , + .ev.event_type =RTE_EVENT_TYPE_TIMER , + .state =RTE_EVENT_TIMER_NOT_ARMED , + .timeout_ticks =1 , + }; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.t_reordering.args = &evtim; + dl_conf.entity.t_reordering.timer = testsuite_params.timdev; + dl_conf.entity.t_reordering.start = event_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + evtim.ev.event_ptr = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +while (n !=1 ) { +rte_delay_us (testsuite_params.min_resolution_ns /1000 ); + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit, +"Dequeued unexpected timer expiry event: %i\n" , n); + } + +ASSERT_TRUE_OR_GOTO (event.event_type ==RTE_EVENT_TYPE_TIMER , exit,"Unexpected event type\n" ); + +/* Handle expiry event */ + n =rte_pdcp_t_reordering_expiry_handle (event.event_ptr, out_mb); +ASSERT_TRUE_OR_GOTO (n ==1 , exit,"Unexpected number of expired packets :%i\n" , n); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +#else +RTE_SET_USED (ul_conf); +return TEST_SKIPPED ; +#endif /* RTE_LIB_EVENTDEV */ +} + +static void +test_rte_timer_expiry_handle (struct rte_timer *tim,void *arg) +{ +struct test_rte_timer_args *tim_data = arg; +struct rte_mbuf *out_mb[1 ] = {0 }; +uint16_t n; + +RTE_SET_USED (tim); + + n =rte_pdcp_t_reordering_expiry_handle (tim_data->pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, n); + + tim_data->status = n ==1 ? n :-1 ; +} + +static void +test_rte_timer_start_cb (void *timer,void *args) +{ +rte_timer_reset_sync (timer,1 ,SINGLE ,rte_lcore_id (), test_rte_timer_expiry_handle, args); +} + +static int +test_expiry_with_rte_timer (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct test_rte_timer_args timer_args; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_timer timer = {0 }; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Set up a timer */ +rte_timer_init (&timer); + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.t_reordering.args = &timer_args; + dl_conf.entity.t_reordering.timer = &timer; + dl_conf.entity.t_reordering.start = test_rte_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + timer_args.status =0 ; + timer_args.pdcp_entity = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Verify that expire was handled correctly */ +rte_timer_manage (); +while (timer_args.status !=1 ) { +rte_delay_us (1 ); +rte_timer_manage (); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit,"Bad expire handle status %i\n" , + timer_args.status); + } + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1143,6 +1365,126 @@ test_combined(struct pdcp_test_conf *ul_conf)return ret; } +#ifdef RTE_LIB_EVENTDEV +static inline void +eventdev_conf_default_set (struct rte_event_dev_config *dev_conf,struct rte_event_dev_info *info) +{ +memset (dev_conf,0 ,sizeof (struct rte_event_dev_config )); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports =1 ; + dev_conf->nb_event_queues =1 ; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = info->max_num_events; +} + +static inline int +eventdev_setup (void ) +{ +struct rte_event_dev_config dev_conf; +struct rte_event_dev_info info; +int ret, evdev =0 ; + +if (!rte_event_dev_count ()) +return TEST_SKIPPED ; + + ret =rte_event_dev_info_get (evdev, &info); +TEST_ASSERT_SUCCESS (ret,"Failed to get event dev info" ); +TEST_ASSERT (info.max_num_events <0 || info.max_num_events >=1 , +"ERROR max_num_events=%d < max_events=%d" , info.max_num_events,1 ); + +eventdev_conf_default_set (&dev_conf, &info); + ret =rte_event_dev_configure (evdev, &dev_conf); +TEST_ASSERT_SUCCESS (ret,"Failed to configure eventdev" ); + + ret =rte_event_queue_setup (evdev,TEST_EV_QUEUE_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup queue=%d" ,TEST_EV_QUEUE_ID ); + +/* Configure event port */ + ret =rte_event_port_setup (evdev,TEST_EV_PORT_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup port=%d" ,TEST_EV_PORT_ID ); + ret =rte_event_port_link (evdev,TEST_EV_PORT_ID ,NULL ,NULL ,0 ); +TEST_ASSERT (ret >=0 ,"Failed to link all queues port=%d" ,TEST_EV_PORT_ID ); + + ret =rte_event_dev_start (evdev); +TEST_ASSERT_SUCCESS (ret,"Failed to start device" ); + + testsuite_params.evdev = evdev; + +return TEST_SUCCESS ; +} + +static int +event_timer_setup (void ) +{ +struct rte_event_timer_adapter_info info; +struct rte_event_timer_adapter *timdev; +uint32_t caps =0 ; + +struct rte_event_timer_adapter_conf config = { + .event_dev_id = testsuite_params.evdev, + .timer_adapter_id =TIMER_ADAPTER_ID , + .timer_tick_ns =NSECPERSEC , + .max_tmo_ns =10 *NSECPERSEC , + .nb_timers =10 , + .flags =0 , + }; + +TEST_ASSERT_SUCCESS (rte_event_timer_adapter_caps_get (testsuite_params.evdev, &caps), +"Failed to get adapter capabilities" ); + +if (!(caps &RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT )) +return TEST_SKIPPED ; + + timdev =rte_event_timer_adapter_create (&config); + +TEST_ASSERT_NOT_NULL (timdev,"Failed to create event timer ring" ); + + testsuite_params.timdev = timdev; + +TEST_ASSERT_EQUAL (rte_event_timer_adapter_start (timdev),0 , +"Failed to start event timer adapter" ); + +rte_event_timer_adapter_get_info (timdev, &info); + testsuite_params.min_resolution_ns = info.min_resolution_ns; + +return TEST_SUCCESS ; +} +#endif /* RTE_LIB_EVENTDEV */ + +static int +ut_setup_pdcp_event_timer (void ) +{ +#ifdef RTE_LIB_EVENTDEV +int ret; + + ret =eventdev_setup (); +if (ret) +return ret; + +return event_timer_setup (); +#else +return TEST_SKIPPED ; +#endif /* RTE_LIB_EVENTDEV */ +} + +static void +ut_teardown_pdcp_event_timer (void ) +{ +#ifdef RTE_LIB_EVENTDEV +struct rte_event_timer_adapter *timdev = testsuite_params.timdev; +int evdev = testsuite_params.evdev; + +rte_event_dev_stop (evdev); +rte_event_dev_close (evdev); + +rte_event_timer_adapter_stop (timdev); +rte_event_timer_adapter_free (timdev); +#endif /* RTE_LIB_EVENTDEV */ +} +static int run_test_for_one_known_vec (const void *arg) {
@@ -1187,6 +1529,14 @@ static struct unit_test_suite reorder_test_cases = { ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass, test_reorder_buffer_full_window_size_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_event_timer" , + ut_setup_pdcp_event_timer, ut_teardown_pdcp_event_timer, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_event_timer), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_rte_timer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_rte_timer), TEST_CASES_END() /**< NULL terminate unit test array */ } };
Signature · 1 line
2.25.1
PATCH v3 18/22 test/pdcp: add timer restart case
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test to cover the case when t-reordering timer should be restarted on the same packet.
--- app/test/test_pdcp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
app/test/test_pdcp.c +68 -0
@@ -1104,6 +1104,71 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)return ret; } +static int +test_reorder_gap_in_reorder_buffer (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +int ret =TEST_FAILED , nb_out, i; +struct pdcp_test_conf dl_conf; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + +/* Create two gaps [NULL, m1, NULL, m3]*/ +for (i =0 ; i <2 ; i++) { + m =generate_packet_for_dl_with_sn (*ul_conf, start_count +2 * i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m =NULL ;/* Packet was moved to PDCP lib */ + } + +/* Generate packet to fill the first gap */ + m =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1, NULL, m3] +* Only first gap should be filled, timer should be restarted for second gap +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m =NULL ; +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), + exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == true, exit, +"Timer should be restarted after partial drain" ); + + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) {
@@ -1525,6 +1590,9 @@ static struct unit_test_suite reorder_test_cases = {TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_in_reorder_buffer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_in_reorder_buffer), TEST_CASE_NAMED_WITH_DATA("test_reorder_buffer_full_window_size_sn_12", ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass,
Signature · 1 line
2.25.1
PATCH v3 19/22 pdcp: add support for status report
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Implement status report generation for PDCP entity.
--- lib/pdcp/pdcp_cnt.c | 158 ++++++++++++++++++++++++++++++++++++--- lib/pdcp/pdcp_cnt.h | 11 ++- lib/pdcp/pdcp_ctrl_pdu.c | 34 ++++++++- lib/pdcp/pdcp_ctrl_pdu.h | 3 +- lib/pdcp/pdcp_entity.h | 2 + lib/pdcp/pdcp_process.c | 9 ++- lib/pdcp/pdcp_process.h | 13 ++++ lib/pdcp/rte_pdcp.c | 34 ++++++--- 8 files changed, 236 insertions(+), 28 deletions(-)
lib/pdcp/pdcp_cnt.c +147 -11
@@ -2,28 +2,164 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_pdcp.h> #include "pdcp_cnt.h" +#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#define SLAB_BYTE_SIZE (RTE_BITMAP_SLAB_BIT_SIZE / 8) + +uint32_t +pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf) +{ +uint32_t n_bits =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); + +return rte_bitmap_get_memory_footprint (n_bits); +} +int -pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) { -struct entity_priv_dl_part *en_priv_dl; -uint32_t window_sz; +uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); -if (en ==NULL || conf ==NULL ) + dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); +if (dl->bitmap.bmp ==NULL )return -EINVAL ; -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) -return 0 ; + dl->bitmap.size = window_size; - en_priv_dl =entity_dl_part_get (en); - window_sz =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); +return 0 ; +} -RTE_SET_USED (window_sz); -RTE_SET_USED (en_priv_dl); +void +pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +rte_bitmap_set (bitmap.bmp, count % bitmap.size); +} -return 0 ; +bool +pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +return rte_bitmap_get (bitmap.bmp, count % bitmap.size); +} + +void +pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop) +{ +uint32_t i; + +for (i = start; i < stop; i++) +rte_bitmap_clear (bitmap.bmp, i % bitmap.size); +} + +uint16_t +pdcp_cnt_get_bitmap_size (uint32_t pending_bytes) +{ +/* +* Round up bitmap size to slab size to operate only on slabs sizes, instead of individual +* bytes +*/ +return RTE_ALIGN_MUL_CEIL (pending_bytes,SLAB_BYTE_SIZE ); +} + +static __rte_always_inline uint64_t +leftover_get (uint64_t slab,uint32_t shift,uint64_t mask) +{ +return (slab & mask) << shift; +} + +void +pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len) +{ +uint64_t slab =0 , next_slab =0 , leftover; +uint32_t zeros, report_len, diff; +uint32_t slab_id, next_slab_id; +uint32_t pos =0 , next_pos =0 ; + +const uint32_t start_count = state.rx_deliv +1 ; +const uint32_t nb_slabs = bitmap.size /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t nb_data_slabs = data_len /SLAB_BYTE_SIZE ; +const uint32_t start_slab_id = start_count /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t stop_slab_id = (start_slab_id + nb_data_slabs) % nb_slabs; +const uint32_t shift = start_count %RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t leftover_shift = shift ?RTE_BITMAP_SLAB_BIT_SIZE - shift :0 ; +const uint8_t *data_end =RTE_PTR_ADD (data, data_len +SLAB_BYTE_SIZE ); + +/* NOTE: Mask required to workaround case - when shift is not needed */ +const uint64_t leftover_mask = shift ? ~0 :0 ; + +/* NOTE: implement scan init at to set custom position */ +__rte_bitmap_scan_init (bitmap.bmp); +while (true) { +assert (rte_bitmap_scan (bitmap.bmp, &pos, &slab) ==1 ); + slab_id = pos /RTE_BITMAP_SLAB_BIT_SIZE ; +if (slab_id >= start_slab_id) +break ; + } + + report_len = nb_data_slabs; + +if (slab_id > start_slab_id) { +/* Zero slabs at beginning */ + zeros = (slab_id - start_slab_id -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + leftover =leftover_get (slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + report_len -= (slab_id - start_slab_id); + } + +while (report_len) { +rte_bitmap_scan (bitmap.bmp, &next_pos, &next_slab); + next_slab_id = next_pos /RTE_BITMAP_SLAB_BIT_SIZE ; + diff = (next_slab_id + nb_slabs - slab_id) % nb_slabs; + +/* If next_slab_id == slab_id - overlap */ + diff += !(next_slab_id ^ slab_id) * nb_slabs; + +/* Size check - next slab is outsize of size range */ +if (diff > report_len) { + next_slab =0 ; + next_slab_id = stop_slab_id; + diff = report_len; + } + + report_len -= diff; + +/* Calculate gap between slabs, taking wrap around into account */ + zeros = (next_slab_id + nb_slabs - slab_id -1 ) % nb_slabs; +if (zeros) { +/* Non continues slabs, align them individually */ + slab >>= shift; +memcpy (data, &slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + +/* Fill zeros between slabs */ + zeros = (zeros -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + +/* Align beginning of next slab */ + leftover =leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + }else { +/* Continues slabs, combine them */ +uint64_t new_slab = (slab >> shift) | +leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &new_slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + } + + slab = next_slab; + pos = next_pos; + slab_id = next_slab_id; + + }; + +assert (data < data_end); }
lib/pdcp/pdcp_cnt.h +10 -1
@@ -9,6 +9,15 @@#include "pdcp_entity.h" -int pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf); +uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); + +void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +void pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop); + +uint16_t pdcp_cnt_get_bitmap_size (uint32_t pending_bytes); +void pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len);#endif /* PDCP_CNT_H */
lib/pdcp/pdcp_ctrl_pdu.c +30 -4
@@ -8,6 +8,14 @@#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#include "pdcp_cnt.h" + +static inline uint16_t +round_up_bits (uint32_t bits) +{ +/* round up to the next multiple of 8 */ +return RTE_ALIGN_MUL_CEIL (bits,8 ) /8 ; +} static __rte_always_inline voidpdcp_hdr_fill (struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr,uint32_t rx_deliv)
@@ -19,11 +27,13 @@ pdcp_hdr_fill(struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr, uint32_t rx_deliv) }int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m) +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m) {struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr; -uint32_t rx_deliv; -int pdu_sz; +uint32_t rx_deliv, actual_sz; +uint16_t pdu_sz, bitmap_sz; +uint8_t *data;if (!en_priv->flags.is_status_report_required)return -EINVAL ;
@@ -42,5 +52,21 @@ pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m)return 0 ; } -return -ENOTSUP ; + actual_sz =RTE_MIN (round_up_bits (en_priv->state.rx_next - rx_deliv -1 ), +RTE_PDCP_CTRL_PDU_SIZE_MAX - pdu_sz); + bitmap_sz =pdcp_cnt_get_bitmap_size (actual_sz); + + data = (uint8_t *)rte_pktmbuf_append (m, pdu_sz + bitmap_sz); +if (data ==NULL ) +return -ENOMEM ; + + m->pkt_len = pdu_sz + actual_sz; + m->data_len = pdu_sz + actual_sz; + +pdcp_hdr_fill ((struct rte_pdcp_up_ctrl_pdu_hdr *)data, rx_deliv); + + data =RTE_PTR_ADD (data, pdu_sz); +pdcp_cnt_report_fill (dl->bitmap, en_priv->state, data, bitmap_sz); + +return 0 ; }
lib/pdcp/pdcp_ctrl_pdu.h +2 -1
@@ -10,6 +10,7 @@#include "pdcp_entity.h" int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m); +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m);#endif /* PDCP_CTRL_PDU_H */
lib/pdcp/pdcp_entity.h +2 -0
@@ -182,6 +182,8 @@ struct entity_priv_dl_part {struct pdcp_t_reordering t_reorder;/** Reorder packet buffer */ struct pdcp_reorder reorder; +/** Bitmap memory region */ +uint8_t bitmap_mem[0 ]; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +7 -2
@@ -9,6 +9,7 @@#include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include "pdcp_cnt.h" #include "pdcp_crypto.h" #include "pdcp_entity.h" #include "pdcp_process.h"
@@ -837,11 +838,15 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (count >= en_priv->state.rx_next) en_priv->state.rx_next = count +1 ; +if (unlikely (pdcp_cnt_bitmap_is_set (dl->bitmap, count))) +return -EEXIST ; + +pdcp_cnt_bitmap_set (dl->bitmap, count);pdcp_packet_strip (mb, hdr_trim_sz, trim_mac);if (en_priv->flags.is_out_of_order_delivery) { out_mb[0 ] = mb; - en_priv->state.rx_deliv = count +1 ; +pdcp_rx_deliv_set (entity, count +1 );return 1 ; }
@@ -868,7 +873,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, }/* Processed should never exceed the window size */ - en_priv->state.rx_deliv = count + processed; +pdcp_rx_deliv_set (entity, count + processed); }else {if (!reorder->is_active)
lib/pdcp/pdcp_process.h +13 -0
@@ -7,7 +7,20 @@#include <rte_pdcp.h> +#include <pdcp_entity.h> +#include <pdcp_cnt.h> +int pdcp_process_func_set (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf); +static inline void +pdcp_rx_deliv_set (const struct rte_pdcp_entity *entity,uint32_t rx_deliv) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +pdcp_cnt_bitmap_range_clear (dl->bitmap, en_priv->state.rx_deliv, rx_deliv); + en_priv->state.rx_deliv = rx_deliv; +} +#endif /* PDCP_PROCESS_H */
lib/pdcp/rte_pdcp.c +25 -9
@@ -12,6 +12,8 @@#include "pdcp_entity.h" #include "pdcp_process.h" +static int bitmap_mem_offset; +static int pdcp_entity_size_get (const struct rte_pdcp_entity_conf *conf) {
@@ -19,9 +21,12 @@ pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) size =sizeof (struct rte_pdcp_entity ) +sizeof (struct entity_priv ); -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +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 =RTE_CACHE_LINE_ROUNDUP (size); + bitmap_mem_offset = size; + size +=pdcp_cnt_bitmap_get_memory_footprint (conf); + }else if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) size +=sizeof (struct entity_priv_ul_part );else return -EINVAL ;
@@ -34,11 +39,24 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_c {const uint32_t window_size =pdcp_window_size_get (conf->pdcp_xfrm.sn_size);struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +void *bitmap_mem; +int ret; entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); dl->t_reorder.handle = conf->t_reordering; -return pdcp_reorder_create (&dl->reorder, window_size); + ret =pdcp_reorder_create (&dl->reorder, window_size); +if (ret) +return ret; + + bitmap_mem =RTE_PTR_ADD (entity, bitmap_mem_offset); + ret =pdcp_cnt_bitmap_create (dl, bitmap_mem, window_size); +if (ret) { +pdcp_reorder_destroy (&dl->reorder); +return ret; + } + +return 0 ; } struct rte_pdcp_entity *
@@ -113,10 +131,6 @@ rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) goto crypto_sess_destroy; } - ret =pdcp_cnt_ring_create (entity, conf); -if (ret) - goto crypto_sess_destroy; -return entity; crypto_sess_destroy:
@@ -195,6 +209,7 @@ struct rte_mbuf * rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, enum rte_pdcp_ctrl_pdu_type type) { +struct entity_priv_dl_part *dl;struct entity_priv *en_priv;struct rte_mbuf *m;int ret;
@@ -205,6 +220,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, } en_priv =entity_priv_get (pdcp_entity); + dl =entity_dl_part_get (pdcp_entity); m =rte_pktmbuf_alloc (en_priv->ctrl_pdu_pool);if (m ==NULL ) {
@@ -214,7 +230,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,switch (type) {case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT : - ret =pdcp_ctrl_pdu_status_gen (en_priv, m); + ret =pdcp_ctrl_pdu_status_gen (en_priv, dl, m);break ;default : ret = -ENOTSUP ;
@@ -260,7 +276,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* - update RX_DELIV to the COUNT value of the first PDCP SDU which has not been delivered * to upper layers, with COUNT value >= RX_REORD; */ - en_priv->state.rx_deliv = en_priv->state.rx_reord + nb_seq; +pdcp_rx_deliv_set (entity, en_priv->state.rx_reord + nb_seq);/* * - if RX_DELIV < RX_NEXT:
Signature · 1 line
2.25.1
PATCH v3 20/22 pdcp: allocate reorder buffer alongside with entity
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Instead of allocating reorder buffer separately on heap, allocate memory for it together with rest of entity, and then only initialize buffer via rte_reorder_init().
--- lib/pdcp/pdcp_cnt.c | 9 +++---- lib/pdcp/pdcp_cnt.h | 3 ++- lib/pdcp/pdcp_entity.h | 2 +- lib/pdcp/pdcp_reorder.c | 11 ++------ lib/pdcp/pdcp_reorder.h | 12 ++++++--- lib/pdcp/rte_pdcp.c | 58 ++++++++++++++++++++++++++--------------- 6 files changed, 55 insertions(+), 40 deletions(-)
lib/pdcp/pdcp_cnt.c +4 -5
@@ -20,15 +20,14 @@ pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf *conf) }int -pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size) { -uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); - - dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); + dl->bitmap.bmp =rte_bitmap_init (nb_elem, bitmap_mem, mem_size);if (dl->bitmap.bmp ==NULL )return -EINVAL ; - dl->bitmap.size = window_size; + dl->bitmap.size = nb_elem;return 0 ; }
lib/pdcp/pdcp_cnt.h +2 -1
@@ -10,7 +10,8 @@#include "pdcp_entity.h" uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); -int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size);void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);
lib/pdcp/pdcp_entity.h +1 -1
@@ -132,7 +132,7 @@ struct pdcp_cnt_bitmap { };/* -* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] +* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] [reorder/bitmap] */ struct entity_priv {
lib/pdcp/pdcp_reorder.c +2 -9
@@ -8,20 +8,13 @@#include "pdcp_reorder.h" int -pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size) { - reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); + reorder->buf =rte_reorder_init (mem, mem_size,"reorder_buffer" , nb_elem);if (reorder->buf ==NULL )return -rte_errno; - reorder->window_size = window_size; reorder->is_active = false;return 0 ; } - -void -pdcp_reorder_destroy (const struct pdcp_reorder *reorder) -{ -rte_reorder_free (reorder->buf); -}
lib/pdcp/pdcp_reorder.h +9 -3
@@ -9,12 +9,18 @@struct pdcp_reorder {struct rte_reorder_buffer *buf; -uint32_t window_size;bool is_active; }; -int pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size); -void pdcp_reorder_destroy (const struct pdcp_reorder *reorder); +int pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size); + +/* NOTE: replace with `rte_reorder_memory_footprint_get` after DPDK 23.07 */ +#define SIZE_OF_REORDER_BUFFER (4 * RTE_CACHE_LINE_SIZE) +static inline size_t +pdcp_reorder_memory_footprint_get (size_t nb_elem) +{ +return SIZE_OF_REORDER_BUFFER + (2 * nb_elem *sizeof (struct rte_mbuf *)); +} static inline uint32_t pdcp_reorder_get_sequential(struct pdcp_reorder *reorder, struct rte_mbuf **mbufs,
lib/pdcp/rte_pdcp.c +37 -21
124 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 21/22 pdcp: add thread safe processing
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP state has to be guarded for:
- Uplink pre_process:
- tx_next atomic increment
- Downlink pre_process:
- rx_deliv - read
- Downlink post_process:
- rx_deliv, rx_reorder, rx_next - read/write
- bitmask/reorder buffer - read/write
When application requires thread safe processing, the state variables need to be updated atomically. Add config option to select this option per entity.
--- lib/pdcp/pdcp_entity.h | 46 +++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 30 ++++++++++++++++++++++++--- lib/pdcp/rte_pdcp.c | 6 ++++++ lib/pdcp/rte_pdcp.h | 2 ++ 4 files changed, 81 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_entity.h +46 -0
@@ -10,6 +10,7 @@#include <rte_mempool.h> #include <rte_pdcp.h> #include <rte_security.h> +#include <rte_spinlock.h> #include "pdcp_reorder.h"
@@ -162,6 +163,8 @@ struct entity_priv { uint64_t is_status_report_required : 1;/** Is out-of-order delivery enabled */ uint64_t is_out_of_order_delivery : 1; +/** Is thread safety disabled */ + uint64_t is_thread_safety_disabled : 1; } flags;/** Crypto op pool. */ struct rte_mempool *cop_pool;
@@ -175,6 +178,8 @@ struct entity_priv {uint8_t dev_id; }; +typedef rte_spinlock_t pdcp_lock_t ; +struct entity_priv_dl_part {/** PDCP would need to track the count values that are already received.*/ struct pdcp_cnt_bitmap bitmap;
@@ -182,6 +187,8 @@ struct entity_priv_dl_part {struct pdcp_t_reordering t_reorder;/** Reorder packet buffer */ struct pdcp_reorder reorder; +/* Lock to protect concurrent updates */ +pdcp_lock_t lock;/** Bitmap memory region */ uint8_t bitmap_mem[0 ]; };
@@ -257,4 +264,43 @@ pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size)return (1 << (32 - sn_size)) -1 ; } +static inline uint32_t +pdcp_atomic_inc (const struct entity_priv *en_priv,uint32_t *val) +{ +if (en_priv->flags.is_thread_safety_disabled) +return (*val)++; +else +return __atomic_fetch_add (val,1 , __ATOMIC_RELAXED); +} + +static inline void +pdcp_lock_init (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_init (&dl->lock); +} + +static inline void +pdcp_lock_lock (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_lock (&dl->lock); +} + +static inline void +pdcp_lock_unlock (const struct rte_pdcp_entity *entity) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +if (!en_priv->flags.is_thread_safety_disabled) +rte_spinlock_unlock (&dl->lock); +} +#endif /* PDCP_ENTITY_H */
lib/pdcp/pdcp_process.c +27 -3
@@ -369,7 +369,7 @@ pdcp_pre_process_uplane_sn_12_ul_set_sn(struct entity_priv *en_priv, struct rte_return false;/* Update sequence num in the PDU header */ - *count = en_priv->state.tx_next++; + *count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (*count,RTE_SECURITY_PDCP_SN_SIZE_12 ); pdu_hdr->d_c =RTE_PDCP_PDU_TYPE_DATA ;
@@ -451,7 +451,7 @@ pdcp_pre_process_uplane_sn_18_ul_set_sn(struct entity_priv *en_priv, struct rte_return false;/* Update sequence num in the PDU header */ - *count = en_priv->state.tx_next++; + *count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (*count,RTE_SECURITY_PDCP_SN_SIZE_18 ); pdu_hdr->d_c =RTE_PDCP_PDU_TYPE_DATA ;
@@ -561,7 +561,7 @@ pdcp_pre_process_cplane_sn_12_ul(const struct rte_pdcp_entity *entity, struct rtmemset (mac_i,0 ,RTE_PDCP_MAC_I_LEN );/* Update sequence number in the PDU header */ - count = en_priv->state.tx_next++; + count =pdcp_atomic_inc (en_priv, &en_priv->state.tx_next); sn =pdcp_sn_from_count_get (count,RTE_SECURITY_PDCP_SN_SIZE_12 ); pdu_hdr->sn_11_8 = ((sn &0xf00 ) >>8 );
@@ -654,7 +654,9 @@ pdcp_pre_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity, nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -717,7 +719,9 @@ pdcp_pre_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity, nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -781,7 +785,9 @@ pdcp_pre_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity, struct rt nb_cop =rte_crypto_op_bulk_alloc (en_priv->cop_pool,RTE_CRYPTO_OP_TYPE_SYMMETRIC , cop, num); +pdcp_lock_lock (entity);const uint32_t rx_deliv = en_priv->state.rx_deliv; +pdcp_lock_unlock (entity);for (i =0 ; i < nb_cop; i++) { mb = in_mb[i];
@@ -923,6 +929,8 @@ pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity,struct rte_mbuf *mb;uint32_t count; +pdcp_lock_lock (entity); +for (i =0 ; i < num; i++) { mb = in_mb[i];if (unlikely (mb->ol_flags &RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED ))
@@ -949,6 +957,8 @@ pdcp_post_process_uplane_sn_12_dl_flags(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -989,6 +999,7 @@ pdcp_post_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity,int32_t rsn =0 ;uint32_t count; +pdcp_lock_lock (entity);for (i =0 ; i < num; i++) { mb = in_mb[i];
@@ -1017,6 +1028,8 @@ pdcp_post_process_uplane_sn_18_dl_flags(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -1057,6 +1070,8 @@ pdcp_post_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity,uint32_t count;int32_t rsn; +pdcp_lock_lock (entity); +for (i =0 ; i < num; i++) { mb = in_mb[i];if (unlikely (mb->ol_flags &RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED ))
@@ -1082,6 +1097,8 @@ pdcp_post_process_cplane_sn_12_dl(const struct rte_pdcp_entity *entity, err_mb[nb_err++] = mb; } +pdcp_lock_unlock (entity); +if (unlikely (nb_err !=0 ))rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *));
@@ -1245,6 +1262,13 @@ pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct rte_pdcp_ent*/ en_priv->flags.is_out_of_order_delivery = conf->out_of_order_delivery; +/** +* flags.disable_thread_safety +* +* Indicate whether the thread safety is disabled for PDCP entity. +*/ + en_priv->flags.is_thread_safety_disabled = conf->disable_thread_safety; +/** * hdr_sz *
lib/pdcp/rte_pdcp.c +6 -0
@@ -72,6 +72,8 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cif (ret)return ret; +pdcp_lock_init (entity); +return 0 ; }
@@ -276,6 +278,8 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* performing header decompression, if not decompressed before: */ +pdcp_lock_lock (entity); +/* - all stored PDCP SDU(s) with associated COUNT value(s) < RX_REORD; */ nb_out =pdcp_reorder_up_to_get (&dl->reorder, out_mb, capacity, en_priv->state.rx_reord); capacity -= nb_out;
@@ -307,5 +311,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct dl->t_reorder.state =TIMER_EXPIRED ; } +pdcp_lock_unlock (entity); +return nb_out; }
lib/pdcp/rte_pdcp.h +2 -0
@@ -141,6 +141,8 @@ struct rte_pdcp_entity_conf {bool is_slrb;/** Enable security offload on the device specified. */ bool en_sec_offload; +/** Disable usage of synchronization primitives for entity. */ +bool disable_thread_safety;/** Device on which security/crypto session need to be created. */ uint8_t dev_id;/**
Signature · 1 line
2.25.1
Re: [PATCH v3 21/22] pdcp: add thread safe processing
Quoted 14 lines · On Wed, 24 May 2023 21:31:15 +0530 Anoob Joseph <[email protected]> wrote:
From: Volodymyr Fialko <[email protected]>
PDCP state has to be guarded for:
- Uplink
pre_process:
-tx_nextatomic increment- Downlink
pre_process:
-rx_deliv- read- Downlink
post_process:
-rx_deliv,rx_reorder,rx_next- read/write
- bitmask/reorder buffer - read/write
Quoted 6 lines
When application requires thread safe processing, the state variables need to be updated atomically. Add config option to select this option per entity.
Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>
NAK
Conditional locking is a bad design pattern.
It leads to lots of problems, and makes it almost impossible for analysis tools.
RE: [EXT] Re: [PATCH v3 21/22] pdcp: add thread safe processing
Hi Stephen,
Please see inline.
Thanks,
Anoob
Quoted 38 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Thursday, May 25, 2023 12:02 AM
To: Anoob Joseph <[email protected]>
Cc: Thomas Monjalon <[email protected]>; Akhil Goyal <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>; Volodymyr Fialko <[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: [EXT] Re: [PATCH v3 21/22] pdcp: add thread safe processingExternal Email
----------------------------------------------------------------------
Quoted 18 lines · On Wed, 24 May 2023 21:31:15 +0530 Anoob Joseph <[email protected]> wrote:
From: Volodymyr Fialko <[email protected]>
PDCP state has to be guarded for:
- Uplink
pre_process:
-tx_nextatomic increment- Downlink
pre_process:
-rx_deliv- read- Downlink
post_process:
-rx_deliv,rx_reorder,rx_next- read/write
- bitmask/reorder buffer - read/writeWhen application requires thread safe processing, the state variables need to be updated atomically. Add config option to select this option per entity.
Quoted 6 lines
Quoted 2 lines
Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>NAK
Conditional locking is a bad design pattern.
It leads to lots of problems, and makes it almost impossible for analysis tools.
[Anoob] With PDCP (& most other protocols), we have to update the states atomically. Application designers would have a choice of either use single thread or do multi-thread processing. If the library is designed for multi-thread and if application uses only single thread, then there would be unnecessary overheads from library. If library sticks to single-thread and if application needs more threads for scaling, then again it would become a library issue.
Is your issue with providing such an option or is it about how it is implemented? IPsec also has a similar challenge and similar per SA configuration is provided in lib IPsec as well.
Re: [EXT] Re: [PATCH v3 21/22] pdcp: add thread safe processing
Quoted 3 lines · On Thu, 25 May 2023 08:15:07 +0000 Anoob Joseph <[email protected]> wrote:
[Anoob] With PDCP (& most other protocols), we have to update the states atomically. Application designers would have a choice of either use single thread or do multi-thread processing. If the library is designed for multi-thread and if application uses only single thread, then there would be unnecessary overheads from library. If library sticks to single-thread and if application needs more threads for scaling, then again it would become a library issue.
Is your issue with providing such an option or is it about how it is implemented? IPsec also has a similar challenge and similar per SA configuration is provided in lib IPsec as well.
If you want to provide unlocked access, then it should be done with another set of API's.
The cost of conditional branch will be higher than atomic some times.
RE: [EXT] Re: [PATCH v3 21/22] pdcp: add thread safe processing
Hi Stephen,
Please see inline.
Thanks,
Anoob
Quoted 25 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Thursday, May 25, 2023 8:56 PM
To: Anoob Joseph <[email protected]>
Cc: Thomas Monjalon <[email protected]>; Akhil Goyal <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Bernard Iremonger <[email protected]>; Volodymyr Fialko <[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: Re: [EXT] Re: [PATCH v3 21/22] pdcp: add thread safe processingQuoted 1 line · On Thu, 25 May 2023 08:15:07 +0000 Anoob Joseph <[email protected]> wrote:
[Anoob] With PDCP (& most other protocols), we have to update the states
atomically. Application designers would have a choice of either use single thread or do multi-thread processing. If the library is designed for multi- thread and if application uses only single thread, then there would be unnecessary overheads from library. If library sticks to single-thread and if application needs more threads for scaling, then again it would become a library issue.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
Is your issue with providing such an option or is it about how it is
implemented? IPsec also has a similar challenge and similar per SA configuration is provided in lib IPsec as well.
If you want to provide unlocked access, then it should be done with another set of API's.
The cost of conditional branch will be higher than atomic some times.
[Anoob] Understood. I'll try to introduce some const flags so that compiler optimized threads can be registered. That way the conditional branch could be avoided.
PATCH v3 22/22 test/pdcp: add PDCP status report cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Test PDCP status report generation.
--- app/test/test_pdcp.c | 312 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+)
app/test/test_pdcp.c +312 -0
@@ -2,6 +2,7 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_errno.h> #ifdef RTE_LIB_EVENTDEV #include <rte_eventdev.h>
@@ -48,6 +49,9 @@ struct pdcp_testsuite_params {#endif /* RTE_LIB_EVENTDEV */ bool timer_is_running;uint64_t min_resolution_ns; +struct rte_pdcp_up_ctrl_pdu_hdr *status_report; +uint32_t status_report_bitmask_capacity; +uint8_t *ctrl_pdu_buf; };static struct pdcp_testsuite_params testsuite_params;
@@ -168,6 +172,18 @@ static struct rte_pdcp_t_reordering t_reorder_timer = { .stop = pdcp_timer_stop_cb, }; +static inline void +bitmask_set_bit (uint8_t *mask,uint32_t bit) +{ + mask[bit /8 ] |= (1 << bit %8 ); +} + +static inline bool +bitmask_is_bit_set (const uint8_t *mask,uint32_t bit) +{ +return mask[bit /8 ] & (1 << (bit %8 )); +} +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -314,6 +330,21 @@ testsuite_setup(void) goto cop_pool_free; } +/* Allocate memory for longest possible status report */ + ts_params->status_report_bitmask_capacity =RTE_PDCP_CTRL_PDU_SIZE_MAX - +sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ); + ts_params->status_report =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->status_report ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report\n" ); + goto cop_pool_free; + } + + ts_params->ctrl_pdu_buf =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->ctrl_pdu_buf ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report data\n" ); + goto cop_pool_free; + } +return 0 ; cop_pool_free:
@@ -322,6 +353,8 @@ testsuite_setup(void) mbuf_pool_free:rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf);return TEST_FAILED ; }
@@ -344,6 +377,9 @@ testsuite_teardown(void)rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; + +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf); } static int
@@ -1408,6 +1444,246 @@ test_expiry_with_rte_timer(const struct pdcp_test_conf *ul_conf)return ret; } +static struct rte_pdcp_up_ctrl_pdu_hdr * +pdcp_status_report_init (uint32_t fmc) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; + + hdr->d_c =RTE_PDCP_PDU_TYPE_CTRL ; + hdr->pdu_type =RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ; + hdr->fmc =rte_cpu_to_be_32 (fmc); + hdr->r =0 ; +memset (hdr->bitmap,0 , testsuite_params.status_report_bitmask_capacity); + +return hdr; +} + +static uint32_t +pdcp_status_report_len (void ) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; +uint32_t i; + +for (i = testsuite_params.status_report_bitmask_capacity; i !=0 ; i--) { +if (hdr->bitmap[i -1 ]) +return i; + } + +return 0 ; +} + +static int +pdcp_status_report_verify (struct rte_mbuf *status_report, +const struct rte_pdcp_up_ctrl_pdu_hdr *expected_hdr,uint32_t expected_len) +{ +uint32_t received_len =rte_pktmbuf_pkt_len (status_report); +uint8_t *received_buf = testsuite_params.ctrl_pdu_buf; +int ret; + + ret =pktmbuf_read_into (status_report, received_buf,RTE_PDCP_CTRL_PDU_SIZE_MAX ); +TEST_ASSERT_SUCCESS (ret,"Failed to copy status report pkt into continuous buffer" ); + +debug_hexdump (stdout,"Received:" , received_buf, received_len); +debug_hexdump (stdout,"Expected:" , expected_hdr, expected_len); + +TEST_ASSERT_EQUAL (expected_len, received_len, +"Mismatch in packet lengths [expected: %d, received: %d]" , + expected_len, received_len); + +TEST_ASSERT_BUFFERS_ARE_EQUAL (received_buf, expected_hdr, expected_len, +"Generated packet not as expected" ); + +return 0 ; +} + +static int +test_status_report_gen (const struct pdcp_test_conf *ul_conf, +const struct rte_pdcp_up_ctrl_pdu_hdr *hdr, +uint32_t bitmap_len) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *status_report =NULL , **out_mb, *m; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint32_t nb_pkts =0 , i; +uint8_t cdev_id; + +const uint32_t start_count =rte_be_to_cpu_32 (hdr->fmc); + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.status_report_required = true; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + out_mb =calloc (pdcp_entity->max_pkt_cache,sizeof (uintptr_t )); + +for (i =0 ; i < bitmap_len *8 ; i++) { +if (!bitmask_is_bit_set (hdr->bitmap, i)) +continue ; + + m =generate_packet_for_dl_with_sn (*ul_conf, start_count + i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + + } + + m =NULL ; + +/* Check status report */ + status_report =rte_pdcp_control_pdu_create (pdcp_entity, +RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ); +ASSERT_TRUE_OR_GOTO (status_report !=NULL , exit,"Could not generate status report\n" ); + +const uint32_t expected_len =sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ) + bitmap_len; + +ASSERT_TRUE_OR_GOTO (pdcp_status_report_verify (status_report, hdr, expected_len) ==0 , exit, +"Report verification failure\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_free (m); +rte_pktmbuf_free (status_report); +rte_pktmbuf_free_bulk (out_mb, nb_pkts); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +free (out_mb); +return ret; +} + +static void +ctrl_pdu_hdr_packet_set (struct rte_pdcp_up_ctrl_pdu_hdr *hdr,uint32_t pkt_count) +{ +bitmask_set_bit (hdr->bitmap, pkt_count -rte_be_to_cpu_32 (hdr->fmc) -1 ); +} + +static int +test_status_report_fmc_only (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (42 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_first_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_second_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_full_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE +1 ; +int i; + +for (i =0 ; i <RTE_BITMAP_SLAB_BIT_SIZE ; i++) +ctrl_pdu_hdr_packet_set (hdr, start_offset + i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_non_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); +ctrl_pdu_hdr_packet_set (hdr,3 *RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_max_length_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr; +const uint32_t fmc =0 ; +uint32_t i; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + ul_conf->entity.pdcp_xfrm.sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + + hdr =pdcp_status_report_init (fmc); + +const uint32_t max_count =RTE_MIN ((RTE_PDCP_CTRL_PDU_SIZE_MAX -sizeof (hdr)) *8 , + (uint32_t )PDCP_WINDOW_SIZE (RTE_SECURITY_PDCP_SN_SIZE_12 )); + + i = fmc +2 ;/* set first count to have a gap, to enable packet buffering */ + +for (; i < max_count; i++) +ctrl_pdu_hdr_packet_set (hdr, i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_different_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (63 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,64 +1 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_same_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (2 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,4 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1609,11 +1885,47 @@ static struct unit_test_suite reorder_test_cases = { } }; +static struct unit_test_suite status_report_test_cases = { + .suite_name ="PDCP status report" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_status_report_fmc_only" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_fmc_only), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_first_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_first_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_second_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_second_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_full_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_full_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_non_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_non_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_max_length_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_status_report_max_length_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_different_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_different_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_same_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_same_slab), +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, &reorder_test_cases, + &status_report_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
v4 cover lib: add pdcp protocol
In reply to Anoob JosephAdd 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 v4:
- Disabled 'annotate locks' with lib PDCP
- Enable PDCP autotest only when lib is enabled
- Use rwlock instead of spinlock
- Avoid per packet checks for thread safety (Stephen)
- In DL path, save count determined during pre-process in mbuf and use the same in post-process. Determining count again may lead To errors
- Simplified DL path threads to allow more common code between SN 12 & 18
Changes in v3:
- Addressed review comments (Akhil)
- Addressed build failure in CI (tests with lib eventdev disabled)
- Addressed checkpatch issues
- Set only positive values to rte_errno (Akhil)
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 : 112/160 passed, 0/160 skipped, 0/160 failed, 48/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: 48 + Tests Passed : 131
+ 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 for status report
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 | 5 + app/test/test_cryptodev.h | 3 + app/test/test_pdcp.c | 1981 +++++++++++++++++ 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 | 293 +++ lib/meson.build | 1 + lib/net/meson.build | 1 + lib/net/rte_pdcp_hdr.h | 147 ++ lib/pdcp/meson.build | 23 + lib/pdcp/pdcp_cnt.c | 164 ++ lib/pdcp/pdcp_cnt.h | 24 + lib/pdcp/pdcp_crypto.c | 238 ++ lib/pdcp/pdcp_crypto.h | 20 + lib/pdcp/pdcp_ctrl_pdu.c | 72 + lib/pdcp/pdcp_ctrl_pdu.h | 16 + lib/pdcp/pdcp_entity.h | 324 +++ lib/pdcp/pdcp_process.c | 1301 +++++++++++ lib/pdcp/pdcp_process.h | 36 + lib/pdcp/pdcp_reorder.c | 20 + lib/pdcp/pdcp_reorder.h | 68 + lib/pdcp/rte_pdcp.c | 343 +++ lib/pdcp/rte_pdcp.h | 385 ++++ lib/pdcp/rte_pdcp_group.h | 131 ++ lib/pdcp/version.map | 20 + 27 files changed, 5622 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
PATCH v4 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 | 147 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 lib/net/rte_pdcp_hdr.h
doc/api/doxy-api-index.md +2 -1
@@ -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
@@ -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 +147 -0
147 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 2/22 lib: add pdcp protocol
In reply to Anoob JosephAdd 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 | 113 ++++++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 138 +++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 13 +++ lib/pdcp/rte_pdcp.c | 141 ++++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 167 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 10 +++ 12 files changed, 639 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 +113 -0
113 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
@@ -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 +141 -0
141 lines not on this page · raw message
lib/pdcp/rte_pdcp.h new file +167 -0
167 lines not on this page · raw message
lib/pdcp/version.map new file +10 -0
@@ -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
PATCH v4 3/22 pdcp: add pre and post-process
In reply to Anoob JosephPDCP 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
@@ -22,6 +22,21 @@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. *
@@ -33,6 +48,10 @@ extern "C" {* plane depending on which radio bearer it is carrying data for. */ 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
@@ -160,6 +179,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
@@ -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
PATCH v4 4/22 pdcp: add packet group
In reply to Anoob JosephCrypto 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 | 6 ++ lib/pdcp/rte_pdcp_group.h | 131 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 3 + 4 files changed, 141 insertions(+) create mode 100644 lib/pdcp/rte_pdcp_group.h
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']
lib/pdcp/rte_pdcp.h +6 -0
@@ -257,6 +257,12 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,return entity->post_process (entity, in_mb, out_mb, num, nb_err); } +/** +* The header 'rte_pdcp_group.h' depends on defines in 'rte_pdcp.h'. So include +* in the end. +*/ +#include <rte_pdcp_group.h> + #ifdef __cplusplus }#endif
lib/pdcp/rte_pdcp_group.h new file +131 -0
131 lines not on this page · raw message
lib/pdcp/version.map +3 -0
@@ -2,12 +2,15 @@ EXPERIMENTAL { global: # added in 23.07 + rte_pdcp_en_from_cop; + rte_pdcp_entity_establish; rte_pdcp_entity_release; rte_pdcp_entity_suspend; rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_pkt_crypto_group; local: *; };
Signature · 1 line
2.25.1
PATCH v4 5/22 pdcp: add crypto session create and destroy
In reply to Anoob JosephAdd 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 | 223 ++++++++++++++++++++++++++++++++++++++++- lib/pdcp/pdcp_crypto.h | 5 + 2 files changed, 225 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_crypto.c +220 -3
@@ -2,20 +2,237 @@* 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 <rte_pdcp_hdr.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 cipher_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 ) + cipher_iv_len =0 ; +else + cipher_iv_len =PDCP_IV_LEN ; + +if (cipher_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 =RTE_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 ) { +/* rte_errno is set as positive values of 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 +5 -0
@@ -5,8 +5,13 @@#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 +int pdcp_crypto_sess_create (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf);
Signature · 1 line
2.25.1
PATCH v4 6/22 pdcp: add pre and post process for UL
In reply to Anoob JosephAdd 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 | 24 +++ lib/pdcp/pdcp_process.c | 334 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+)
lib/pdcp/pdcp_entity.h +24 -0
@@ -92,22 +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 +334 -0
345 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 7/22 pdcp: add pre and post process for DL
In reply to Anoob JosephAdd routines to perform pre & post processing for down link entities.
--- lib/pdcp/pdcp_entity.h | 2 + lib/pdcp/pdcp_process.c | 383 ++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 10 ++ lib/pdcp/rte_pdcp.c | 23 +++ 4 files changed, 418 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
@@ -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 +383 -0
404 lines not on this page · raw message
lib/pdcp/pdcp_process.h +10 -0
@@ -7,6 +7,16 @@#include <rte_pdcp.h> +typedef uint32_t rte_pdcp_dynfield_t ; + +extern int rte_pdcp_dynfield_offset; + +static inline rte_pdcp_dynfield_t * +pdcp_dynfield (struct rte_mbuf *mbuf) +{ + return RTE_MBUF_DYNFIELD(mbuf, rte_pdcp_dynfield_offset, rte_pdcp_dynfield_t *); +} +int pdcp_process_func_set (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf);
lib/pdcp/rte_pdcp.c +23 -0
@@ -10,6 +10,26 @@#include "pdcp_entity.h" #include "pdcp_process.h" +#define RTE_PDCP_DYNFIELD_NAME "rte_pdcp_dynfield" + +int rte_pdcp_dynfield_offset =-1 ; + +static int +pdcp_dynfield_register (void ) +{ +const struct rte_mbuf_dynfield dynfield_desc = { + .name =RTE_PDCP_DYNFIELD_NAME , + .size =sizeof (rte_pdcp_dynfield_t), + .align = __alignof__(rte_pdcp_dynfield_t ), + }; + +if (rte_pdcp_dynfield_offset !=-1 ) +return rte_pdcp_dynfield_offset; + + rte_pdcp_dynfield_offset =rte_mbuf_dynfield_register (&dynfield_desc); +return rte_pdcp_dynfield_offset; +} +static int pdcp_entity_size_get (const struct rte_pdcp_entity_conf *conf) {
@@ -35,6 +55,9 @@ rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)int ret, entity_size;uint32_t count; +if (pdcp_dynfield_register () <0 ) +return NULL ; +if (conf ==NULL || conf->cop_pool ==NULL ) { rte_errno =EINVAL ;return NULL ;
Signature · 1 line
2.25.1
PATCH v4 8/22 pdcp: add IV generation routines
In reply to Anoob JosephFor 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
@@ -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
PATCH v4 9/22 app/test: add lib pdcp tests
In reply to Anoob JosephAdd tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.
--- app/test/meson.build | 5 + app/test/test_cryptodev.h | 3 + app/test/test_pdcp.c | 732 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 740 insertions(+) create mode 100644 app/test/test_pdcp.c
app/test/meson.build +5 -0
@@ -435,6 +435,11 @@ if dpdk_conf.has('RTE_HAS_LIBPCAP') endif endif +if dpdk_conf.has('RTE_LIB_PDCP') + test_sources += 'test_pdcp.c' + fast_tests += [['pdcp_autotest', false, true]] +endif + if cc.has_argument('-Wno-format-truncation') cflags += '-Wno-format-truncation' endif
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> +#define HEX_DUMP 0#define FALSE 0
app/test/test_pdcp.c new file +732 -0
732 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 10/22 test/pdcp: pdcp HFN tests in combined mode
In reply to Anoob JosephFrom: 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
@@ -16,6 +16,9 @@#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16 +/* 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;
@@ -36,12 +39,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) {
@@ -326,6 +386,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) {
@@ -648,9 +723,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) {
@@ -667,6 +750,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, 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 ; + } + +/* 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.pdcp_xfrm.hfn = new_hfn; + conf->entity.sn = new_sn; + 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.pdcp_xfrm.hfn = rx_deliv_hfn; + dl_conf.entity.sn = rx_deliv_sn; + 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) {
@@ -677,8 +947,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
PATCH v4 11/22 doc: add PDCP library guide
In reply to Anoob JosephAdd guide for PDCP library.
--- .../img/pdcp_functional_overview.svg | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/pdcp_lib.rst | 254 ++++++++++++++++++ 3 files changed, 256 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
@@ -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>
doc/guides/prog_guide/index.rst +1 -0
@@ -77,4 +77,5 @@ Programmer's Guide lto profile_app asan + pdcp_lib glossary
doc/guides/prog_guide/pdcp_lib.rst new file +254 -0
254 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 12/22 pdcp: add control PDU handling for status report
In reply to Anoob JosephAdd control PDU handling and implement status report generation. Status report generation works only when RX_DELIV = RX_NEXT.
--- doc/guides/prog_guide/pdcp_lib.rst | 9 ++++++ 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 | 33 +++++++++++++++++++++ lib/pdcp/version.map | 2 ++ 11 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
doc/guides/prog_guide/pdcp_lib.rst +9 -0
@@ -76,6 +76,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 ``rte_pdcp_control_pdu_create`` allows +application to request the same. + PDCP packet processing API for data PDU ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/pdcp/meson.build +2 -0
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 *ctrl_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
@@ -1091,6 +1091,19 @@ pdcp_entity_priv_populate(struct entity_priv *en_priv, const struct rte_pdcp_entif (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 +33 -0
@@ -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
@@ -79,6 +80,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 *ctrl_pdu_pool;/** * SN value to be used. 32 bit count value to be used for the first * packet would be derived based on HFN (`rte_security_pdcp_xform.hfn`)
@@ -98,6 +101,16 @@ struct rte_pdcp_entity_conf {* 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_control_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. */
@@ -179,6 +192,26 @@ 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. The control PDU packet +* would be allocated from *rte_pdcp_entity_conf.ctrl_pdu_pool* by lib PDCP. +* +* @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
@@ -2,6 +2,8 @@ EXPERIMENTAL { global: # added in 23.07 + rte_pdcp_control_pdu_create; + rte_pdcp_en_from_cop; rte_pdcp_entity_establish;
Signature · 1 line
2.25.1
PATCH v4 13/22 pdcp: implement t-Reordering and packet buffering
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add in-order delivery of packets in PDCP. Delivery of packets in-order relies on t-Reordering timer.
When 'out-of-order delivery' is disabled, PDCP will buffer all received packets that are out of order. The t-Reordering timer determines the time period these packets would be held in the buffer, waiting for any missing packets to arrive.
Introduce packet buffering and state variables which indicate status of the timer.
--- lib/pdcp/meson.build | 3 +- lib/pdcp/pdcp_entity.h | 19 +++++++ lib/pdcp/pdcp_process.c | 117 ++++++++++++++++++++++++++++++---------- lib/pdcp/pdcp_reorder.c | 27 ++++++++++ lib/pdcp/pdcp_reorder.h | 62 +++++++++++++++++++++ lib/pdcp/rte_pdcp.c | 53 ++++++++++++++++-- lib/pdcp/rte_pdcp.h | 6 ++- 7 files changed, 252 insertions(+), 35 deletions(-) create mode 100644 lib/pdcp/pdcp_reorder.c create mode 100644 lib/pdcp/pdcp_reorder.h
lib/pdcp/meson.build +2 -1
@@ -12,9 +12,10 @@ sources = files( 'pdcp_crypto.c', 'pdcp_ctrl_pdu.c', 'pdcp_process.c', + 'pdcp_reorder.c', 'rte_pdcp.c', ) headers = files('rte_pdcp.h') indirect_headers += files('rte_pdcp_group.h') -deps += ['mbuf', 'net', 'cryptodev', 'security'] +deps += ['mbuf', 'net', 'cryptodev', 'security', 'reorder']
lib/pdcp/pdcp_entity.h +19 -0
@@ -11,6 +11,8 @@#include <rte_pdcp.h> #include <rte_security.h> +#include "pdcp_reorder.h" +struct entity_priv ;#define PDCP_HFN_MIN 0
@@ -109,6 +111,17 @@ union cipher_iv_partial {uint64_t u64[2 ]; }; +enum timer_state { +TIMER_STOP , +TIMER_RUNNING , +TIMER_EXPIRED , +}; + +struct pdcp_t_reordering { +/** Represent timer state */ +enum timer_state state; +}; +struct pdcp_cnt_bitmap {/** Number of entries that can be stored. */ uint32_t size;
@@ -145,6 +158,8 @@ struct entity_priv { uint64_t is_null_auth : 1;/** Is status report required.*/ uint64_t is_status_report_required : 1; +/** Is out-of-order delivery enabled */ + uint64_t is_out_of_order_delivery : 1; } flags;/** Crypto op pool. */ struct rte_mempool *cop_pool;
@@ -161,6 +176,10 @@ struct entity_priv {struct entity_priv_dl_part {/** PDCP would need to track the count values that are already received.*/ struct pdcp_cnt_bitmap bitmap; +/** t-Reordering handles */ +struct pdcp_t_reordering t_reorder; +/** Reorder packet buffer */ +struct pdcp_reorder reorder; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +90 -27
176 lines not on this page · raw message
lib/pdcp/pdcp_reorder.c new file +27 -0
@@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(C) 2023 Marvell. +*/ + +#include <rte_errno.h> +#include <rte_reorder.h> + +#include "pdcp_reorder.h" + +int +pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +{ + reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); +if (reorder->buf ==NULL ) +return -rte_errno; + + reorder->window_size = window_size; + reorder->is_active = false; + +return 0 ; +} + +void +pdcp_reorder_destroy (const struct pdcp_reorder *reorder) +{ +rte_reorder_free (reorder->buf); +}
lib/pdcp/pdcp_reorder.h new file +62 -0
62 lines not on this page · raw message
lib/pdcp/rte_pdcp.c +48 -5
99 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +4 -2
@@ -111,6 +111,8 @@ struct rte_pdcp_entity_conf {* as entity re-establishment. */ bool status_report_required; +/** Enable out of order delivery. */ +bool out_of_order_delivery; };/* >8 End of structure rte_pdcp_entity_conf. */
@@ -271,8 +273,8 @@ rte_pdcp_pkt_pre_process(const struct rte_pdcp_entity *entity,* @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. +* The address of an array that can hold up to *rte_pdcp_entity.max_pkt_cache* +* 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
Signature · 1 line
2.25.1
PATCH v4 14/22 test/pdcp: add in-order delivery cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases to verify behaviour when in-order delivery is enabled and packets arrive in out-of-order. PDCP library is expected to buffer the packets and return packets in-order when the missing packet arrives.
--- app/test/test_pdcp.c | 223 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+)
app/test/test_pdcp.c +223 -0
@@ -16,6 +16,15 @@#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16 +/* Assert that condition is true, or goto the mark */ +#define ASSERT_TRUE_OR_GOTO (cond, mark, ...) do {\ + if (!(cond)) { \ + RTE_LOG(ERR, USER1, "Error at: %s:%d\n", __func__, __LINE__); \ + RTE_LOG(ERR, USER1, __VA_ARGS__); \ + goto mark; \ + } \ +} while (0) +/* According to formula(7.2.a Window_Size) */ #define PDCP_WINDOW_SIZE (sn_size) (1 << (sn_size - 1))
@@ -83,6 +92,38 @@ run_test_with_all_known_vec(const void *args)return run_test_foreach_known_vec (test, false); } +static int +run_test_with_all_known_vec_until_first_pass (const void *args) +{ +test_with_conf_t test = args; + +return run_test_foreach_known_vec (test, true); +} + +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 int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -416,6 +457,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.ctrl_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 ;
@@ -868,6 +910,7 @@ test_sn_range_type(enum sn_range_type type, struct pdcp_test_conf *conf)/* Configure Uplink to generate expected, encrypted packet */ pdcp_sn_to_raw_set (conf->input, new_sn, conf->entity.pdcp_xfrm.sn_size); + conf->entity.out_of_order_delivery = true; conf->entity.reverse_iv_direction = true; conf->entity.pdcp_xfrm.hfn = new_hfn; conf->entity.sn = new_sn;
@@ -915,6 +958,171 @@ test_sn_minus_outside(struct pdcp_test_conf *t_conf)return test_sn_range_type (SN_RANGE_MINUS_OUTSIDE , t_conf); } +static struct rte_mbuf * +generate_packet_for_dl_with_sn (struct pdcp_test_conf ul_conf,uint32_t count) +{ +enum rte_security_pdcp_sn_size sn_size = ul_conf.entity.pdcp_xfrm.sn_size; +int ret; + + ul_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (count, sn_size); + ul_conf.entity.sn =pdcp_sn_from_count_get (count, sn_size); + ul_conf.entity.out_of_order_delivery = true; + ul_conf.entity.reverse_iv_direction = true; + ul_conf.output_len =0 ; + + ret =test_attempt_single (&ul_conf); +if (ret !=TEST_SUCCESS ) +return NULL ; + +return mbuf_from_data_create (ul_conf.output, ul_conf.output_len); +} + +static bool +array_asc_sorted_check (struct rte_mbuf *m[],uint32_t len,enum rte_security_pdcp_sn_size sn_size) +{ +uint32_t i; + +if (len <2 ) +return true; + +for (i =0 ; i < (len -1 ); i++) { + if (pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i], void *), sn_size) > + pdcp_sn_from_raw_get(rte_pktmbuf_mtod(m[i + 1], void *), sn_size)) +return false; + } + +return true; +} + +static int +test_reorder_gap_fill (struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m0 =NULL , *m1 =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Generate packet to fill the existing gap */ + m0 =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m0 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1] +* Gap filled, all packets should be returned +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m0,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m0 =NULL ;/* Packet was moved to out_mb */ + +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit, +"Error occurred during packet drain\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m0); +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} + +static int +test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +const uint32_t window_size =PDCP_WINDOW_SIZE (sn_size); +struct rte_mbuf *m1 =NULL , **out_mb =NULL ; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +const int rx_deliv =0 ; +int ret =TEST_FAILED ; +size_t i, nb_out; +uint8_t cdev_id; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (rx_deliv, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (rx_deliv, sn_size); + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + +ASSERT_TRUE_OR_GOTO (pdcp_entity->max_pkt_cache >= window_size, exit, +"PDCP max packet cache is too small" ); + cdev_id = dl_conf.entity.dev_id; + out_mb =rte_zmalloc (NULL , pdcp_entity->max_pkt_cache *sizeof (uintptr_t ),0 ); +ASSERT_TRUE_OR_GOTO (out_mb !=NULL , exit, +"Could not allocate buffer for holding out_mb buffers\n" ); + +/* Send packets with SN > RX_DELIV to create a gap */ +for (i = rx_deliv +1 ; i < window_size; i++) { + m1 =generate_packet_for_dl_with_sn (*ul_conf, i); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Buffered packets after insert [NULL, m1] */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + } + + m1 =generate_packet_for_dl_with_sn (*ul_conf, rx_deliv); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); +/* Insert missing packet */ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success == window_size, exit, +"Packet count mismatch (received: %i, expected: %i)\n" , + nb_success, window_size); + m1 =NULL ; + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +rte_free (out_mb); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -971,10 +1179,25 @@ static struct unit_test_suite hfn_sn_test_cases = { } }; +static struct unit_test_suite reorder_test_cases = { + .suite_name ="PDCP reorder" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_buffer_full_window_size_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_reorder_buffer_full_window_size_sn_12), +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, + &reorder_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
PATCH v4 15/22 pdcp: add timer callback handlers
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP has a windowing mechanism which allows only packets that fall in a reception window. The pivot point for this window is RX_REORD which happens to be the first missing or next expected packet. If the missing packet is not received after a specified time, then the RX_REORD state variable needs to be moved up to slide the reception window. PDCP relies on timers for such operations.
The timer needs to be armed when PDCP library doesn't receive all packets in-order and starts buffering packets that arrived after a missing packet. The timer needs to be cancelled when a missing packet is received.
To avoid dependency on particular timer implementation, PDCP library allows application to register two callbacks, timer_start() and timer_stop() that will be called later by library.
--- lib/pdcp/pdcp_entity.h | 2 ++ lib/pdcp/pdcp_process.c | 2 ++ lib/pdcp/rte_pdcp.c | 1 + lib/pdcp/rte_pdcp.h | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+)
lib/pdcp/pdcp_entity.h +2 -0
@@ -120,6 +120,8 @@ enum timer_state {struct pdcp_t_reordering {/** Represent timer state */ enum timer_state state; +/** User defined callback handles */ +struct rte_pdcp_t_reordering handle; };struct pdcp_cnt_bitmap {
lib/pdcp/pdcp_process.c +2 -0
@@ -901,6 +901,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (t_reorder->state ==TIMER_RUNNING && en_priv->state.rx_deliv >= en_priv->state.rx_reord) { t_reorder->state =TIMER_STOP ; + t_reorder->handle.stop (t_reorder->handle.timer, t_reorder->handle.args);/* Stop reorder buffer, only if it's empty */ if (en_priv->state.rx_deliv == en_priv->state.rx_next)pdcp_reorder_stop (reorder);
@@ -915,6 +916,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, en_priv->state.rx_reord = en_priv->state.rx_next;/* Start t-Reordering */ t_reorder->state =TIMER_RUNNING ; + t_reorder->handle.start (t_reorder->handle.timer, t_reorder->handle.args); }return processed;
lib/pdcp/rte_pdcp.c +1 -0
@@ -56,6 +56,7 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cstruct entity_priv_dl_part *dl =entity_dl_part_get (entity); entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); + dl->t_reorder.handle = conf->t_reordering;return pdcp_reorder_create (&dl->reorder, window_size); }
lib/pdcp/rte_pdcp.h +47 -0
59 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 16/22 pdcp: add timer expiry handle
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
The PDCP protocol requires usage of timers to keep track of how long an out-of-order packet should be buffered while waiting for missing packets. Applications can register a desired timer implementation with the PDCP library. Once the timer expires, the application will be notified, and further handling of the event will be performed in the PDCP library.
When the timer expires, the PDCP library will return the cached packets, and PDCP internal state variables (like RX_REORD, RX_DELIV etc) will be updated accordingly.
--- doc/guides/prog_guide/pdcp_lib.rst | 30 ++++++++++++++++++ lib/pdcp/rte_pdcp.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 31 +++++++++++++++++++ lib/pdcp/version.map | 2 ++ 4 files changed, 112 insertions(+)
doc/guides/prog_guide/pdcp_lib.rst +30 -0
@@ -130,6 +130,36 @@ Supported integrity protection algorithms - SNOW3G-AUTH - ZUC-AUTH +Timers +------ + +PDCP utilizes a reception window mechanism to limit the bits of COUNT value +transmitted in the packet. It utilizes state variables such as RX_REORD, +RX_DELIV to define the window and uses RX_DELIV as the lower pivot point of the +window. + +RX_DELIV would be updated only when packets are received in-order. Any missing +packet would mean RX_DELIV won't be updated. A timer, t-Reordering, helps PDCP +to slide the window if the missing packet is not received in a specified time +duration. + +While starting and stopping the timer need to be done by lib PDCP, application +could register its own timer implementation. This is to make sure application +can choose between timers such as rte_timer and rte_event based timers. Starting +and stopping of timer would happen during pre & post process API. + +When the t-Reordering timer expires, application would receive the expiry event. +To perform the PDCP handling of the expiry event, +``rte_pdcp_t_reordering_expiry_handle`` can be used. Expiry handling would +involve sliding the window by updating state variables and passing the expired +packets to the application. + +.. literalinclude:: ../../../lib/pdcp/rte_pdcp.h + :language: c + :start-after: Structure rte_pdcp_t_reordering 8< + :end-before: >8 End of structure rte_pdcp_t_reordering. + + Sample API usage ----------------
lib/pdcp/rte_pdcp.c +49 -0
52 lines not on this page · raw message
lib/pdcp/rte_pdcp.h +31 -0
@@ -101,6 +101,7 @@ typedef void (*rte_pdcp_t_reordering_stop_cb_t)(void *timer, void *args);* * Configuration provided by user, that PDCP library will invoke according to timer behaviour. */ +/* Structure rte_pdcp_t_reordering 8< */ struct rte_pdcp_t_reordering {/** Timer pointer, stored for later use in callback functions */ void *timer;
@@ -111,6 +112,7 @@ struct rte_pdcp_t_reordering {/** Timer stop callback handle */ rte_pdcp_t_reordering_stop_cb_t stop; }; +/* >8 End of structure rte_pdcp_t_reordering. */ /** * PDCP entity configuration to be used for establishing an entity.
@@ -339,6 +341,35 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,return entity->post_process (entity, in_mb, out_mb, num, nb_err); } +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* 5.2.2.2 Actions when a t-Reordering expires +* +* When t-Reordering timer expires, PDCP is required to slide the reception +* window by updating state variables such as RX_REORD & RX_DELIV. PDCP would +* need to deliver some of the buffered packets based on the state variables and +* conditions described. +* +* The expiry handle need to be invoked by the application when t-Reordering +* timer expires. In addition to returning buffered packets, it may also restart +* timer based on the state variables. +* +* @param entity +* Pointer to the *rte_pdcp_entity* for which the timer expired. +* @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. Used to return buffered packets that are +* expired. +* @return +* Number of packets returned in *out_mb* buffer. +*/ +__rte_experimental +uint16_t +rte_pdcp_t_reordering_expiry_handle (const struct rte_pdcp_entity *entity, +struct rte_mbuf *out_mb[]); +/** * The header 'rte_pdcp_group.h' depends on defines in 'rte_pdcp.h'. So include * in the end.
lib/pdcp/version.map +2 -0
@@ -14,5 +14,7 @@ EXPERIMENTAL { rte_pdcp_pkt_pre_process; rte_pdcp_pkt_crypto_group; + rte_pdcp_t_reordering_expiry_handle; + local: *; };
Signature · 1 line
2.25.1
PATCH v4 17/22 test/pdcp: add timer expiry cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test cases for handling the expiry with rte_timer and rte_event_timer.
--- app/test/test_pdcp.c | 350 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+)
app/test/test_pdcp.c +350 -0
@@ -3,15 +3,24 @@*/ #include <rte_errno.h> +#ifdef RTE_LIB_EVENTDEV +#include <rte_eventdev.h> +#include <rte_event_timer_adapter.h> +#endif /* RTE_LIB_EVENTDEV */ #include <rte_malloc.h> #include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include <rte_timer.h> #include "test.h" #include "test_cryptodev.h" #include "test_cryptodev_security_pdcp_test_vectors.h" +#define NSECPERSEC 1E9#define NB_DESC 1024 +#define TIMER_ADAPTER_ID 0 +#define TEST_EV_QUEUE_ID 0 +#define TEST_EV_PORT_ID 0#define CDEV_INVALID_ID UINT8_MAX#define NB_TESTS RTE_DIM(pdcp_test_params)#define PDCP_IV_LEN 16
@@ -33,10 +42,21 @@ struct pdcp_testsuite_params {struct rte_mempool *cop_pool;struct rte_mempool *sess_pool;bool cdevs_used[RTE_CRYPTO_MAX_DEVS ]; +int evdev; +#ifdef RTE_LIB_EVENTDEV +struct rte_event_timer_adapter *timdev; +#endif /* RTE_LIB_EVENTDEV */ +bool timer_is_running; +uint64_t min_resolution_ns; };static struct pdcp_testsuite_params testsuite_params; +struct test_rte_timer_args { +int status; +struct rte_pdcp_entity *pdcp_entity; +}; +struct pdcp_test_conf {struct rte_pdcp_entity_conf entity;struct rte_crypto_sym_xform c_xfrm;
@@ -124,6 +144,30 @@ 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 void +pdcp_timer_start_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = true; +} + +static void +pdcp_timer_stop_cb (void *timer,void *args) +{ +bool *is_timer_running = timer; + +RTE_SET_USED (args); + *is_timer_running = false; +} + +static struct rte_pdcp_t_reordering t_reorder_timer = { + .timer = &testsuite_params.timer_is_running, + .start = pdcp_timer_start_cb, + .stop = pdcp_timer_stop_cb, +}; +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -462,6 +506,7 @@ create_test_conf_from_index(const int index, struct pdcp_test_conf *conf) conf->entity.pdcp_xfrm.en_ordering =0 ; conf->entity.pdcp_xfrm.remove_duplicates =0 ; conf->entity.pdcp_xfrm.domain = pdcp_test_params[index].domain; + conf->entity.t_reordering = t_reorder_timer;if (pdcp_test_packet_direction[index] ==PDCP_DIR_UPLINK ) conf->entity.pdcp_xfrm.pkt_dir =RTE_SECURITY_PDCP_UPLINK ;
@@ -1048,6 +1093,8 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)/* Check that packets in correct order */ ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == false, exit, +"Timer should be stopped after full drain\n" ); ret =TEST_SUCCESS ; exit:
@@ -1123,6 +1170,181 @@ test_reorder_buffer_full_window_size_sn_12(const struct pdcp_test_conf *ul_conf)return ret; } +#ifdef RTE_LIB_EVENTDEV +static void +event_timer_start_cb (void *timer,void *args) +{ +struct rte_event_timer *evtims = args; +int ret =0 ; + + ret =rte_event_timer_arm_burst (timer, &evtims,1 ); +assert (ret ==1 ); +} +#endif /* RTE_LIB_EVENTDEV */ + +static int +test_expiry_with_event_timer (const struct pdcp_test_conf *ul_conf) +{ +#ifdef RTE_LIB_EVENTDEV +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_event event; + +const int start_count =0 ; +struct rte_event_timer evtim = { + .ev.op =RTE_EVENT_OP_NEW , + .ev.queue_id =TEST_EV_QUEUE_ID , + .ev.sched_type =RTE_SCHED_TYPE_ATOMIC , + .ev.priority =RTE_EVENT_DEV_PRIORITY_NORMAL , + .ev.event_type =RTE_EVENT_TYPE_TIMER , + .state =RTE_EVENT_TIMER_NOT_ARMED , + .timeout_ticks =1 , + }; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.t_reordering.args = &evtim; + dl_conf.entity.t_reordering.timer = testsuite_params.timdev; + dl_conf.entity.t_reordering.start = event_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + evtim.ev.event_ptr = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +while (n !=1 ) { +rte_delay_us (testsuite_params.min_resolution_ns /1000 ); + n =rte_event_dequeue_burst (testsuite_params.evdev,TEST_EV_PORT_ID , &event,1 ,0 ); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit, +"Dequeued unexpected timer expiry event: %i\n" , n); + } + +ASSERT_TRUE_OR_GOTO (event.event_type ==RTE_EVENT_TYPE_TIMER , exit,"Unexpected event type\n" ); + +/* Handle expiry event */ + n =rte_pdcp_t_reordering_expiry_handle (event.event_ptr, out_mb); +ASSERT_TRUE_OR_GOTO (n ==1 , exit,"Unexpected number of expired packets :%i\n" , n); + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +#else +RTE_SET_USED (ul_conf); +return TEST_SKIPPED ; +#endif /* RTE_LIB_EVENTDEV */ +} + +static void +test_rte_timer_expiry_handle (struct rte_timer *timer_handle,void *arg) +{ +struct test_rte_timer_args *timer_data = arg; +struct rte_mbuf *out_mb[1 ] = {0 }; +uint16_t n; + +RTE_SET_USED (timer_handle); + + n =rte_pdcp_t_reordering_expiry_handle (timer_data->pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, n); + + timer_data->status = n ==1 ? n :-1 ; +} + +static void +test_rte_timer_start_cb (void *timer,void *args) +{ +rte_timer_reset_sync (timer,1 ,SINGLE ,rte_lcore_id (), test_rte_timer_expiry_handle, args); +} + +static int +test_expiry_with_rte_timer (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m1 =NULL , *out_mb[1 ] = {0 }; +uint16_t n =0 , nb_err =0 , nb_try =5 ; +struct test_rte_timer_args timer_args; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +struct rte_timer timer = {0 }; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Set up a timer */ +rte_timer_init (&timer); + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.t_reordering.args = &timer_args; + dl_conf.entity.t_reordering.timer = &timer; + dl_conf.entity.t_reordering.start = test_rte_timer_start_cb; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + timer_args.status =0 ; + timer_args.pdcp_entity = pdcp_entity; + +/* Send packet with SN > RX_DELIV to create a gap */ + m1 =generate_packet_for_dl_with_sn (*ul_conf, start_count +1 ); +ASSERT_TRUE_OR_GOTO (m1 !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* Buffered packets after insert [NULL, m1] */ + n =test_process_packets (pdcp_entity, dl_conf.entity.dev_id, &m1,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (n ==0 , exit,"Packet was not buffered as expected\n" ); + + m1 =NULL ;/* Packet was moved to PDCP lib */ + +/* Verify that expire was handled correctly */ +rte_timer_manage (); +while (timer_args.status !=1 ) { +rte_delay_us (1 ); +rte_timer_manage (); +ASSERT_TRUE_OR_GOTO (nb_try-- >0 , exit,"Bad expire handle status %i\n" , + timer_args.status); + } + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m1); +rte_pktmbuf_free_bulk (out_mb, n); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1145,6 +1367,126 @@ test_combined(struct pdcp_test_conf *ul_conf)return ret; } +#ifdef RTE_LIB_EVENTDEV +static inline void +eventdev_conf_default_set (struct rte_event_dev_config *dev_conf,struct rte_event_dev_info *info) +{ +memset (dev_conf,0 ,sizeof (struct rte_event_dev_config )); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports =1 ; + dev_conf->nb_event_queues =1 ; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = info->max_num_events; +} + +static inline int +eventdev_setup (void ) +{ +struct rte_event_dev_config dev_conf; +struct rte_event_dev_info info; +int ret, evdev =0 ; + +if (!rte_event_dev_count ()) +return TEST_SKIPPED ; + + ret =rte_event_dev_info_get (evdev, &info); +TEST_ASSERT_SUCCESS (ret,"Failed to get event dev info" ); +TEST_ASSERT (info.max_num_events <0 || info.max_num_events >=1 , +"ERROR max_num_events=%d < max_events=%d" , info.max_num_events,1 ); + +eventdev_conf_default_set (&dev_conf, &info); + ret =rte_event_dev_configure (evdev, &dev_conf); +TEST_ASSERT_SUCCESS (ret,"Failed to configure eventdev" ); + + ret =rte_event_queue_setup (evdev,TEST_EV_QUEUE_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup queue=%d" ,TEST_EV_QUEUE_ID ); + +/* Configure event port */ + ret =rte_event_port_setup (evdev,TEST_EV_PORT_ID ,NULL ); +TEST_ASSERT_SUCCESS (ret,"Failed to setup port=%d" ,TEST_EV_PORT_ID ); + ret =rte_event_port_link (evdev,TEST_EV_PORT_ID ,NULL ,NULL ,0 ); +TEST_ASSERT (ret >=0 ,"Failed to link all queues port=%d" ,TEST_EV_PORT_ID ); + + ret =rte_event_dev_start (evdev); +TEST_ASSERT_SUCCESS (ret,"Failed to start device" ); + + testsuite_params.evdev = evdev; + +return TEST_SUCCESS ; +} + +static int +event_timer_setup (void ) +{ +struct rte_event_timer_adapter_info info; +struct rte_event_timer_adapter *timdev; +uint32_t caps =0 ; + +struct rte_event_timer_adapter_conf config = { + .event_dev_id = testsuite_params.evdev, + .timer_adapter_id =TIMER_ADAPTER_ID , + .timer_tick_ns =NSECPERSEC , + .max_tmo_ns =10 *NSECPERSEC , + .nb_timers =10 , + .flags =0 , + }; + +TEST_ASSERT_SUCCESS (rte_event_timer_adapter_caps_get (testsuite_params.evdev, &caps), +"Failed to get adapter capabilities" ); + +if (!(caps &RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT )) +return TEST_SKIPPED ; + + timdev =rte_event_timer_adapter_create (&config); + +TEST_ASSERT_NOT_NULL (timdev,"Failed to create event timer ring" ); + + testsuite_params.timdev = timdev; + +TEST_ASSERT_EQUAL (rte_event_timer_adapter_start (timdev),0 , +"Failed to start event timer adapter" ); + +rte_event_timer_adapter_get_info (timdev, &info); + testsuite_params.min_resolution_ns = info.min_resolution_ns; + +return TEST_SUCCESS ; +} +#endif /* RTE_LIB_EVENTDEV */ + +static int +ut_setup_pdcp_event_timer (void ) +{ +#ifdef RTE_LIB_EVENTDEV +int ret; + + ret =eventdev_setup (); +if (ret) +return ret; + +return event_timer_setup (); +#else +return TEST_SKIPPED ; +#endif /* RTE_LIB_EVENTDEV */ +} + +static void +ut_teardown_pdcp_event_timer (void ) +{ +#ifdef RTE_LIB_EVENTDEV +struct rte_event_timer_adapter *timdev = testsuite_params.timdev; +int evdev = testsuite_params.evdev; + +rte_event_dev_stop (evdev); +rte_event_dev_close (evdev); + +rte_event_timer_adapter_stop (timdev); +rte_event_timer_adapter_free (timdev); +#endif /* RTE_LIB_EVENTDEV */ +} +static int run_test_for_one_known_vec (const void *arg) {
@@ -1189,6 +1531,14 @@ static struct unit_test_suite reorder_test_cases = { ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass, test_reorder_buffer_full_window_size_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_event_timer" , + ut_setup_pdcp_event_timer, ut_teardown_pdcp_event_timer, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_event_timer), +TEST_CASE_NAMED_WITH_DATA ("test_expire_with_rte_timer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_expiry_with_rte_timer), TEST_CASES_END() /**< NULL terminate unit test array */ } };
Signature · 1 line
2.25.1
PATCH v4 18/22 test/pdcp: add timer restart case
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Add test to cover the case when t-reordering timer should be restarted on the same packet.
--- app/test/test_pdcp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
app/test/test_pdcp.c +68 -0
@@ -1106,6 +1106,71 @@ test_reorder_gap_fill(struct pdcp_test_conf *ul_conf)return ret; } +static int +test_reorder_gap_in_reorder_buffer (const struct pdcp_test_conf *ul_conf) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *m =NULL , *out_mb[2 ] = {0 }; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +int ret =TEST_FAILED , nb_out, i; +struct pdcp_test_conf dl_conf; +uint8_t cdev_id; + +const int start_count =0 ; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + +/* Create two gaps [NULL, m1, NULL, m3]*/ +for (i =0 ; i <2 ; i++) { + m =generate_packet_for_dl_with_sn (*ul_conf, start_count +2 * i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + m =NULL ;/* Packet was moved to PDCP lib */ + } + +/* Generate packet to fill the first gap */ + m =generate_packet_for_dl_with_sn (*ul_conf, start_count); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + +/* +* Buffered packets after insert [m0, m1, NULL, m3] +* Only first gap should be filled, timer should be restarted for second gap +*/ + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet process\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==2 , exit, +"Packet count mismatch (received: %i, expected: 2)\n" , nb_success); + m =NULL ; +/* Check that packets in correct order */ +ASSERT_TRUE_OR_GOTO (array_asc_sorted_check (out_mb, nb_success, sn_size), + exit,"Error occurred during packet drain\n" ); +ASSERT_TRUE_OR_GOTO (testsuite_params.timer_is_running == true, exit, +"Timer should be restarted after partial drain" ); + + + ret =TEST_SUCCESS ; +exit: +rte_pktmbuf_free (m); +rte_pktmbuf_free_bulk (out_mb, nb_success); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +return ret; +} +static int test_reorder_buffer_full_window_size_sn_12 (const struct pdcp_test_conf *ul_conf) {
@@ -1527,6 +1592,9 @@ static struct unit_test_suite reorder_test_cases = {TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_fill" , ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec, test_reorder_gap_fill), +TEST_CASE_NAMED_WITH_DATA ("test_reorder_gap_in_reorder_buffer" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_reorder_gap_in_reorder_buffer), TEST_CASE_NAMED_WITH_DATA("test_reorder_buffer_full_window_size_sn_12", ut_setup_pdcp, ut_teardown_pdcp, run_test_with_all_known_vec_until_first_pass,
Signature · 1 line
2.25.1
PATCH v4 19/22 pdcp: add support for status report
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Implement status report generation for PDCP entity.
--- lib/pdcp/pdcp_cnt.c | 158 ++++++++++++++++++++++++++++++++++++--- lib/pdcp/pdcp_cnt.h | 11 ++- lib/pdcp/pdcp_ctrl_pdu.c | 34 ++++++++- lib/pdcp/pdcp_ctrl_pdu.h | 3 +- lib/pdcp/pdcp_entity.h | 2 + lib/pdcp/pdcp_process.c | 9 ++- lib/pdcp/pdcp_process.h | 13 ++++ lib/pdcp/rte_pdcp.c | 34 ++++++--- 8 files changed, 236 insertions(+), 28 deletions(-)
lib/pdcp/pdcp_cnt.c +147 -11
@@ -2,28 +2,164 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_pdcp.h> #include "pdcp_cnt.h" +#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#define SLAB_BYTE_SIZE (RTE_BITMAP_SLAB_BIT_SIZE / 8) + +uint32_t +pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf) +{ +uint32_t n_bits =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); + +return rte_bitmap_get_memory_footprint (n_bits); +} +int -pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) { -struct entity_priv_dl_part *en_priv_dl; -uint32_t window_sz; +uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); -if (en ==NULL || conf ==NULL ) + dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); +if (dl->bitmap.bmp ==NULL )return -EINVAL ; -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) -return 0 ; + dl->bitmap.size = window_size; - en_priv_dl =entity_dl_part_get (en); - window_sz =pdcp_window_size_get (conf->pdcp_xfrm.sn_size); +return 0 ; +} -RTE_SET_USED (window_sz); -RTE_SET_USED (en_priv_dl); +void +pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +rte_bitmap_set (bitmap.bmp, count % bitmap.size); +} -return 0 ; +bool +pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count) +{ +return rte_bitmap_get (bitmap.bmp, count % bitmap.size); +} + +void +pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop) +{ +uint32_t i; + +for (i = start; i < stop; i++) +rte_bitmap_clear (bitmap.bmp, i % bitmap.size); +} + +uint16_t +pdcp_cnt_get_bitmap_size (uint32_t pending_bytes) +{ +/* +* Round up bitmap size to slab size to operate only on slabs sizes, instead of individual +* bytes +*/ +return RTE_ALIGN_MUL_CEIL (pending_bytes,SLAB_BYTE_SIZE ); +} + +static __rte_always_inline uint64_t +leftover_get (uint64_t slab,uint32_t shift,uint64_t mask) +{ +return (slab & mask) << shift; +} + +void +pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len) +{ +uint64_t slab =0 , next_slab =0 , leftover; +uint32_t zeros, report_len, diff; +uint32_t slab_id, next_slab_id; +uint32_t pos =0 , next_pos =0 ; + +const uint32_t start_count = state.rx_deliv +1 ; +const uint32_t nb_slabs = bitmap.size /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t nb_data_slabs = data_len /SLAB_BYTE_SIZE ; +const uint32_t start_slab_id = start_count /RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t stop_slab_id = (start_slab_id + nb_data_slabs) % nb_slabs; +const uint32_t shift = start_count %RTE_BITMAP_SLAB_BIT_SIZE ; +const uint32_t leftover_shift = shift ?RTE_BITMAP_SLAB_BIT_SIZE - shift :0 ; +const uint8_t *data_end =RTE_PTR_ADD (data, data_len +SLAB_BYTE_SIZE ); + +/* NOTE: Mask required to workaround case - when shift is not needed */ +const uint64_t leftover_mask = shift ? ~0 :0 ; + +/* NOTE: implement scan init at to set custom position */ +__rte_bitmap_scan_init (bitmap.bmp); +while (true) { +assert (rte_bitmap_scan (bitmap.bmp, &pos, &slab) ==1 ); + slab_id = pos /RTE_BITMAP_SLAB_BIT_SIZE ; +if (slab_id >= start_slab_id) +break ; + } + + report_len = nb_data_slabs; + +if (slab_id > start_slab_id) { +/* Zero slabs at beginning */ + zeros = (slab_id - start_slab_id -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + leftover =leftover_get (slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + report_len -= (slab_id - start_slab_id); + } + +while (report_len) { +rte_bitmap_scan (bitmap.bmp, &next_pos, &next_slab); + next_slab_id = next_pos /RTE_BITMAP_SLAB_BIT_SIZE ; + diff = (next_slab_id + nb_slabs - slab_id) % nb_slabs; + +/* If next_slab_id == slab_id - overlap */ + diff += !(next_slab_id ^ slab_id) * nb_slabs; + +/* Size check - next slab is outsize of size range */ +if (diff > report_len) { + next_slab =0 ; + next_slab_id = stop_slab_id; + diff = report_len; + } + + report_len -= diff; + +/* Calculate gap between slabs, taking wrap around into account */ + zeros = (next_slab_id + nb_slabs - slab_id -1 ) % nb_slabs; +if (zeros) { +/* Non continues slabs, align them individually */ + slab >>= shift; +memcpy (data, &slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + +/* Fill zeros between slabs */ + zeros = (zeros -1 ) *SLAB_BYTE_SIZE ; +memset (data,0 , zeros); + data =RTE_PTR_ADD (data, zeros); + +/* Align beginning of next slab */ + leftover =leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &leftover,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + }else { +/* Continues slabs, combine them */ +uint64_t new_slab = (slab >> shift) | +leftover_get (next_slab, leftover_shift, leftover_mask); +memcpy (data, &new_slab,SLAB_BYTE_SIZE ); + data =RTE_PTR_ADD (data,SLAB_BYTE_SIZE ); + } + + slab = next_slab; + pos = next_pos; + slab_id = next_slab_id; + + }; + +assert (data < data_end); }
lib/pdcp/pdcp_cnt.h +10 -1
@@ -9,6 +9,15 @@#include "pdcp_entity.h" -int pdcp_cnt_ring_create (struct rte_pdcp_entity *en,const struct rte_pdcp_entity_conf *conf); +uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); + +void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count); +void pdcp_cnt_bitmap_range_clear (struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop); + +uint16_t pdcp_cnt_get_bitmap_size (uint32_t pending_bytes); +void pdcp_cnt_report_fill (struct pdcp_cnt_bitmap bitmap,struct entity_state state, +uint8_t *data,uint16_t data_len);#endif /* PDCP_CNT_H */
lib/pdcp/pdcp_ctrl_pdu.c +30 -4
@@ -8,6 +8,14 @@#include "pdcp_ctrl_pdu.h" #include "pdcp_entity.h" +#include "pdcp_cnt.h" + +static inline uint16_t +round_up_bits (uint32_t bits) +{ +/* round up to the next multiple of 8 */ +return RTE_ALIGN_MUL_CEIL (bits,8 ) /8 ; +} static __rte_always_inline voidpdcp_hdr_fill (struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr,uint32_t rx_deliv)
@@ -19,11 +27,13 @@ pdcp_hdr_fill(struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr, uint32_t rx_deliv) }int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m) +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m) {struct rte_pdcp_up_ctrl_pdu_hdr *pdu_hdr; -uint32_t rx_deliv; -int pdu_sz; +uint32_t rx_deliv, actual_sz; +uint16_t pdu_sz, bitmap_sz; +uint8_t *data;if (!en_priv->flags.is_status_report_required)return -EINVAL ;
@@ -42,5 +52,21 @@ pdcp_ctrl_pdu_status_gen(struct entity_priv *en_priv, struct rte_mbuf *m)return 0 ; } -return -ENOTSUP ; + actual_sz =RTE_MIN (round_up_bits (en_priv->state.rx_next - rx_deliv -1 ), +RTE_PDCP_CTRL_PDU_SIZE_MAX - pdu_sz); + bitmap_sz =pdcp_cnt_get_bitmap_size (actual_sz); + + data = (uint8_t *)rte_pktmbuf_append (m, pdu_sz + bitmap_sz); +if (data ==NULL ) +return -ENOMEM ; + + m->pkt_len = pdu_sz + actual_sz; + m->data_len = pdu_sz + actual_sz; + +pdcp_hdr_fill ((struct rte_pdcp_up_ctrl_pdu_hdr *)data, rx_deliv); + + data =RTE_PTR_ADD (data, pdu_sz); +pdcp_cnt_report_fill (dl->bitmap, en_priv->state, data, bitmap_sz); + +return 0 ; }
lib/pdcp/pdcp_ctrl_pdu.h +2 -1
@@ -10,6 +10,7 @@#include "pdcp_entity.h" int -pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct rte_mbuf *m); +pdcp_ctrl_pdu_status_gen (struct entity_priv *en_priv,struct entity_priv_dl_part *dl, +struct rte_mbuf *m);#endif /* PDCP_CTRL_PDU_H */
lib/pdcp/pdcp_entity.h +2 -0
@@ -182,6 +182,8 @@ struct entity_priv_dl_part {struct pdcp_t_reordering t_reorder;/** Reorder packet buffer */ struct pdcp_reorder reorder; +/** Bitmap memory region */ +uint8_t bitmap_mem[0 ]; };struct entity_priv_ul_part {
lib/pdcp/pdcp_process.c +7 -2
@@ -9,6 +9,7 @@#include <rte_pdcp.h> #include <rte_pdcp_hdr.h> +#include "pdcp_cnt.h" #include "pdcp_crypto.h" #include "pdcp_entity.h" #include "pdcp_process.h"
@@ -856,11 +857,15 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity,if (count >= en_priv->state.rx_next) en_priv->state.rx_next = count +1 ; +if (unlikely (pdcp_cnt_bitmap_is_set (dl->bitmap, count))) +return -EEXIST ; + +pdcp_cnt_bitmap_set (dl->bitmap, count);pdcp_packet_strip (mb, hdr_trim_sz, trim_mac);if (en_priv->flags.is_out_of_order_delivery) { out_mb[0 ] = mb; - en_priv->state.rx_deliv = count +1 ; +pdcp_rx_deliv_set (entity, count +1 );return 1 ; }
@@ -887,7 +892,7 @@ pdcp_post_process_update_entity_state(const struct rte_pdcp_entity *entity, }/* Processed should never exceed the window size */ - en_priv->state.rx_deliv = count + processed; +pdcp_rx_deliv_set (entity, count + processed); }else {if (!reorder->is_active)
lib/pdcp/pdcp_process.h +13 -0
@@ -7,6 +7,9 @@#include <rte_pdcp.h> +#include <pdcp_entity.h> +#include <pdcp_cnt.h> +typedef uint32_t rte_pdcp_dynfield_t ;extern int rte_pdcp_dynfield_offset;
@@ -20,4 +23,14 @@ pdcp_dynfield(struct rte_mbuf *mbuf)int pdcp_process_func_set (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf); +static inline void +pdcp_rx_deliv_set (const struct rte_pdcp_entity *entity,uint32_t rx_deliv) +{ +struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +struct entity_priv *en_priv =entity_priv_get (entity); + +pdcp_cnt_bitmap_range_clear (dl->bitmap, en_priv->state.rx_deliv, rx_deliv); + en_priv->state.rx_deliv = rx_deliv; +} +#endif /* PDCP_PROCESS_H */
lib/pdcp/rte_pdcp.c +25 -9
@@ -14,6 +14,8 @@#define RTE_PDCP_DYNFIELD_NAME "rte_pdcp_dynfield" +static int bitmap_mem_offset; +int rte_pdcp_dynfield_offset =-1 ; static int
@@ -39,9 +41,12 @@ pdcp_entity_size_get(const struct rte_pdcp_entity_conf *conf) size =sizeof (struct rte_pdcp_entity ) +sizeof (struct entity_priv ); -if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +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 =RTE_CACHE_LINE_ROUNDUP (size); + bitmap_mem_offset = size; + size +=pdcp_cnt_bitmap_get_memory_footprint (conf); + }else if (conf->pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_UPLINK ) size +=sizeof (struct entity_priv_ul_part );else return -EINVAL ;
@@ -54,11 +59,24 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_c {const uint32_t window_size =pdcp_window_size_get (conf->pdcp_xfrm.sn_size);struct entity_priv_dl_part *dl =entity_dl_part_get (entity); +void *bitmap_mem; +int ret; entity->max_pkt_cache =RTE_MAX (entity->max_pkt_cache, window_size); dl->t_reorder.handle = conf->t_reordering; -return pdcp_reorder_create (&dl->reorder, window_size); + ret =pdcp_reorder_create (&dl->reorder, window_size); +if (ret) +return ret; + + bitmap_mem =RTE_PTR_ADD (entity, bitmap_mem_offset); + ret =pdcp_cnt_bitmap_create (dl, bitmap_mem, window_size); +if (ret) { +pdcp_reorder_destroy (&dl->reorder); +return ret; + } + +return 0 ; } struct rte_pdcp_entity *
@@ -136,10 +154,6 @@ rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf) goto crypto_sess_destroy; } - ret =pdcp_cnt_ring_create (entity, conf); -if (ret) - goto crypto_sess_destroy; -return entity; crypto_sess_destroy:
@@ -218,6 +232,7 @@ struct rte_mbuf * rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, enum rte_pdcp_ctrl_pdu_type type) { +struct entity_priv_dl_part *dl;struct entity_priv *en_priv;struct rte_mbuf *m;int ret;
@@ -228,6 +243,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity, } en_priv =entity_priv_get (pdcp_entity); + dl =entity_dl_part_get (pdcp_entity); m =rte_pktmbuf_alloc (en_priv->ctrl_pdu_pool);if (m ==NULL ) {
@@ -237,7 +253,7 @@ rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,switch (type) {case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT : - ret =pdcp_ctrl_pdu_status_gen (en_priv, m); + ret =pdcp_ctrl_pdu_status_gen (en_priv, dl, m);break ;default : ret = -ENOTSUP ;
@@ -283,7 +299,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* - update RX_DELIV to the COUNT value of the first PDCP SDU which has not been delivered * to upper layers, with COUNT value >= RX_REORD; */ - en_priv->state.rx_deliv = en_priv->state.rx_reord + nb_seq; +pdcp_rx_deliv_set (entity, en_priv->state.rx_reord + nb_seq);/* * - if RX_DELIV < RX_NEXT:
Signature · 1 line
2.25.1
PATCH v4 20/22 pdcp: allocate reorder buffer alongside with entity
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Instead of allocating reorder buffer separately on heap, allocate memory for it together with rest of entity, and then only initialize buffer via rte_reorder_init().
--- lib/pdcp/pdcp_cnt.c | 9 +++---- lib/pdcp/pdcp_cnt.h | 3 ++- lib/pdcp/pdcp_entity.h | 2 +- lib/pdcp/pdcp_reorder.c | 11 ++------ lib/pdcp/pdcp_reorder.h | 12 ++++++--- lib/pdcp/rte_pdcp.c | 58 ++++++++++++++++++++++++++--------------- 6 files changed, 55 insertions(+), 40 deletions(-)
lib/pdcp/pdcp_cnt.c +4 -5
@@ -20,15 +20,14 @@ pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf *conf) }int -pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size) +pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size) { -uint32_t mem_size =rte_bitmap_get_memory_footprint (window_size); - - dl->bitmap.bmp =rte_bitmap_init (window_size, bitmap_mem, mem_size); + dl->bitmap.bmp =rte_bitmap_init (nb_elem, bitmap_mem, mem_size);if (dl->bitmap.bmp ==NULL )return -EINVAL ; - dl->bitmap.size = window_size; + dl->bitmap.size = nb_elem;return 0 ; }
lib/pdcp/pdcp_cnt.h +2 -1
@@ -10,7 +10,8 @@#include "pdcp_entity.h" uint32_t pdcp_cnt_bitmap_get_memory_footprint (const struct rte_pdcp_entity_conf *conf); -int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,void *bitmap_mem,uint32_t window_size); +int pdcp_cnt_bitmap_create (struct entity_priv_dl_part *dl,uint32_t nb_elem, +void *bitmap_mem,uint32_t mem_size);void pdcp_cnt_bitmap_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);bool pdcp_cnt_bitmap_is_set (struct pdcp_cnt_bitmap bitmap,uint32_t count);
lib/pdcp/pdcp_entity.h +1 -1
@@ -132,7 +132,7 @@ struct pdcp_cnt_bitmap { };/* -* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] +* Layout of PDCP entity: [rte_pdcp_entity] [entity_priv] [entity_dl/ul] [reorder/bitmap] */ struct entity_priv {
lib/pdcp/pdcp_reorder.c +2 -9
@@ -8,20 +8,13 @@#include "pdcp_reorder.h" int -pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size) +pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size) { - reorder->buf =rte_reorder_create ("reorder_buffer" ,SOCKET_ID_ANY , window_size); + reorder->buf =rte_reorder_init (mem, mem_size,"reorder_buffer" , nb_elem);if (reorder->buf ==NULL )return -rte_errno; - reorder->window_size = window_size; reorder->is_active = false;return 0 ; } - -void -pdcp_reorder_destroy (const struct pdcp_reorder *reorder) -{ -rte_reorder_free (reorder->buf); -}
lib/pdcp/pdcp_reorder.h +9 -3
@@ -9,12 +9,18 @@struct pdcp_reorder {struct rte_reorder_buffer *buf; -uint32_t window_size;bool is_active; }; -int pdcp_reorder_create (struct pdcp_reorder *reorder,uint32_t window_size); -void pdcp_reorder_destroy (const struct pdcp_reorder *reorder); +int pdcp_reorder_create (struct pdcp_reorder *reorder,size_t nb_elem,void *mem,size_t mem_size); + +/* NOTE: replace with `rte_reorder_memory_footprint_get` after DPDK 23.07 */ +#define SIZE_OF_REORDER_BUFFER (4 * RTE_CACHE_LINE_SIZE) +static inline size_t +pdcp_reorder_memory_footprint_get (size_t nb_elem) +{ +return SIZE_OF_REORDER_BUFFER + (2 * nb_elem *sizeof (struct rte_mbuf *)); +} static inline uint32_t pdcp_reorder_get_sequential(struct pdcp_reorder *reorder, struct rte_mbuf **mbufs,
lib/pdcp/rte_pdcp.c +37 -21
128 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v4 21/22 pdcp: add thread safe processing
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
PDCP state has to be guarded for:
- Uplink pre_process:
- tx_next atomic increment
- Downlink pre_process:
- rx_deliv - read
- Downlink post_process:
- rx_deliv, rx_reorder, rx_next - read/write
- bitmask/reorder buffer - read/write
When application requires thread safe processing, the state variables need to be updated atomically. Add config option to select this option per entity.
--- lib/pdcp/meson.build | 2 + lib/pdcp/pdcp_entity.h | 64 ++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 117 +++++++++++++++++++++++++++++++++------- lib/pdcp/rte_pdcp.c | 9 ++++ lib/pdcp/rte_pdcp.h | 2 + 5 files changed, 175 insertions(+), 19 deletions(-)
lib/pdcp/meson.build +2 -0
@@ -19,3 +19,5 @@ headers = files('rte_pdcp.h') indirect_headers += files('rte_pdcp_group.h') deps += ['mbuf', 'net', 'cryptodev', 'security', 'reorder'] + +annotate_locks = false
lib/pdcp/pdcp_entity.h +64 -0
86 lines not on this page · raw message
lib/pdcp/pdcp_process.c +98 -19
266 lines not on this page · raw message
lib/pdcp/rte_pdcp.c +9 -0
@@ -92,6 +92,8 @@ pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_cif (ret)return ret; +pdcp_lock_init (entity); +return 0 ; }
@@ -237,8 +239,11 @@ rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity, nb_out =pdcp_reorder_up_to_get (&dl->reorder, out_mb, pdcp_entity->max_pkt_cache, en_priv->state.rx_next);pdcp_reorder_stop (&dl->reorder); + +pdcp_write_lock (pdcp_entity); en_priv->state.rx_next =0 ; en_priv->state.rx_deliv =0 ; +pdcp_write_unlock (pdcp_entity); }return nb_out;
@@ -299,6 +304,8 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct* performing header decompression, if not decompressed before: */ +pdcp_write_lock (entity); +/* - all stored PDCP SDU(s) with associated COUNT value(s) < RX_REORD; */ nb_out =pdcp_reorder_up_to_get (&dl->reorder, out_mb, capacity, en_priv->state.rx_reord); capacity -= nb_out;
@@ -330,5 +337,7 @@ rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct dl->t_reorder.state =TIMER_EXPIRED ; } +pdcp_write_unlock (entity); +return nb_out; }
lib/pdcp/rte_pdcp.h +2 -0
@@ -141,6 +141,8 @@ struct rte_pdcp_entity_conf {bool is_slrb;/** Enable security offload on the device specified. */ bool en_sec_offload; +/** Enable usage of synchronization primitives for entity. */ +bool enable_thread_safety;/** Device on which security/crypto session need to be created. */ uint8_t dev_id;/**
Signature · 1 line
2.25.1
Re: [PATCH v4 21/22] pdcp: add thread safe processing
lib/pdcp/pdcp_entity.h pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size) · line 272
Quoted 8 lines · On Sat, 27 May 2023 02:32:13 +0530 Anoob Joseph <[email protected]> wrote:
lib/pdcp/pdcp_entity.h +8
-0+static inline uint32_t +pdcp_atomic_inc (uint32_t *val,const bool mt_safe) +{ +if (mt_safe) +return __atomic_fetch_add (val,1 , __ATOMIC_RELAXED); +else +return (*val)++; +}
This is a bad pattern. None of the rest of DPDK does this. Either be thread safe or not.
RE: [EXT] Re: [PATCH v4 21/22] pdcp: add thread safe processing
Hi Stephen,
Please see inline.
Thanks,
Anoob
Quoted 19 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Saturday, May 27, 2023 3:42 AM
To: Anoob Joseph <[email protected]>
Cc: Thomas Monjalon <[email protected]>; Akhil Goyal <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Volodymyr Fialko <[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: [EXT] Re: [PATCH v4 21/22] pdcp: add thread safe processingExternal Email
----------------------------------------------------------------------
On Sat, 27 May 2023 02:32:13 +0530
Anoob Joseph <[email protected]> wrote:
Quoted 10 lines
lib/pdcp/pdcp_entity.h pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size) · line 272
Quoted 7 lines
lib/pdcp/pdcp_entity.h +7
-0+static inline uint32_t +pdcp_atomic_inc (uint32_t *val,const bool mt_safe) { +if (mt_safe) +return __atomic_fetch_add (val,1 , __ATOMIC_RELAXED); +else +return (*val)++; +}This is a bad pattern. None of the rest of DPDK does this. Either be thread safe or not.
[Anoob] Most protocol implementation would have a similar issue. I've tried to follow the approach taken in lib IPsec (please check lib/ipsec/ipsec_sqn.h). From the discussion we had on v3, I've tried to make it compile time constant to remove any conditional checks in datapath.
If you still think, this is an issue, I could drop this patch for now and re-introduce it later once we have test applications that can work with traffic. Please share your thoughts.
RE: [EXT] Re: [PATCH v4 21/22] pdcp: add thread safe processing
Hi Stephen,
I've dropped this patch for now. Based on what we conclude on this thread, will post this as a separate patch as required.
Thanks,
Anoob
Quoted 59 lines
-----Original Message-----
From: Anoob Joseph <[email protected]>
Sent: Saturday, May 27, 2023 10:55 AM
To: Stephen Hemminger <[email protected]>
Cc: Thomas Monjalon <[email protected]>; Akhil Goyal <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; Volodymyr Fialko <[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: RE: [EXT] Re: [PATCH v4 21/22] pdcp: add thread safe processingHi Stephen,
Please see inline.
Thanks,
AnoobQuoted 7 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Saturday, May 27, 2023 3:42 AM
To: Anoob Joseph <[email protected]>
Cc: Thomas Monjalon <[email protected]>; Akhil Goyal <[email protected]>; Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; VolodymyrFialko
Quoted 12 lines
<[email protected]>; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; [email protected]; Olivier Matz <[email protected]>
Subject: [EXT] Re: [PATCH v4 21/22] pdcp: add thread safe processingExternal Email
----------------------------------------------------------------------
On Sat, 27 May 2023 02:32:13 +0530
Anoob Joseph <[email protected]> wrote:Quoted 10 lines
lib/pdcp/pdcp_entity.h pdcp_hfn_max(enum rte_security_pdcp_sn_size sn_size) · line 272
Quoted 7 lines
lib/pdcp/pdcp_entity.h +7
-0+static inline uint32_t +pdcp_atomic_inc (uint32_t *val,const bool mt_safe) { +if (mt_safe) +return __atomic_fetch_add (val,1 , __ATOMIC_RELAXED); +else +return (*val)++; +}This is a bad pattern. None of the rest of DPDK does this. Either be thread safe or not.
[Anoob] Most protocol implementation would have a similar issue. I've tried to follow the approach taken in lib IPsec (please check
lib/ipsec/ipsec_sqn.h). From the discussion we had on v3, I've tried to make it compile time constant to remove any conditional checks in datapath.If you still think, this is an issue, I could drop this patch for now and re- introduce it later once we have test applications that can work with traffic. Please share your thoughts.
Re: [PATCH v4 21/22] pdcp: add thread safe processing
In reply to Anoob Josephlib/pdcp/pdcp_entity.h struct entity_priv_dl_part {
Quoted 3 lines · On Sat, 27 May 2023 02:32:13 +0530 Anoob Joseph <[email protected]> wrote:
lib/pdcp/pdcp_entity.h +2
-0+/* Lock to protect concurrent updates */ +rte_rwlock_t rwl;/** Bitmap memory region
Reader/writer locks are significantly more expensive than simple spin lock. Even uncontended access requires additional cache update. Unless there is case with a long region where lock is held, just use a spin lock.
See some Paul McKenney's locking talks (LCA video is good) about lock overheads in Linux. Since DPDK has same set of instructions to use; the same issues apply to userspace.
PATCH v4 22/22 test/pdcp: add PDCP status report cases
In reply to Anoob JosephFrom: Volodymyr Fialko <[email protected]>
Test PDCP status report generation.
--- app/test/test_pdcp.c | 312 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+)
app/test/test_pdcp.c +312 -0
@@ -2,6 +2,7 @@* Copyright(C) 2023 Marvell. */ +#include <rte_bitmap.h> #include <rte_errno.h> #ifdef RTE_LIB_EVENTDEV #include <rte_eventdev.h>
@@ -48,6 +49,9 @@ struct pdcp_testsuite_params {#endif /* RTE_LIB_EVENTDEV */ bool timer_is_running;uint64_t min_resolution_ns; +struct rte_pdcp_up_ctrl_pdu_hdr *status_report; +uint32_t status_report_bitmask_capacity; +uint8_t *ctrl_pdu_buf; };static struct pdcp_testsuite_params testsuite_params;
@@ -168,6 +172,18 @@ static struct rte_pdcp_t_reordering t_reorder_timer = { .stop = pdcp_timer_stop_cb, }; +static inline void +bitmask_set_bit (uint8_t *mask,uint32_t bit) +{ + mask[bit /8 ] |= (1 << bit %8 ); +} + +static inline bool +bitmask_is_bit_set (const uint8_t *mask,uint32_t bit) +{ +return mask[bit /8 ] & (1 << (bit %8 )); +} +static inline int pdcp_hdr_size_get (enum rte_security_pdcp_sn_size sn_size) {
@@ -314,6 +330,21 @@ testsuite_setup(void) goto cop_pool_free; } +/* Allocate memory for longest possible status report */ + ts_params->status_report_bitmask_capacity =RTE_PDCP_CTRL_PDU_SIZE_MAX - +sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ); + ts_params->status_report =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->status_report ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report\n" ); + goto cop_pool_free; + } + + ts_params->ctrl_pdu_buf =rte_zmalloc (NULL ,RTE_PDCP_CTRL_PDU_SIZE_MAX ,0 ); +if (ts_params->ctrl_pdu_buf ==NULL ) { +RTE_LOG (ERR ,USER1 ,"Could not allocate status report data\n" ); + goto cop_pool_free; + } +return 0 ; cop_pool_free:
@@ -322,6 +353,8 @@ testsuite_setup(void) mbuf_pool_free:rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf);return TEST_FAILED ; }
@@ -344,6 +377,9 @@ testsuite_teardown(void)rte_mempool_free (ts_params->mbuf_pool); ts_params->mbuf_pool =NULL ; + +rte_free (ts_params->status_report); +rte_free (ts_params->ctrl_pdu_buf); } static int
@@ -1410,6 +1446,246 @@ test_expiry_with_rte_timer(const struct pdcp_test_conf *ul_conf)return ret; } +static struct rte_pdcp_up_ctrl_pdu_hdr * +pdcp_status_report_init (uint32_t fmc) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; + + hdr->d_c =RTE_PDCP_PDU_TYPE_CTRL ; + hdr->pdu_type =RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ; + hdr->fmc =rte_cpu_to_be_32 (fmc); + hdr->r =0 ; +memset (hdr->bitmap,0 , testsuite_params.status_report_bitmask_capacity); + +return hdr; +} + +static uint32_t +pdcp_status_report_len (void ) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr = testsuite_params.status_report; +uint32_t i; + +for (i = testsuite_params.status_report_bitmask_capacity; i !=0 ; i--) { +if (hdr->bitmap[i -1 ]) +return i; + } + +return 0 ; +} + +static int +pdcp_status_report_verify (struct rte_mbuf *status_report, +const struct rte_pdcp_up_ctrl_pdu_hdr *expected_hdr,uint32_t expected_len) +{ +uint32_t received_len =rte_pktmbuf_pkt_len (status_report); +uint8_t *received_buf = testsuite_params.ctrl_pdu_buf; +int ret; + + ret =pktmbuf_read_into (status_report, received_buf,RTE_PDCP_CTRL_PDU_SIZE_MAX ); +TEST_ASSERT_SUCCESS (ret,"Failed to copy status report pkt into continuous buffer" ); + +debug_hexdump (stdout,"Received:" , received_buf, received_len); +debug_hexdump (stdout,"Expected:" , expected_hdr, expected_len); + +TEST_ASSERT_EQUAL (expected_len, received_len, +"Mismatch in packet lengths [expected: %d, received: %d]" , + expected_len, received_len); + +TEST_ASSERT_BUFFERS_ARE_EQUAL (received_buf, expected_hdr, expected_len, +"Generated packet not as expected" ); + +return 0 ; +} + +static int +test_status_report_gen (const struct pdcp_test_conf *ul_conf, +const struct rte_pdcp_up_ctrl_pdu_hdr *hdr, +uint32_t bitmap_len) +{ +const enum rte_security_pdcp_sn_size sn_size = ul_conf->entity.pdcp_xfrm.sn_size; +struct rte_mbuf *status_report =NULL , **out_mb, *m; +uint16_t nb_success =0 , nb_err =0 ; +struct rte_pdcp_entity *pdcp_entity; +struct pdcp_test_conf dl_conf; +int ret =TEST_FAILED , nb_out; +uint32_t nb_pkts =0 , i; +uint8_t cdev_id; + +const uint32_t start_count =rte_be_to_cpu_32 (hdr->fmc); + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK ) +return TEST_SKIPPED ; + +/* Create configuration for actual testing */ +uplink_to_downlink_convert (ul_conf, &dl_conf); + dl_conf.entity.pdcp_xfrm.hfn =pdcp_hfn_from_count_get (start_count, sn_size); + dl_conf.entity.sn =pdcp_sn_from_count_get (start_count, sn_size); + dl_conf.entity.status_report_required = true; + + pdcp_entity =test_entity_create (&dl_conf, &ret); +if (pdcp_entity ==NULL ) +return ret; + + cdev_id = dl_conf.entity.dev_id; + out_mb =calloc (pdcp_entity->max_pkt_cache,sizeof (uintptr_t )); + +for (i =0 ; i < bitmap_len *8 ; i++) { +if (!bitmask_is_bit_set (hdr->bitmap, i)) +continue ; + + m =generate_packet_for_dl_with_sn (*ul_conf, start_count + i +1 ); +ASSERT_TRUE_OR_GOTO (m !=NULL , exit,"Could not allocate buffer for packet\n" ); + + nb_success =test_process_packets (pdcp_entity, cdev_id, &m,1 , out_mb, &nb_err); +ASSERT_TRUE_OR_GOTO (nb_err ==0 , exit,"Error occurred during packet buffering\n" ); +ASSERT_TRUE_OR_GOTO (nb_success ==0 , exit,"Packet was not buffered as expected\n" ); + + } + + m =NULL ; + +/* Check status report */ + status_report =rte_pdcp_control_pdu_create (pdcp_entity, +RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT ); +ASSERT_TRUE_OR_GOTO (status_report !=NULL , exit,"Could not generate status report\n" ); + +const uint32_t expected_len =sizeof (struct rte_pdcp_up_ctrl_pdu_hdr ) + bitmap_len; + +ASSERT_TRUE_OR_GOTO (pdcp_status_report_verify (status_report, hdr, expected_len) ==0 , exit, +"Report verification failure\n" ); + + ret =TEST_SUCCESS ; +exit: +rte_free (m); +rte_pktmbuf_free (status_report); +rte_pktmbuf_free_bulk (out_mb, nb_pkts); + nb_out =rte_pdcp_entity_release (pdcp_entity, out_mb); +rte_pktmbuf_free_bulk (out_mb, nb_out); +free (out_mb); +return ret; +} + +static void +ctrl_pdu_hdr_packet_set (struct rte_pdcp_up_ctrl_pdu_hdr *hdr,uint32_t pkt_count) +{ +bitmask_set_bit (hdr->bitmap, pkt_count -rte_be_to_cpu_32 (hdr->fmc) -1 ); +} + +static int +test_status_report_fmc_only (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (42 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_first_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_one_pkt_second_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); + +ctrl_pdu_hdr_packet_set (hdr,RTE_BITMAP_SLAB_BIT_SIZE +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_full_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (1 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE +1 ; +int i; + +for (i =0 ; i <RTE_BITMAP_SLAB_BIT_SIZE ; i++) +ctrl_pdu_hdr_packet_set (hdr, start_offset + i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_two_non_sequential_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (0 ); +const uint32_t start_offset =RTE_BITMAP_SLAB_BIT_SIZE /2 +1 ; + +ctrl_pdu_hdr_packet_set (hdr, start_offset); +ctrl_pdu_hdr_packet_set (hdr, start_offset +RTE_BITMAP_SLAB_BIT_SIZE ); +ctrl_pdu_hdr_packet_set (hdr,3 *RTE_BITMAP_SLAB_BIT_SIZE ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_max_length_sn_12 (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr; +const uint32_t fmc =0 ; +uint32_t i; + +if (ul_conf->entity.pdcp_xfrm.pkt_dir ==RTE_SECURITY_PDCP_DOWNLINK || + ul_conf->entity.pdcp_xfrm.sn_size !=RTE_SECURITY_PDCP_SN_SIZE_12 ) +return TEST_SKIPPED ; + + hdr =pdcp_status_report_init (fmc); + +const uint32_t max_count =RTE_MIN ((RTE_PDCP_CTRL_PDU_SIZE_MAX -sizeof (hdr)) *8 , + (uint32_t )PDCP_WINDOW_SIZE (RTE_SECURITY_PDCP_SN_SIZE_12 )); + + i = fmc +2 ;/* set first count to have a gap, to enable packet buffering */ + +for (; i < max_count; i++) +ctrl_pdu_hdr_packet_set (hdr, i); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_different_slabs (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (63 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,64 +1 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} + +static int +test_status_report_overlap_same_slab (const struct pdcp_test_conf *ul_conf) +{ +struct rte_pdcp_up_ctrl_pdu_hdr *hdr =pdcp_status_report_init (2 ); +const uint32_t sn_size =12 ; + +ctrl_pdu_hdr_packet_set (hdr,4 ); +ctrl_pdu_hdr_packet_set (hdr,PDCP_WINDOW_SIZE (sn_size) +1 ); + +return test_status_report_gen (ul_conf, hdr,pdcp_status_report_len ()); +} +static int test_combined (struct pdcp_test_conf *ul_conf) {
@@ -1611,11 +1887,47 @@ static struct unit_test_suite reorder_test_cases = { } }; +static struct unit_test_suite status_report_test_cases = { + .suite_name ="PDCP status report" , + .unit_test_cases = { +TEST_CASE_NAMED_WITH_DATA ("test_status_report_fmc_only" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_fmc_only), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_first_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_first_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_one_pkt_second_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_one_pkt_second_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_full_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_full_slab), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_two_non_sequential_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_two_non_sequential_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_max_length_sn_12" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec_until_first_pass, + test_status_report_max_length_sn_12), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_different_slabs" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_different_slabs), +TEST_CASE_NAMED_WITH_DATA ("test_status_report_overlap_same_slab" , + ut_setup_pdcp, ut_teardown_pdcp, + run_test_with_all_known_vec, test_status_report_overlap_same_slab), +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, &reorder_test_cases, + &status_report_test_cases,NULL /* End of suites list */ };
Signature · 1 line
2.25.1
v5 cover lib: add pdcp protocol
In reply to Anoob JosephAdd 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 v5:
- Deferred patch adding thread safe processing.
- Updated release notes & MAINTAINERS file.
Changes in v4:
- Disabled 'annotate locks' with lib PDCP
- Enable PDCP autotest only when lib is enabled
- Use rwlock instead of spinlock
- Avoid per packet checks for thread safety (Stephen)
- In DL path, save count determined during pre-process in mbuf and use the same in post-process. Determining count again may lead To errors
- Simplified DL path threads to allow more common code between SN 12 & 18
Changes in v3:
- Addressed review comments (Akhil)
- Addressed build failure in CI (tests with lib eventdev disabled)
- Addressed checkpatch issues
- Set only positive values to rte_errno (Akhil)
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 : 112/160 passed, 0/160 skipped, 0/160 failed, 48/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: 48 + Tests Passed : 131
+ 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 for status report
Volodymyr Fialko (11):
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 test/pdcp: add PDCP status report cases
MAINTAINERS | 8 + app/test/meson.build | 5 + app/test/test_pdcp.c | 1981 +++++++++++++++++ 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 | 293 +++ doc/guides/rel_notes/release_23_07.rst | 12 + lib/meson.build | 1 + lib/net/meson.build | 1 + lib/net/rte_pdcp_hdr.h | 147 ++ lib/pdcp/meson.build | 21 + lib/pdcp/pdcp_cnt.c | 164 ++ lib/pdcp/pdcp_cnt.h | 24 + lib/pdcp/pdcp_crypto.c | 238 ++ lib/pdcp/pdcp_crypto.h | 20 + lib/pdcp/pdcp_ctrl_pdu.c | 72 + lib/pdcp/pdcp_ctrl_pdu.h | 16 + lib/pdcp/pdcp_entity.h | 260 +++ lib/pdcp/pdcp_process.c | 1223 ++++++++++ lib/pdcp/pdcp_process.h | 37 + lib/pdcp/pdcp_reorder.c | 20 + lib/pdcp/pdcp_reorder.h | 68 + lib/pdcp/rte_pdcp.c | 334 +++ lib/pdcp/rte_pdcp.h | 383 ++++ lib/pdcp/rte_pdcp_group.h | 131 ++ lib/pdcp/version.map | 20 + 28 files changed, 5485 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
PATCH v5 1/21 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 | 147 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 lib/net/rte_pdcp_hdr.h
doc/api/doxy-api-index.md +2 -1
@@ -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
@@ -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 +147 -0
147 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v5 2/21 lib: add pdcp protocol
In reply to Anoob JosephAdd 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()
--- MAINTAINERS | 6 ++ 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 | 113 ++++++++++++++++++++++++++ lib/pdcp/pdcp_process.c | 138 +++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 13 +++ lib/pdcp/rte_pdcp.c | 141 ++++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 167 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 10 +++ 13 files changed, 645 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
MAINTAINERS +6 -0
@@ -1549,6 +1549,12 @@ F: doc/guides/tools/pdump.rst F: app/dumpcap/ F: doc/guides/tools/dumpcap.rst +PDCP - EXPERIMENTAL +M: Anoob Joseph <[email protected]> +M: Volodymyr Fialko <[email protected]> +T: git://dpdk.org/next/dpdk-next-crypto +F: lib/pdcp/ + Packet Framework ----------------
doc/api/doxy-api-index.md +2 -1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 +113 -0
113 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
@@ -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 +141 -0
141 lines not on this page · raw message
lib/pdcp/rte_pdcp.h new file +167 -0
167 lines not on this page · raw message
lib/pdcp/version.map new file +10 -0
@@ -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
PATCH v5 3/21 pdcp: add pre and post-process
In reply to Anoob JosephPDCP 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
@@ -22,6 +22,21 @@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. *
@@ -33,6 +48,10 @@ extern "C" {* plane depending on which radio bearer it is carrying data for. */ 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
@@ -160,6 +179,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
@@ -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
PATCH v5 4/21 pdcp: add packet group
In reply to Anoob JosephCrypto 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 | 6 ++ lib/pdcp/rte_pdcp_group.h | 131 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 3 + 4 files changed, 141 insertions(+) create mode 100644 lib/pdcp/rte_pdcp_group.h
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']
lib/pdcp/rte_pdcp.h +6 -0
@@ -257,6 +257,12 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity,return entity->post_process (entity, in_mb, out_mb, num, nb_err); } +/** +* The header 'rte_pdcp_group.h' depends on defines in 'rte_pdcp.h'. So include +* in the end. +*/ +#include <rte_pdcp_group.h> + #ifdef __cplusplus }#endif
lib/pdcp/rte_pdcp_group.h new file +131 -0
131 lines not on this page · raw message
lib/pdcp/version.map +3 -0
@@ -2,12 +2,15 @@ EXPERIMENTAL { global: # added in 23.07 + rte_pdcp_en_from_cop; + rte_pdcp_entity_establish; rte_pdcp_entity_release; rte_pdcp_entity_suspend; rte_pdcp_pkt_post_process; rte_pdcp_pkt_pre_process; + rte_pdcp_pkt_crypto_group; local: *; };
Signature · 1 line
2.25.1
PATCH v5 5/21 pdcp: add crypto session create and destroy
In reply to Anoob JosephAdd 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 | 223 ++++++++++++++++++++++++++++++++++++++++- lib/pdcp/pdcp_crypto.h | 5 + 2 files changed, 225 insertions(+), 3 deletions(-)
lib/pdcp/pdcp_crypto.c +220 -3
@@ -2,20 +2,237 @@* 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 <rte_pdcp_hdr.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 cipher_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 ) + cipher_iv_len =0 ; +else + cipher_iv_len =PDCP_IV_LEN ; + +if (cipher_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 =RTE_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 ) { +/* rte_errno is set as positive values of 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 +5 -0
@@ -5,8 +5,13 @@#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 +int pdcp_crypto_sess_create (struct rte_pdcp_entity *entity,const struct rte_pdcp_entity_conf *conf);
Signature · 1 line
2.25.1
PATCH v5 6/21 pdcp: add pre and post process for UL
In reply to Anoob JosephAdd 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 | 24 +++ lib/pdcp/pdcp_process.c | 334 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+)
lib/pdcp/pdcp_entity.h +24 -0
@@ -92,22 +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 +334 -0
345 lines not on this page · raw message
Signature · 1 line
2.25.1