lib: add pdcp protocol
Subsystems (2)
PATCH v5 7/21 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 | 384 ++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 11 ++ lib/pdcp/rte_pdcp.c | 23 +++ 4 files changed, 420 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 +384 -0
411 lines not on this page · raw message
lib/pdcp/pdcp_process.h +11 -0
@@ -5,8 +5,19 @@#ifndef PDCP_PROCESS_H #define PDCP_PROCESS_H +#include <rte_mbuf_dyn.h> #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 v5 8/21 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 v5 9/21 app/test: add lib pdcp tests
In reply to Anoob JosephAdd tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.
--- MAINTAINERS | 1 + app/test/meson.build | 5 + app/test/test_pdcp.c | 732 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 738 insertions(+) create mode 100644 app/test/test_pdcp.c
MAINTAINERS +1 -0
@@ -1554,6 +1554,7 @@ M: Anoob Joseph <[email protected]> M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ +F: app/test/test_pdcp* Packet Framework
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_pdcp.c new file +732 -0
732 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v5 10/21 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 v5 11/21 doc: add PDCP library guide
In reply to Anoob JosephAdd guide for PDCP library.
--- MAINTAINERS | 1 + .../img/pdcp_functional_overview.svg | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/pdcp_lib.rst | 254 ++++++++++++++++++ doc/guides/rel_notes/release_23_07.rst | 12 + 5 files changed, 269 insertions(+) create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
MAINTAINERS +1 -0
@@ -1555,6 +1555,7 @@ M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ F: app/test/test_pdcp* +F: doc/guides/prog_guide/pdcp_lib.rst Packet Framework
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
doc/guides/rel_notes/release_23_07.rst +12 -0
@@ -65,6 +65,18 @@ New Features * Added support for SM3 hash operations. * Added support for AES-CCM in cn9k and cn10k drivers. +* **Added PDCP Library.** + + Added an experimental library ``lib_pdcp`` to provide PDCP UL and DL + processing of packets. + + The library supports all PDCP algorithms and leverages lookaside crypto + offloads to cryptodevs for crypto processing. PDCP features such as IV + generation, sequence number handling etc are supported. It is planned to add + more features such as packet caching in future releases. + + See :doc:`../prog_guide/pdcp_lib` for more information. + Removed Items -------------
Signature · 1 line
2.25.1
PATCH v5 12/21 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
@@ -1092,6 +1092,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 v5 13/21 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 v5 14/21 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 v5 15/21 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
@@ -902,6 +902,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);
@@ -916,6 +917,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 v5 16/21 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 v5 17/21 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 v5 18/21 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 v5 19/21 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
@@ -10,6 +10,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"
@@ -857,11 +858,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 ; }
@@ -888,7 +893,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
@@ -8,6 +8,9 @@#include <rte_mbuf_dyn.h> #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;
@@ -21,4 +24,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 v5 20/21 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 v5 21/21 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
v6 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 v6:
- Rebased
- Minor udpates to documentation (Akhil)
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 | 294 +++ 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 | 380 ++++ lib/pdcp/rte_pdcp_group.h | 131 ++ lib/pdcp/version.map | 20 + 28 files changed, 5483 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 v6 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 v6 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 | 166 ++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 10 +++ 13 files changed, 644 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
@@ -1551,6 +1551,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 +166 -0
166 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 v6 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 | 96 ++++++++++++++++++++++++++++++++++++++++++++ lib/pdcp/version.map | 3 ++ 2 files changed, 99 insertions(+)
lib/pdcp/rte_pdcp.h +96 -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. *
@@ -34,6 +49,10 @@ extern "C" {* 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
@@ -159,6 +178,83 @@ 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 rte_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 v6 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
@@ -255,6 +255,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 v6 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 v6 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
Re: [PATCH v6 06/21] pdcp: add pre and post process for UL
Hello,
I'm sorry to inform you that I see a compilation failure when cross-compiling for PPC64:err_mb is seen as potentially unitialized when calling rte_memcpy().
30/05/2023 12:01, Anoob Joseph:
lib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_ · line 315
Quoted 10 lines
lib/pdcp/pdcp_process.c +10
-0+static uint16_t +pdcp_post_process_ul (const struct rte_pdcp_entity *entity, +struct rte_mbuf *in_mb[],struct rte_mbuf *out_mb[], +uint16_t num,uint16_t *nb_err_ret) +{ +struct entity_priv *en_priv =entity_priv_get (entity); +const uint32_t hdr_trim_sz = en_priv->aad_sz; +int i, nb_success =0 , nb_err =0 ; +struct rte_mbuf *mb, *err_mb[num]; +
I need to add a workaround here to make GCC happy:
#ifdef RTE_ARCH_PPC_64
err_mb[0] = NULL; /* workaround PPC-GCC bug */
#endif
Quoted 9 lines
lib/pdcp/pdcp_process.c +9
-0+for (i =0 ; i < num; i++) { + mb = in_mb[i]; +if (unlikely (mb->ol_flags &RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED )) { + err_mb[nb_err++] = mb; +continue ; + } + +if (hdr_trim_sz) +rte_pktmbuf_adj (mb, hdr_trim_sz);
lib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_ · line 334
Quoted 10 lines
lib/pdcp/pdcp_process.c +10
-0+ + out_mb[nb_success++] = mb; + } + +if (unlikely (nb_err !=0 )) +rte_memcpy (&out_mb[nb_success], err_mb, nb_err *sizeof (struct rte_mbuf *)); + + *nb_err_ret = nb_err; +return nb_success; +}
I've added the workaround in 3 places while pulling next-crypto tree. Feel free to improve it with a new patch, thanks.
RE: [EXT] Re: [PATCH v6 06/21] pdcp: add pre and post process for UL
Hi Thomas,
Thanks for the fix. Will check if we can have it addressed properly.
Thanks,
Anoob
Quoted 65 lines
-----Original Message-----
From: Thomas Monjalon <[email protected]>
Sent: Sunday, June 11, 2023 4:21 AM
To: Akhil Goyal <[email protected]>; Kiran Kumar Kokkilagadda <[email protected]>; Volodymyr Fialko <[email protected]>; Anoob Joseph <[email protected]>
Cc: Jerin Jacob Kollanukkaran <[email protected]>; Konstantin Ananyev <[email protected]>; [email protected]; Hemant Agrawal <[email protected]>; Mattias Rönnblom <[email protected]>; [email protected]; Olivier Matz <[email protected]>; Stephen Hemminger <[email protected]>; [email protected]
Subject: [EXT] Re: [PATCH v6 06/21] pdcp: add pre and post process for ULExternal Email
----------------------------------------------------------------------
Hello,I'm sorry to inform you that I see a compilation failure when cross-compiling for PPC64:
err_mbis seen as potentially unitialized when callingrte_memcpy().30/05/2023 12:01, Anoob Joseph:
lib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_ · line 315
Quoted 9 lines
lib/pdcp/pdcp_process.c +9
-0+static uint16_t +pdcp_post_process_ul (const struct rte_pdcp_entity *entity, +struct rte_mbuf *in_mb[],struct rte_mbuf *out_mb[], +uint16_t num,uint16_t *nb_err_ret) { +struct entity_priv *en_priv =entity_priv_get (entity); +const uint32_t hdr_trim_sz = en_priv->aad_sz; +int i, nb_success =0 , nb_err =0 ; +struct rte_mbuf *mb, *err_mb[num]; +I need to add a workaround here to make GCC happy:
#ifdefRTE_ARCH_PPC_64
err_mb[0] = NULL; /* workaround PPC-GCC bug */ #endiflib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_
Quoted 3 lines
lib/pdcp/pdcp_process.c +3
-0+for (i =0 ; i < num; i++) { + mb = in_mb[i]; + if (unlikely(mb->ol_flags &
RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {lib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_
Quoted 12 lines
lib/pdcp/pdcp_process.c +12
-0+ err_mb[nb_err++] = mb; +continue ; + } + +if (hdr_trim_sz) +rte_pktmbuf_adj (mb, hdr_trim_sz); + + out_mb[nb_success++] = mb; + } + +if (unlikely (nb_err !=0 )) + rte_memcpy(&out_mb[nb_success], err_mb, nb_err *sizeof(struct
lib/pdcp/pdcp_process.c pdcp_crypto_xfrm_get(const struct rte_pdcp_entity_conf *conf, struct rte_crypto_ · line 334
Quoted 5 lines
lib/pdcp/pdcp_process.c +5
-0+rte_mbuf *)); + + *nb_err_ret = nb_err; +return nb_success; +}I've added the workaround in 3 places while pulling next-crypto tree. Feel free to improve it with a new patch, thanks.
PATCH v6 7/21 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 | 384 ++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 11 ++ lib/pdcp/rte_pdcp.c | 23 +++ 4 files changed, 420 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 +384 -0
411 lines not on this page · raw message
lib/pdcp/pdcp_process.h +11 -0
@@ -5,8 +5,19 @@#ifndef PDCP_PROCESS_H #define PDCP_PROCESS_H +#include <rte_mbuf_dyn.h> #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 v6 8/21 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 v6 9/21 app/test: add lib pdcp tests
In reply to Anoob JosephAdd tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.
--- MAINTAINERS | 1 + app/test/meson.build | 5 + app/test/test_pdcp.c | 732 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 738 insertions(+) create mode 100644 app/test/test_pdcp.c
MAINTAINERS +1 -0
@@ -1556,6 +1556,7 @@ M: Anoob Joseph <[email protected]> M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ +F: app/test/test_pdcp* Packet Framework
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_pdcp.c new file +732 -0
732 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v6 10/21 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 v6 11/21 doc: add PDCP library guide
In reply to Anoob JosephAdd guide for PDCP library.
--- MAINTAINERS | 1 + .../img/pdcp_functional_overview.svg | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/pdcp_lib.rst | 254 ++++++++++++++++++ doc/guides/rel_notes/release_23_07.rst | 12 + 5 files changed, 269 insertions(+) create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
MAINTAINERS +1 -0
@@ -1557,6 +1557,7 @@ M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ F: app/test/test_pdcp* +F: doc/guides/prog_guide/pdcp_lib.rst Packet Framework
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
doc/guides/rel_notes/release_23_07.rst +12 -0
@@ -65,6 +65,18 @@ New Features * Added support for SM3 hash operations. * Added support for AES-CCM in cn9k and cn10k drivers. +* **Added PDCP Library.** + + Added an experimental library ``lib_pdcp`` to provide PDCP UL and DL + processing of packets. + + The library supports all PDCP algorithms and leverages lookaside crypto + offloads to cryptodevs for crypto processing. PDCP features such as IV + generation, sequence number handling etc are supported. It is planned to add + more features such as packet caching in future releases. + + See :doc:`../prog_guide/pdcp_lib` for more information. + Removed Items -------------
Signature · 1 line
2.25.1
PATCH v6 12/21 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 as +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
@@ -1092,6 +1092,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
@@ -80,6 +81,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;/** * Sequence number value to be used. * 32 bit count value to be used for the first packet
@@ -97,6 +100,16 @@ struct rte_pdcp_entity_conf {* Can be used to simulate UE crypto processing. */ bool reverse_iv_direction; +/** +* Status report required (specified in TS 38.331). +* +* If PDCP entity is configured to send a PDCP status report, +* the upper layer application may request a receiving PDCP entity +* to generate a PDCP status report using ``rte_pdcp_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. */
@@ -178,6 +191,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 v6 13/21 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
@@ -110,6 +110,8 @@ struct rte_pdcp_entity_conf {* 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. */
@@ -269,8 +271,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 v6 14/21 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 v6 15/21 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
@@ -902,6 +902,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);
@@ -916,6 +917,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 v6 16/21 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 | 31 +++++++++++++++++++ lib/pdcp/rte_pdcp.c | 49 ++++++++++++++++++++++++++++++ lib/pdcp/rte_pdcp.h | 34 +++++++++++++++++++-- lib/pdcp/version.map | 2 ++ 4 files changed, 114 insertions(+), 2 deletions(-)
doc/guides/prog_guide/pdcp_lib.rst +31 -0
@@ -130,6 +130,37 @@ Supported integrity protection algorithms - RTE_CRYPTO_AUTH_SNOW3G_UIA2 - RTE_CRYPTO_AUTH_ZUC_EIA3 +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 will 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 +32 -2
@@ -102,6 +102,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, to be used in callback functions. */ void *timer;
@@ -112,6 +113,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.
@@ -338,8 +340,36 @@ rte_pdcp_pkt_post_process(const struct rte_pdcp_entity *entity, }/** -* The header 'rte_pdcp_group.h' depends on defines in 'rte_pdcp.h'. So include -* in the end. +* @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. */ #include <rte_pdcp_group.h>
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 v6 17/21 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 v6 18/21 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 v6 19/21 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
@@ -10,6 +10,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"
@@ -857,11 +858,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 ; }
@@ -888,7 +893,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
@@ -8,6 +8,9 @@#include <rte_mbuf_dyn.h> #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;
@@ -21,4 +24,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 v6 20/21 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 v6 21/21 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
Akhil Goyal
AppliedQuoted 55 lines
Subject: [PATCH v6 00/21] lib: add pdcp protocol
Add Packet Data Convergence Protocol (PDCP) processing library.
The library is similar to
lib_ipsecwhich 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 protectionPDCP 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_securitylibrary. 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_opallocation 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 bothrte_timerbased timers as well asrte_eventdevbased 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.
Quoted 3 lines
Changes in v6:
- Rebased
- Minor udpates to documentation (Akhil)
Series Acked-by: Akhil Goyal <[email protected]>
Applied to dpdk-next-crypto
Thanks.
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
RE: [PATCH v5 01/21] net: add PDCP header
Quoted 4 lines
Subject: [PATCH v5 01/21] net: add PDCP header
From: Volodymyr Fialko <[email protected]>
Quoted 8 lines
Add PDCP protocol header to be used for supporting PDCP protocol processing.
Signed-off-by Anoob Joseph <[email protected]>Signed-off-by Kiran Kumar K <[email protected]>Signed-off-by Volodymyr Fialko <[email protected]>Acked-by Akhil Goyal <[email protected]>---
Olivier,
Could you please review and give ack on this patch.
Thomas,
Can this patch be applied to next-crypto?
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
PATCH v5 7/21 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 | 384 ++++++++++++++++++++++++++++++++++++++++ lib/pdcp/pdcp_process.h | 11 ++ lib/pdcp/rte_pdcp.c | 23 +++ 4 files changed, 420 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 +384 -0
411 lines not on this page · raw message
lib/pdcp/pdcp_process.h +11 -0
@@ -5,8 +5,19 @@#ifndef PDCP_PROCESS_H #define PDCP_PROCESS_H +#include <rte_mbuf_dyn.h> #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 v5 8/21 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 v5 9/21 app/test: add lib pdcp tests
In reply to Anoob JosephAdd tests to verify lib PDCP operations. Tests leverage existing PDCP test vectors.
--- MAINTAINERS | 1 + app/test/meson.build | 5 + app/test/test_pdcp.c | 732 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 738 insertions(+) create mode 100644 app/test/test_pdcp.c
MAINTAINERS +1 -0
@@ -1554,6 +1554,7 @@ M: Anoob Joseph <[email protected]> M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ +F: app/test/test_pdcp* Packet Framework
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_pdcp.c new file +732 -0
732 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v5 10/21 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 v5 11/21 doc: add PDCP library guide
In reply to Anoob JosephAdd guide for PDCP library.
--- MAINTAINERS | 1 + .../img/pdcp_functional_overview.svg | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/pdcp_lib.rst | 254 ++++++++++++++++++ doc/guides/rel_notes/release_23_07.rst | 12 + 5 files changed, 269 insertions(+) create mode 100644 doc/guides/prog_guide/img/pdcp_functional_overview.svg create mode 100644 doc/guides/prog_guide/pdcp_lib.rst
MAINTAINERS +1 -0
@@ -1555,6 +1555,7 @@ M: Volodymyr Fialko <[email protected]> T: git://dpdk.org/next/dpdk-next-crypto F: lib/pdcp/ F: app/test/test_pdcp* +F: doc/guides/prog_guide/pdcp_lib.rst Packet Framework
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
doc/guides/rel_notes/release_23_07.rst +12 -0
@@ -65,6 +65,18 @@ New Features * Added support for SM3 hash operations. * Added support for AES-CCM in cn9k and cn10k drivers. +* **Added PDCP Library.** + + Added an experimental library ``lib_pdcp`` to provide PDCP UL and DL + processing of packets. + + The library supports all PDCP algorithms and leverages lookaside crypto + offloads to cryptodevs for crypto processing. PDCP features such as IV + generation, sequence number handling etc are supported. It is planned to add + more features such as packet caching in future releases. + + See :doc:`../prog_guide/pdcp_lib` for more information. + Removed Items -------------
Signature · 1 line
2.25.1
PATCH v5 12/21 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
@@ -1092,6 +1092,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 v5 13/21 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 v5 14/21 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 v5 15/21 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
@@ -902,6 +902,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);
@@ -916,6 +917,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 v5 16/21 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 v5 17/21 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 v5 18/21 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 v5 19/21 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
@@ -10,6 +10,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"
@@ -857,11 +858,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 ; }
@@ -888,7 +893,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
@@ -8,6 +8,9 @@#include <rte_mbuf_dyn.h> #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;
@@ -21,4 +24,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 v5 20/21 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 v5 21/21 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