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 326E4A0032; Thu, 17 Feb 2022 18:24:11 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9E30741152; Thu, 17 Feb 2022 18:24:05 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 3FD1641142 for ; Thu, 17 Feb 2022 18:24:04 +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 21HGH4ov014913; Thu, 17 Feb 2022 09:23:59 -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=56/M3p0K8QRmrYKH+4Dgp+XuTr0GulICP9ekGxBbq7Q=; b=Pp2z3sRcmaoPAN1d2dNrzRLp9A7/2/ZD9mw2B54QcbuTGT9pcL/S7cNk27rnYY+2mM3y ZzCrsv8Ckq1JE8Nr8nTEZ45584PZKfpLyL4cnSqzXas0bU9vdEma7CfxZ7mqttlv605x gOYG0gCQosfTf5GxNSiKhyboZD93JpAha+EtmRNi6CXezYlEsT+KDfzK2n+21d68UEKs W7+ReslqCfsPLFw2k4Rv9nN5fcv4rHqNFXawHGicx3oBYM1SvSmx201Hb2ot1+fubLHE W8KgrLb2bR79x64RmUM7Ch4pPCfKpXiOXszFfZVxOGzNjypggSdWl71GlurThNvJyZFu 7A== Received: from dc5-exch01.marvell.com ([199.233.59.181]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3e9sqrgb3x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Thu, 17 Feb 2022 09:23:59 -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, 17 Feb 2022 09:23:58 -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, 17 Feb 2022 09:23:57 -0800 Received: from localhost.localdomain (unknown [10.28.48.55]) by maili.marvell.com (Postfix) with ESMTP id EFC783F706F; Thu, 17 Feb 2022 09:23:53 -0800 (PST) From: Akhil Goyal To: CC: , , , , , , , , , , , , Akhil Goyal , Nithin Dabilpuram Subject: [PATCH v3 2/4] app/test: add IP reassembly case with no frags Date: Thu, 17 Feb 2022 22:53:39 +0530 Message-ID: <20220217172341.607360-3-gakhil@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220217172341.607360-1-gakhil@marvell.com> References: <20220120164804.4163645-1-gakhil@marvell.com> <20220217172341.607360-1-gakhil@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-ORIG-GUID: 5MJSvuy-De27nAcBdi4xI-BykajPvhRa X-Proofpoint-GUID: 5MJSvuy-De27nAcBdi4xI-BykajPvhRa 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-02-17_06,2022-02-17_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 | 326 ++++++++++++++++++ app/test/test_security_inline_proto_vectors.h | 1 + 2 files changed, 327 insertions(+) diff --git a/app/test/test_security_inline_proto.c b/app/test/test_security_inline_proto.c index e2b95de68e..3fbf8105e1 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 @@ -102,6 +104,8 @@ struct lcore_cfg lcore_cfg; static uint64_t link_mbps; +static int ip_reassembly_dynfield_offset = -1; + static struct rte_flow *default_flow[RTE_MAX_ETHPORTS]; /* Create Inline IPsec session */ @@ -476,6 +480,294 @@ 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_reassembly_dynflag; + int ip_reassembly_dynflag_offset; + + if (ip_reassembly_dynflag == 0) { + ip_reassembly_dynflag_offset = rte_mbuf_dynflag_lookup( + RTE_MBUF_DYNFLAG_IP_REASSEMBLY_INCOMPLETE_NAME, NULL); + if (ip_reassembly_dynflag_offset < 0) + return false; + ip_reassembly_dynflag = RTE_BIT64(ip_reassembly_dynflag_offset); + } + + return (mbuf->ol_flags & ip_reassembly_dynflag) != 0; +} + +static void +free_mbuf(struct rte_mbuf *mbuf) +{ + rte_eth_ip_reassembly_dynfield_t dynfield; + + if (!mbuf) + return; + + if (!is_ip_reassembly_incomplete(mbuf)) { + rte_pktmbuf_free(mbuf); + } else { + if (ip_reassembly_dynfield_offset < 0) + return; + + while (mbuf) { + dynfield = *RTE_MBUF_DYNFIELD(mbuf, + ip_reassembly_dynfield_offset, + rte_eth_ip_reassembly_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_reassembly_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_reassembly_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_reassembly_dynfield_offset, + rte_eth_ip_reassembly_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_reassembly_dynfield_offset, + rte_eth_ip_reassembly_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}; + struct rte_eth_ip_reassembly_params reass_capa = {0}; + unsigned int nb_tx, burst_sz, nb_sent = 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_ip_reassembly_capability_get(portid, &reass_capa); + if (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_reassembly_dynfield_offset < 0 && vector->nb_frags > 1) + ip_reassembly_dynfield_offset = rte_mbuf_dynfield_lookup( + RTE_MBUF_DYNFIELD_IP_REASSEMBLY_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, @@ -732,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, @@ -743,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 94d2f0145c..2ee1b3fc41 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