DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v2] ip_frag: support IPv6 reassembly with extensions
@ 2024-10-15  8:21 vignesh.purushotham.srinivas
  0 siblings, 0 replies; only message in thread
From: vignesh.purushotham.srinivas @ 2024-10-15  8:21 UTC (permalink / raw)
  To: konstantin.v.ananyev; +Cc: dev, Vignesh PS

From: Vignesh PS <vignesh.purushotham.srinivas@ericsson.com>

Add support to ip_frag library to perform IPv6 reassembly
when extension headers are present before the fragment
extension in the packet.

Signed-off-by: Vignesh PS <vignesh.purushotham.srinivas@ericsson.com>
---
 .mailmap                          |   1 +
 app/test/test_reassembly_perf.c   | 163 +++++++++++++++++++-----------
 lib/ip_frag/ip_frag_common.h      |   4 +
 lib/ip_frag/ip_reassembly.h       |   2 +
 lib/ip_frag/rte_ipv6_reassembly.c |  75 ++++++++++++--
 5 files changed, 179 insertions(+), 66 deletions(-)

diff --git a/.mailmap b/.mailmap
index ed4ea17c4c..1bd3885424 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1555,6 +1555,7 @@ Viacheslav Ovsiienko <viacheslavo@nvidia.com> <viacheslavo@mellanox.com>
 Victor Kaplansky <victork@redhat.com>
 Victor Raj <victor.raj@intel.com>
 Vidya Sagar Velumuri <vvelumuri@marvell.com>
+Vignesh PS <vignesh.purushotham.srinivas@ericsson.com> <vig.vigneshps1995@gmail.com>
 Vignesh Sridhar <vignesh.sridhar@intel.com>
 Vijayakumar Muthuvel Manickam <mmvijay@gmail.com>
 Vijaya Mohan Guvva <vijay1054@gmail.com>
diff --git a/app/test/test_reassembly_perf.c b/app/test/test_reassembly_perf.c
index 3912179022..6090182943 100644
--- a/app/test/test_reassembly_perf.c
+++ b/app/test/test_reassembly_perf.c
@@ -47,6 +47,16 @@ static struct rte_mbuf *mbufs[MAX_FLOWS][MAX_FRAGMENTS];
 static uint8_t frag_per_flow[MAX_FLOWS];
 static uint32_t flow_cnt;
 
+struct ipv6_extension_routing {
+	uint8_t next_header;
+	uint8_t length;
+	uint8_t type;
+	uint8_t segments;
+	uint32_t data;
+};
+
+#define IPV6_ROUTING_HDR_SIZE sizeof(struct ipv6_extension_routing)
+
 #define FILL_MODE_LINEAR      0
 #define FILL_MODE_RANDOM      1
 #define FILL_MODE_INTERLEAVED 2
@@ -108,15 +118,15 @@ static void
 reassembly_print_banner(const char *proto_str)
 {
 	printf("+=============================================================="
-	       "============================================+\n");
-	printf("| %-32s| %-3s : %-58d|\n", proto_str, "Flow Count", MAX_FLOWS);
+	       "===========================================================+\n");
+	printf("| %-32s| %-3s : %-73d|\n", proto_str, "Flow Count", MAX_FLOWS);
 	printf("+================+================+=============+=============+"
-	       "========================+===================+\n");
-	printf("%-17s%-17s%-14s%-14s%-25s%-20s\n", "| Fragment Order",
-	       "| Fragments/Flow", "| Outstanding", "| Cycles/Flow",
+	       "========================+==================================+\n");
+	printf("%-17s%-17s%-15s%-14s%-14s%-25s%-20s\n", "| Fragment Order",
+	       "| Fragments/Flow", "| Extensions", "| Outstanding", "| Cycles/Flow",
 	       "| Cycles/Fragment insert", "| Cycles/Reassembly |");
 	printf("+================+================+=============+=============+"
-	       "========================+===================+\n");
+	       "========================+==================================+\n");
 }
 
 static void
@@ -272,9 +282,10 @@ ipv4_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag)
 
 static void
 ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
-		    uint8_t fill_mode)
+		    uint8_t fill_mode, uint8_t num_exts)
 {
 	struct ipv6_extension_fragment *frag_hdr;
+	struct ipv6_extension_routing *routing_hdr;
 	struct rte_ether_hdr *eth_hdr;
 	struct rte_ipv6_hdr *ip_hdr;
 	struct rte_udp_hdr *udp_hdr;
@@ -303,15 +314,18 @@ ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
 		eth_hdr = rte_pktmbuf_mtod(frag, struct rte_ether_hdr *);
 		ip_hdr = rte_pktmbuf_mtod_offset(frag, struct rte_ipv6_hdr *,
 						 sizeof(struct rte_ether_hdr));
+
 		udp_hdr = rte_pktmbuf_mtod_offset(
 			frag, struct rte_udp_hdr *,
 			sizeof(struct rte_ether_hdr) +
 				sizeof(struct rte_ipv6_hdr) +
+				num_exts * IPV6_ROUTING_HDR_SIZE +
 				RTE_IPV6_FRAG_HDR_SIZE);
 		frag_hdr = rte_pktmbuf_mtod_offset(
 			frag, struct ipv6_extension_fragment *,
 			sizeof(struct rte_ether_hdr) +
-				sizeof(struct rte_ipv6_hdr));
+				sizeof(struct rte_ipv6_hdr) +
+				num_exts * IPV6_ROUTING_HDR_SIZE);
 
 		rte_ether_unformat_addr("02:00:00:00:00:01",
 					&eth_hdr->dst_addr);
@@ -334,11 +348,15 @@ ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
 		 * Initialize IP header.
 		 */
 		pkt_len = (uint16_t)(pkt_len + sizeof(struct rte_ipv6_hdr) +
-				     RTE_IPV6_FRAG_HDR_SIZE);
+			num_exts * IPV6_ROUTING_HDR_SIZE +
+				RTE_IPV6_FRAG_HDR_SIZE);
 		ip_hdr->vtc_flow = rte_cpu_to_be_32(IP6_VERSION << 28);
 		ip_hdr->payload_len =
 			rte_cpu_to_be_16(pkt_len - sizeof(struct rte_ipv6_hdr));
-		ip_hdr->proto = IPPROTO_FRAGMENT;
+		if (num_exts > 0)
+			ip_hdr->proto = IPPROTO_ROUTING;
+		else
+			ip_hdr->proto = IPPROTO_FRAGMENT;
 		ip_hdr->hop_limits = IP_DEFTTL;
 		memcpy(ip_hdr->src_addr, ip6_addr, sizeof(ip_hdr->src_addr));
 		memcpy(ip_hdr->dst_addr, ip6_addr, sizeof(ip_hdr->dst_addr));
@@ -352,6 +370,24 @@ ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
 		ip_hdr->dst_addr[8] = (flow_id >> 8) & 0xff;
 		ip_hdr->dst_addr[9] = flow_id & 0xff;
 
+		for (uint8_t exts = 0; exts < num_exts; exts++) {
+			routing_hdr = rte_pktmbuf_mtod_offset(
+				frag, struct ipv6_extension_routing *,
+					sizeof(struct rte_ether_hdr) +
+					sizeof(struct rte_ipv6_hdr) +
+					exts * IPV6_ROUTING_HDR_SIZE);
+
+			routing_hdr->length = 0;    /* zero because extension is bare, no data */
+			routing_hdr->type = 4;
+			routing_hdr->segments = num_exts - exts - 1;
+			routing_hdr->data = 0;
+
+			if (exts == num_exts - 1)
+				routing_hdr->next_header = IPPROTO_FRAGMENT;
+			else
+				routing_hdr->next_header = IPPROTO_ROUTING;
+		}
+
 		frag_hdr->next_header = IPPROTO_UDP;
 		frag_hdr->reserved = 0;
 		frag_hdr->frag_data = rte_cpu_to_be_16(frag_offset);
@@ -361,7 +397,9 @@ ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
 		frag->pkt_len = frag->data_len;
 		frag->l2_len = sizeof(struct rte_ether_hdr);
 		frag->l3_len =
-			sizeof(struct rte_ipv6_hdr) + RTE_IPV6_FRAG_HDR_SIZE;
+			sizeof(struct rte_ipv6_hdr) +
+				num_exts * IPV6_ROUTING_HDR_SIZE +
+				RTE_IPV6_FRAG_HDR_SIZE;
 	}
 
 	if (fill_mode == FILL_MODE_RANDOM)
@@ -369,7 +407,7 @@ ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id,
 }
 
 static int
-ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag)
+ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag, uint8_t num_exts)
 {
 	uint8_t nb_frag;
 	int i;
@@ -379,7 +417,7 @@ ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag)
 		if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
 		    0)
 			return TEST_FAILED;
-		ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
+		ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode, num_exts);
 		frag_per_flow[i] = nb_frag;
 	}
 	flow_cnt = i;
@@ -388,7 +426,7 @@ ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag)
 }
 
 static int
-ipv6_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag)
+ipv6_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag, uint8_t num_exts)
 {
 	int i;
 
@@ -396,7 +434,7 @@ ipv6_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag)
 		if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) <
 		    0)
 			return TEST_FAILED;
-		ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode);
+		ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode, num_exts);
 		frag_per_flow[i] = nb_frag;
 	}
 	flow_cnt = i;
@@ -414,7 +452,7 @@ frag_pkt_teardown(void)
 }
 
 static void
-reassembly_print_stats(int8_t nb_frags, uint8_t fill_order,
+reassembly_print_stats(int8_t nb_frags, uint8_t fill_order, uint8_t num_exts,
 		       uint32_t outstanding, uint64_t cyc_per_flow,
 		       uint64_t cyc_per_frag_insert,
 		       uint64_t cyc_per_reassembly)
@@ -440,12 +478,12 @@ reassembly_print_stats(int8_t nb_frags, uint8_t fill_order,
 		break;
 	}
 
-	printf("| %-14s | %-14s | %-11d | %-11" PRIu64 " | %-22" PRIu64
+	printf("| %-14s | %-14s | %-12d | %-11d | %-11" PRIu64 " | %-22" PRIu64
 	       " | %-17" PRIu64 " |\n",
-	       order_str, frag_str, outstanding, cyc_per_flow,
+	       order_str, frag_str, num_exts, outstanding, cyc_per_flow,
 	       cyc_per_frag_insert, cyc_per_reassembly);
 	printf("+================+================+=============+=============+"
-	       "========================+===================+\n");
+	       "========================+==================================+\n");
 }
 
 static void
@@ -501,7 +539,7 @@ ipv4_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
 		mbufs[i][0] = buf_out;
 	}
 
-	reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt,
+	reassembly_print_stats(nb_frags, fill_order, 0, 0, total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
 
@@ -576,7 +614,7 @@ ipv4_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
 		mbufs[i][0] = buf_out;
 	}
 
-	reassembly_print_stats(nb_frags, fill_order, outstanding,
+	reassembly_print_stats(nb_frags, fill_order, 0, outstanding,
 			       total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
@@ -642,7 +680,7 @@ ipv4_reassembly_interleaved_flows_perf(uint8_t nb_frags)
 		}
 	}
 
-	reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0,
+	reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0, 0,
 			       total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
@@ -651,7 +689,7 @@ ipv4_reassembly_interleaved_flows_perf(uint8_t nb_frags)
 }
 
 static int
-ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
+ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order, uint8_t num_exts)
 {
 	struct rte_ip_frag_death_row death_row;
 	uint64_t total_reassembled_cyc = 0;
@@ -673,8 +711,8 @@ ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
 			struct ipv6_extension_fragment *frag_hdr =
 				rte_pktmbuf_mtod_offset(
 					buf, struct ipv6_extension_fragment *,
-					buf->l2_len +
-						sizeof(struct rte_ipv6_hdr));
+					buf->l2_len + sizeof(struct rte_ipv6_hdr) +
+						num_exts * IPV6_ROUTING_HDR_SIZE);
 
 			tstamp = rte_rdtsc_precise();
 			buf_out = rte_ipv6_frag_reassemble_packet(
@@ -699,7 +737,7 @@ ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
 		mbufs[i][0] = buf_out;
 	}
 
-	reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt,
+	reassembly_print_stats(nb_frags, fill_order, num_exts, 0, total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
 
@@ -708,7 +746,7 @@ ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order)
 
 static int
 ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
-				 uint32_t outstanding)
+				 uint32_t outstanding, uint8_t num_exts)
 {
 	struct rte_ip_frag_death_row death_row;
 	uint64_t total_reassembled_cyc = 0;
@@ -731,8 +769,8 @@ ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
 			struct ipv6_extension_fragment *frag_hdr =
 				rte_pktmbuf_mtod_offset(
 					buf, struct ipv6_extension_fragment *,
-					buf->l2_len +
-						sizeof(struct rte_ipv6_hdr));
+					buf->l2_len + sizeof(struct rte_ipv6_hdr) +
+						num_exts * IPV6_ROUTING_HDR_SIZE);
 
 			tstamp = rte_rdtsc_precise();
 			buf_out = rte_ipv6_frag_reassemble_packet(
@@ -761,8 +799,8 @@ ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
 			struct ipv6_extension_fragment *frag_hdr =
 				rte_pktmbuf_mtod_offset(
 					buf, struct ipv6_extension_fragment *,
-					buf->l2_len +
-						sizeof(struct rte_ipv6_hdr));
+					buf->l2_len + sizeof(struct rte_ipv6_hdr) +
+						num_exts * IPV6_ROUTING_HDR_SIZE);
 
 			tstamp = rte_rdtsc_precise();
 			buf_out = rte_ipv6_frag_reassemble_packet(
@@ -787,7 +825,7 @@ ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
 		mbufs[i][0] = buf_out;
 	}
 
-	reassembly_print_stats(nb_frags, fill_order, outstanding,
+	reassembly_print_stats(nb_frags, fill_order, num_exts, outstanding,
 			       total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
@@ -796,7 +834,7 @@ ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order,
 }
 
 static int
-ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags)
+ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags, uint8_t num_exts)
 {
 	struct rte_ip_frag_death_row death_row;
 	uint64_t total_reassembled_cyc = 0;
@@ -830,8 +868,8 @@ ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags)
 			struct ipv6_extension_fragment *frag_hdr =
 				rte_pktmbuf_mtod_offset(
 					buf, struct ipv6_extension_fragment *,
-					buf->l2_len +
-						sizeof(struct rte_ipv6_hdr));
+					buf->l2_len + sizeof(struct rte_ipv6_hdr) +
+						num_exts * IPV6_ROUTING_HDR_SIZE);
 
 			tstamp = rte_rdtsc_precise();
 			buf_out[reassembled] = rte_ipv6_frag_reassemble_packet(
@@ -859,7 +897,7 @@ ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags)
 		}
 	}
 
-	reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0,
+	reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, num_exts, 0,
 			       total_cyc / flow_cnt,
 			       total_empty_cyc / frag_processed,
 			       total_reassembled_cyc / flow_cnt);
@@ -894,25 +932,27 @@ ipv4_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding)
 }
 
 static int
-ipv6_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding)
+ipv6_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding,
+			uint8_t num_exts)
 {
 	int rc;
 
 	if (nb_frags > 0)
-		rc = ipv6_frag_pkt_setup(fill_order, nb_frags);
+		rc = ipv6_frag_pkt_setup(fill_order, nb_frags, num_exts);
 	else
-		rc = ipv6_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS);
+		rc = ipv6_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS, num_exts);
+
 
 	if (rc)
 		return rc;
 
 	if (outstanding)
 		rc = ipv6_outstanding_reassembly_perf(nb_frags, fill_order,
-						      outstanding);
+						      outstanding, num_exts);
 	else if (fill_order == FILL_MODE_INTERLEAVED)
-		rc = ipv6_reassembly_interleaved_flows_perf(nb_frags);
+		rc = ipv6_reassembly_interleaved_flows_perf(nb_frags, num_exts);
 	else
-		rc = ipv6_reassembly_perf(nb_frags, fill_order);
+		rc = ipv6_reassembly_perf(nb_frags, fill_order, num_exts);
 
 	frag_pkt_teardown();
 
@@ -925,7 +965,8 @@ test_reassembly_perf(void)
 	int8_t nb_fragments[] = {2, 3, MAX_FRAGMENTS, -1 /* Random */};
 	uint8_t order_type[] = {FILL_MODE_LINEAR, FILL_MODE_RANDOM};
 	uint32_t outstanding[] = {100, 500, 1000, 2000, 3000};
-	uint32_t i, j;
+	uint8_t num_exts[] = {0, 4, 8};
+	uint32_t i, j, k;
 	int rc;
 
 	rc = reassembly_test_setup();
@@ -967,32 +1008,40 @@ test_reassembly_perf(void)
 	/* Test variable fragment count and ordering. */
 	for (i = 0; i < RTE_DIM(nb_fragments); i++) {
 		for (j = 0; j < RTE_DIM(order_type); j++) {
-			rc = ipv6_reassembly_test(nb_fragments[i],
-						  order_type[j], 0);
-			if (rc)
-				return rc;
+			for (k = 0; k < RTE_DIM(num_exts); k++) {
+				rc = ipv6_reassembly_test(nb_fragments[i],
+							  order_type[j], 0, num_exts[k]);
+				if (rc)
+					return rc;
+			}
 		}
 	}
 
 	/* Test outstanding fragments in the table. */
 	for (i = 0; i < RTE_DIM(outstanding); i++) {
-		rc = ipv6_reassembly_test(2, 0, outstanding[i]);
-		if (rc)
-			return rc;
+		for (k = 0; k < RTE_DIM(num_exts); k++) {
+			rc = ipv6_reassembly_test(2, 0, outstanding[i], num_exts[k]);
+			if (rc)
+				return rc;
+		}
 	}
 
 	for (i = 0; i < RTE_DIM(outstanding); i++) {
-		rc = ipv6_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i]);
-		if (rc)
-			return rc;
+		for (k = 0; k < RTE_DIM(num_exts); k++) {
+			rc = ipv6_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i], num_exts[k]);
+			if (rc)
+				return rc;
+		}
 	}
 
 	/* Test interleaved flow reassembly perf */
 	for (i = 0; i < RTE_DIM(nb_fragments); i++) {
-		rc = ipv6_reassembly_test(nb_fragments[i],
-					  FILL_MODE_INTERLEAVED, 0);
-		if (rc)
-			return rc;
+		for (k = 0; k < RTE_DIM(num_exts); k++) {
+			rc = ipv6_reassembly_test(nb_fragments[i],
+						  FILL_MODE_INTERLEAVED, 0, num_exts[k]);
+			if (rc)
+				return rc;
+		}
 	}
 	reassembly_test_teardown();
 
diff --git a/lib/ip_frag/ip_frag_common.h b/lib/ip_frag/ip_frag_common.h
index 51fc9d47fb..67f5f01c5e 100644
--- a/lib/ip_frag/ip_frag_common.h
+++ b/lib/ip_frag/ip_frag_common.h
@@ -34,6 +34,8 @@ extern int ipfrag_logtype;
 #define IPV4_KEYLEN 1
 #define IPV6_KEYLEN 4
 
+#define MAX_NUM_IPV6_EXTS 8
+
 /* helper macros */
 #define	IP_FRAG_MBUF2DR(dr, mb)	((dr)->row[(dr)->cnt++] = (mb))
 
@@ -169,6 +171,8 @@ ip_frag_reset(struct ip_frag_pkt *fp, uint64_t tms)
 	fp->total_size = UINT32_MAX;
 	fp->frag_size = 0;
 	fp->last_idx = IP_MIN_FRAG_NUM;
+	fp->exts_len = 0;
+	fp->next_proto = NULL;
 	fp->frags[IP_LAST_FRAG_IDX] = zero_frag;
 	fp->frags[IP_FIRST_FRAG_IDX] = zero_frag;
 }
diff --git a/lib/ip_frag/ip_reassembly.h b/lib/ip_frag/ip_reassembly.h
index 54afed5417..689a36ed9a 100644
--- a/lib/ip_frag/ip_reassembly.h
+++ b/lib/ip_frag/ip_reassembly.h
@@ -51,9 +51,11 @@ struct __rte_cache_aligned ip_frag_pkt {
 	RTE_TAILQ_ENTRY(ip_frag_pkt) lru;      /* LRU list */
 	struct ip_frag_key key;                /* fragmentation key */
 	uint64_t start;                        /* creation timestamp */
+	uint8_t *next_proto;                   /* pointer of the next_proto field */
 	uint32_t total_size;                   /* expected reassembled size */
 	uint32_t frag_size;                    /* size of fragments received */
 	uint32_t last_idx;                     /* index of next entry to fill */
+	uint32_t exts_len;                     /* length of extension hdrs for first fragment */
 	struct ip_frag frags[IP_MAX_FRAG_NUM]; /* fragments */
 };
 
diff --git a/lib/ip_frag/rte_ipv6_reassembly.c b/lib/ip_frag/rte_ipv6_reassembly.c
index 88863a98d1..fa41bd8e37 100644
--- a/lib/ip_frag/rte_ipv6_reassembly.c
+++ b/lib/ip_frag/rte_ipv6_reassembly.c
@@ -91,19 +91,19 @@ ipv6_frag_reassemble(struct ip_frag_pkt *fp)
 	/* update ipv6 header for the reassembled datagram */
 	ip_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *, m->l2_len);
 
+	payload_len += fp->exts_len;
 	ip_hdr->payload_len = rte_cpu_to_be_16(payload_len);
 
 	/*
 	 * remove fragmentation header. note that per RFC2460, we need to update
 	 * the last non-fragmentable header with the "next header" field to contain
-	 * type of the first fragmentable header, but we currently don't support
-	 * other headers, so we assume there are no other headers and thus update
-	 * the main IPv6 header instead.
+	 * type of the first fragmentable header.
 	 */
-	move_len = m->l2_len + m->l3_len - sizeof(*frag_hdr);
-	frag_hdr = (struct rte_ipv6_fragment_ext *) (ip_hdr + 1);
-	ip_hdr->proto = frag_hdr->next_header;
+	frag_hdr = (struct rte_ipv6_fragment_ext *)
+		((uint8_t *) (ip_hdr + 1) + fp->exts_len);
+	*fp->next_proto = frag_hdr->next_header;
 
+	move_len = m->l2_len + m->l3_len - sizeof(*frag_hdr);
 	ip_frag_memmove(rte_pktmbuf_mtod_offset(m, char *, sizeof(*frag_hdr)),
 			rte_pktmbuf_mtod(m, char*), move_len);
 
@@ -112,6 +112,42 @@ ipv6_frag_reassemble(struct ip_frag_pkt *fp)
 	return m;
 }
 
+/*
+ * Function to crawl through the extension header stack.
+ * This function breaks as soon a the fragment header is
+ * found and returns the total length the traversed exts
+ * and the last extension before the fragment header
+ */
+static inline int
+ip_frag_get_last_exthdr(struct rte_ipv6_hdr *ip_hdr, uint8_t **last_ext)
+{
+	uint32_t total_len = 0;
+	uint8_t num_exts = 0;
+	size_t ext_len = 0;
+	*last_ext = (uint8_t *)(ip_hdr + 1);
+	int next_proto = ip_hdr->proto;
+
+	if (next_proto == IPPROTO_FRAGMENT)
+		return total_len;
+
+	while (next_proto != IPPROTO_FRAGMENT && num_exts < MAX_NUM_IPV6_EXTS) {
+
+		next_proto = rte_ipv6_get_next_ext(*last_ext, next_proto, &ext_len);
+		if (next_proto < 0)
+			break;
+
+		total_len += ext_len;
+
+		if (next_proto == IPPROTO_FRAGMENT)
+			return total_len;
+
+		*last_ext += ext_len;
+		num_exts++;
+	}
+
+	return -1;
+}
+
 /*
  * Process new mbuf with fragment of IPV6 datagram.
  * Incoming mbuf should have its l2_len/l3_len fields setup correctly.
@@ -139,6 +175,8 @@ rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl,
 {
 	struct ip_frag_pkt *fp;
 	struct ip_frag_key key;
+	uint8_t *last_ipv6_ext;
+	int exts_len;
 	uint16_t ip_ofs;
 	int32_t ip_len;
 	int32_t trim;
@@ -154,10 +192,15 @@ rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl,
 	/*
 	 * as per RFC2460, payload length contains all extension headers
 	 * as well.
-	 * since we don't support anything but frag headers,
-	 * this is what we remove from the payload len.
+	 * so we remove the extension len from the payload len.
 	 */
-	ip_len = rte_be_to_cpu_16(ip_hdr->payload_len) - sizeof(*frag_hdr);
+	exts_len = ip_frag_get_last_exthdr(ip_hdr, &last_ipv6_ext);
+	if (exts_len < 0) {
+		IP_FRAG_MBUF2DR(dr, mb);
+		return NULL;
+	}
+
+	ip_len = rte_be_to_cpu_16(ip_hdr->payload_len) - exts_len - sizeof(*frag_hdr);
 	trim = mb->pkt_len - (ip_len + mb->l3_len + mb->l2_len);
 
 	IP_FRAG_LOG(DEBUG, "%s:%d:\n"
@@ -197,10 +240,24 @@ rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl,
 		fp, IPv6_KEY_BYTES(fp->key.src_dst), fp->key.id, fp->start,
 		fp->total_size, fp->frag_size, fp->last_idx);
 
+	/* store extension stack info, only for first fragment */
+	if (ip_ofs == 0) {
+		/*
+		 * fp->next_proto points to either the IP's next header
+		 * or th next header of the extension before the fragment
+		 * extension
+		 */
+		fp->next_proto = (uint8_t *)&ip_hdr->proto;
+		if (exts_len > 0) {
+			fp->exts_len = exts_len;
+			fp->next_proto = last_ipv6_ext;
+		}
+	}
 
 	/* process the fragmented packet. */
 	mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len,
 			MORE_FRAGS(frag_hdr->frag_data));
+
 	ip_frag_inuse(tbl, fp);
 
 	IP_FRAG_LOG(DEBUG, "%s:%d:\n"
-- 
2.34.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-10-15  8:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-15  8:21 [PATCH v2] ip_frag: support IPv6 reassembly with extensions vignesh.purushotham.srinivas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).