@@ -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>
@@ -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",
ð_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();
@@ -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;
}
@@ -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 */
};
@@ -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"