From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 18079A034E; Thu, 20 Jan 2022 17:48:32 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 707794271D; Thu, 20 Jan 2022 17:48:29 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 9D4824271D for ; Thu, 20 Jan 2022 17:48:27 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 20KAA7S4026184; Thu, 20 Jan 2022 08:48:25 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0220; bh=C8MRr/8YvlbKejAheeO5/O/Yo4ngWwVIR9kGHjvZuhs=; b=Uh+vNedGjFI3YFl5l0slkKUij9Kd32QHuB2z5cAxt/lpw49CgJXsp/3elQm2sIHrCF0a FJX3V6wIbMig5FOEbA4VxFaE161XVdo9CF54y7qclRAjviQ9o94L7ZpAkhIOEL1ax8Ty qi/1X1RCO9ggtiVEJMVxHqzWR43I8t/50RDu/4MqFiwtq2JlP3FSZF8vnKvsoXMHtnIz WpIdclQhjyp8dShwgx5ARO5Kl+Dj6dYTSjNL2fVQZIxabFjs/t5oUYqBKME28JFHsXBK dtMmQLDhc0zLazTnwex2BZxhCXB4/RnTVyt9yVuk9pApNrmnX1alYbcJ7H6wMxq6nMB1 zw== Received: from dc5-exch01.marvell.com ([199.233.59.181]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3dq5re1ftb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Thu, 20 Jan 2022 08:48:25 -0800 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 20 Jan 2022 08:48:24 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 20 Jan 2022 08:48:24 -0800 Received: from localhost.localdomain (unknown [10.28.48.55]) by maili.marvell.com (Postfix) with ESMTP id 637D93F7048; Thu, 20 Jan 2022 08:48:19 -0800 (PST) From: Akhil Goyal To: CC: , , , , , , , , , , , , "Akhil Goyal" , Nithin Dabilpuram Subject: [PATCH v2 2/4] app/test: add IP reassembly case with no frags Date: Thu, 20 Jan 2022 22:18:02 +0530 Message-ID: <20220120164804.4163645-3-gakhil@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220120164804.4163645-1-gakhil@marvell.com> References: <20220103150813.1694888-6-gakhil@marvell.com> <20220120164804.4163645-1-gakhil@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-GUID: -g5ww5dHBgKxr3SLGXawz5cqqJ7a4p_Q X-Proofpoint-ORIG-GUID: -g5ww5dHBgKxr3SLGXawz5cqqJ7a4p_Q X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.816,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2022-01-20_06,2022-01-20_01,2021-12-02_01 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org test_inline_ipsec testsuite is extended to test IP reassembly of inbound fragmented packets. The fragmented packet is sent on an interface which encrypts the packet and then it is loopbacked on the same interface which decrypts the packet and then attempts IP reassembly of the decrypted packets. In this patch, a case is added for packets without fragmentation to verify the complete path. Other cases are added in subsequent patches. Signed-off-by: Akhil Goyal Signed-off-by: Nithin Dabilpuram --- app/test/test_security_inline_proto.c | 325 ++++++++++++++++++ app/test/test_security_inline_proto_vectors.h | 1 + 2 files changed, 326 insertions(+) diff --git a/app/test/test_security_inline_proto.c b/app/test/test_security_inline_proto.c index 4738792cb8..9dc083369a 100644 --- a/app/test/test_security_inline_proto.c +++ b/app/test/test_security_inline_proto.c @@ -25,6 +25,8 @@ #define RTE_TEST_TX_DESC_DEFAULT (1024) #define RTE_PORT_ALL (~(uint16_t)0x0) +#define ENCAP_DECAP_BURST_SZ 33 + /* * RX and TX Prefetch, Host, and Write-back threshold values should be * carefully set for optimal performance. Consult the network @@ -103,6 +105,8 @@ struct lcore_cfg lcore_cfg; static uint64_t link_mbps; +static int ip_reass_dynfield_offset = -1; + static struct rte_flow *default_flow[RTE_MAX_ETHPORTS]; /* Create Inline IPsec session */ @@ -477,6 +481,293 @@ destroy_default_flow(uint16_t port_id) struct rte_mbuf **tx_pkts_burst; struct rte_mbuf **rx_pkts_burst; +static int +compare_pkt_data(struct rte_mbuf *m, uint8_t *ref, unsigned int tot_len) +{ + unsigned int len; + unsigned int nb_segs = m->nb_segs; + unsigned int matched = 0; + struct rte_mbuf *save = m; + + while (m && nb_segs != 0) { + len = tot_len; + if (len > m->data_len) + len = m->data_len; + if (len != 0) { + if (memcmp(rte_pktmbuf_mtod(m, char *), + ref + matched, len)) { + printf("\n====Reassembly case failed: Data Mismatch"); + rte_hexdump(stdout, "Reassembled", + rte_pktmbuf_mtod(m, char *), + len); + rte_hexdump(stdout, "reference", + ref + matched, + len); + return TEST_FAILED; + } + } + tot_len -= len; + matched += len; + m = m->next; + nb_segs--; + } + + if (tot_len) { + printf("\n====Reassembly case failed: Data Missing %u", + tot_len); + printf("\n====nb_segs %u, tot_len %u", nb_segs, tot_len); + rte_pktmbuf_dump(stderr, save, -1); + return TEST_FAILED; + } + return TEST_SUCCESS; +} + +static inline bool +is_ip_reassembly_incomplete(struct rte_mbuf *mbuf) +{ + static uint64_t ip_reass_dynflag; + int ip_reass_dynflag_offset; + + if (ip_reass_dynflag == 0) { + ip_reass_dynflag_offset = rte_mbuf_dynflag_lookup( + RTE_ETH_IP_REASS_INCOMPLETE_DYNFLAG_NAME, NULL); + if (ip_reass_dynflag_offset < 0) + return false; + ip_reass_dynflag = RTE_BIT64(ip_reass_dynflag_offset); + } + + return (mbuf->ol_flags & ip_reass_dynflag) != 0; +} + +static void +free_mbuf(struct rte_mbuf *mbuf) +{ + rte_eth_ip_reass_dynfield_t dynfield; + + if (!mbuf) + return; + + if (!is_ip_reassembly_incomplete(mbuf)) { + rte_pktmbuf_free(mbuf); + } else { + if (ip_reass_dynfield_offset < 0) + return; + + while (mbuf) { + dynfield = *RTE_MBUF_DYNFIELD(mbuf, ip_reass_dynfield_offset, + rte_eth_ip_reass_dynfield_t *); + rte_pktmbuf_free(mbuf); + mbuf = dynfield.next_frag; + } + } +} + + +static int +get_and_verify_incomplete_frags(struct rte_mbuf *mbuf, + struct reassembly_vector *vector) +{ + rte_eth_ip_reass_dynfield_t *dynfield[MAX_PKT_BURST]; + int j = 0, ret; + /** + * IP reassembly offload is incomplete, and fragments are listed in + * dynfield which can be reassembled in SW. + */ + printf("\nHW IP Reassembly is not complete; attempt SW IP Reassembly," + "\nMatching with original frags."); + + if (ip_reass_dynfield_offset < 0) + return -1; + + printf("\ncomparing frag: %d", j); + ret = compare_pkt_data(mbuf, vector->frags[j]->data, + vector->frags[j]->len); + if (ret) + return ret; + j++; + dynfield[j] = RTE_MBUF_DYNFIELD(mbuf, ip_reass_dynfield_offset, + rte_eth_ip_reass_dynfield_t *); + printf("\ncomparing frag: %d", j); + ret = compare_pkt_data(dynfield[j]->next_frag, vector->frags[j]->data, + vector->frags[j]->len); + if (ret) + return ret; + + while ((dynfield[j]->nb_frags > 1) && + is_ip_reassembly_incomplete(dynfield[j]->next_frag)) { + j++; + dynfield[j] = RTE_MBUF_DYNFIELD(dynfield[j-1]->next_frag, + ip_reass_dynfield_offset, + rte_eth_ip_reass_dynfield_t *); + printf("\ncomparing frag: %d", j); + ret = compare_pkt_data(dynfield[j]->next_frag, + vector->frags[j]->data, vector->frags[j]->len); + if (ret) + return ret; + } + return ret; +} + +static int +test_ipsec_encap_decap(struct reassembly_vector *vector, + enum rte_security_ipsec_tunnel_type tun_type) +{ + struct rte_ipsec_session out_ips[ENCAP_DECAP_BURST_SZ] = {0}; + struct rte_ipsec_session in_ips[ENCAP_DECAP_BURST_SZ] = {0}; + unsigned int nb_tx, burst_sz, nb_sent = 0; + struct rte_eth_dev_info dev_info = {0}; + unsigned int i, portid, nb_rx = 0, j; + struct ipsec_session_data sa_data; + int ret = 0; + + burst_sz = vector->burst ? ENCAP_DECAP_BURST_SZ : 1; + + portid = lcore_cfg.port; + rte_eth_dev_info_get(portid, &dev_info); + if (dev_info.reass_capa.max_frags < vector->nb_frags) + return TEST_SKIPPED; + + nb_tx = vector->nb_frags * burst_sz; + memset(tx_pkts_burst, 0, sizeof(tx_pkts_burst[0]) * nb_tx); + memset(rx_pkts_burst, 0, sizeof(rx_pkts_burst[0]) * nb_tx); + + for (i = 0; i < nb_tx; i += vector->nb_frags) { + ret = init_traffic(mbufpool[lcore_cfg.socketid], + &tx_pkts_burst[i], vector->frags, + vector->nb_frags); + if (ret != vector->nb_frags) { + ret = -1; + goto out; + } + } + + for (i = 0; i < burst_sz; i++) { + memcpy(&sa_data, vector->sa_data, sizeof(sa_data)); + /* Update SPI for every new SA */ + sa_data.ipsec_xform.spi += i; + + /* Create Inline IPsec outbound session. */ + ret = create_inline_ipsec_session(&sa_data, portid, &out_ips[i], + RTE_SECURITY_IPSEC_SA_DIR_EGRESS, + tun_type); + if (ret) + goto out; + } + + j = 0; + for (i = 0; i < nb_tx; i++) { + if (out_ips[j].security.ol_flags & + RTE_SECURITY_TX_OLOAD_NEED_MDATA) + rte_security_set_pkt_metadata(out_ips[j].security.ctx, + out_ips[j].security.ses, tx_pkts_burst[i], NULL); + tx_pkts_burst[i]->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD; + tx_pkts_burst[i]->l2_len = RTE_ETHER_HDR_LEN; + + /* Move to next SA after nb_frags */ + if ((i + 1) % vector->nb_frags == 0) + j++; + } + + for (i = 0; i < burst_sz; i++) { + memcpy(&sa_data, vector->sa_data, sizeof(sa_data)); + /* Update SPI for every new SA */ + sa_data.ipsec_xform.spi += i; + + /* Create Inline IPsec inbound session. */ + ret = create_inline_ipsec_session(&sa_data, portid, &in_ips[i], + RTE_SECURITY_IPSEC_SA_DIR_INGRESS, + tun_type); + if (ret) + goto out; + } + + /* Retrieve reassembly dynfield offset if available */ + if (ip_reass_dynfield_offset < 0 && vector->nb_frags > 1) + ip_reass_dynfield_offset = rte_mbuf_dynfield_lookup( + RTE_ETH_IP_REASS_DYNFIELD_NAME, NULL); + + + create_default_flow(portid); + + nb_sent = rte_eth_tx_burst(portid, 0, tx_pkts_burst, nb_tx); + if (nb_sent != nb_tx) { + ret = -1; + printf("\nFailed to tx %u pkts", nb_tx); + goto out; + } + + rte_delay_ms(100); + + /* Retry few times before giving up */ + nb_rx = 0; + j = 0; + do { + nb_rx += rte_eth_rx_burst(portid, 0, &rx_pkts_burst[nb_rx], + nb_tx - nb_rx); + j++; + if (nb_rx >= nb_tx) + break; + rte_delay_ms(100); + } while (j < 5 || !nb_rx); + + /* Check for minimum number of Rx packets expected */ + if ((vector->nb_frags == 1 && nb_rx != nb_tx) || + (vector->nb_frags > 1 && nb_rx < burst_sz)) { + printf("\nreceived less Rx pkts(%u) pkts\n", nb_rx); + ret = TEST_FAILED; + goto out; + } + + for (i = 0; i < nb_rx; i++) { + if (vector->nb_frags > 1 && + is_ip_reassembly_incomplete(rx_pkts_burst[i])) { + ret = get_and_verify_incomplete_frags(rx_pkts_burst[i], + vector); + if (ret != TEST_SUCCESS) + break; + continue; + } + + if (rx_pkts_burst[i]->ol_flags & + RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED || + !(rx_pkts_burst[i]->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD)) { + printf("\nsecurity offload failed\n"); + ret = TEST_FAILED; + break; + } + + if (vector->full_pkt->len != rx_pkts_burst[i]->pkt_len) { + printf("\nreassembled/decrypted packet length mismatch\n"); + ret = TEST_FAILED; + break; + } + ret = compare_pkt_data(rx_pkts_burst[i], + vector->full_pkt->data, + vector->full_pkt->len); + if (ret != TEST_SUCCESS) + break; + } + +out: + destroy_default_flow(portid); + + /* Clear session data. */ + for (i = 0; i < burst_sz; i++) { + if (out_ips[i].security.ses) + rte_security_session_destroy(out_ips[i].security.ctx, + out_ips[i].security.ses); + if (in_ips[i].security.ses) + rte_security_session_destroy(in_ips[i].security.ctx, + in_ips[i].security.ses); + } + + for (i = nb_sent; i < nb_tx; i++) + free_mbuf(tx_pkts_burst[i]); + for (i = 0; i < nb_rx; i++) + free_mbuf(rx_pkts_burst[i]); + return ret; +} + static int test_ipsec(struct reassembly_vector *vector, enum rte_security_ipsec_sa_direction dir, @@ -733,6 +1024,34 @@ test_ipsec_ipv4_decap_nofrag(void) RTE_SECURITY_IPSEC_TUNNEL_IPV4); } +static int +test_reassembly_ipv4_nofrag(void) +{ + struct reassembly_vector ipv4_nofrag_case = { + .sa_data = &conf_aes_128_gcm, + .full_pkt = &pkt_ipv4_plain, + .frags[0] = &pkt_ipv4_plain, + .nb_frags = 1, + }; + return test_ipsec_encap_decap(&ipv4_nofrag_case, + RTE_SECURITY_IPSEC_TUNNEL_IPV4); +} + + +static int +test_ipsec_ipv4_burst_encap_decap(void) +{ + struct reassembly_vector ipv4_nofrag_case = { + .sa_data = &conf_aes_128_gcm, + .full_pkt = &pkt_ipv4_plain, + .frags[0] = &pkt_ipv4_plain, + .nb_frags = 1, + .burst = true, + }; + return test_ipsec_encap_decap(&ipv4_nofrag_case, + RTE_SECURITY_IPSEC_TUNNEL_IPV4); +} + static struct unit_test_suite inline_ipsec_testsuite = { .suite_name = "Inline IPsec Ethernet Device Unit Test Suite", .setup = testsuite_setup, @@ -744,6 +1063,12 @@ static struct unit_test_suite inline_ipsec_testsuite = { TEST_CASE_ST(ut_setup_inline_ipsec, ut_teardown_inline_ipsec, test_ipsec_ipv4_decap_nofrag), + TEST_CASE_ST(ut_setup_inline_ipsec, + ut_teardown_inline_ipsec, + test_reassembly_ipv4_nofrag), + TEST_CASE_ST(ut_setup_inline_ipsec, + ut_teardown_inline_ipsec, + test_ipsec_ipv4_burst_encap_decap), TEST_CASES_END() /**< NULL terminate unit test array */ } diff --git a/app/test/test_security_inline_proto_vectors.h b/app/test/test_security_inline_proto_vectors.h index 08e6868b0d..861c4fad48 100644 --- a/app/test/test_security_inline_proto_vectors.h +++ b/app/test/test_security_inline_proto_vectors.h @@ -42,6 +42,7 @@ struct reassembly_vector { struct ipsec_test_packet *full_pkt; struct ipsec_test_packet *frags[MAX_FRAGS]; uint16_t nb_frags; + bool burst; }; struct ipsec_test_packet pkt_ipv4_plain = { -- 2.25.1