xref: /f-stack/dpdk/lib/librte_net/rte_net.c (revision 2d9fd380)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  */
4 
5 #include <stdint.h>
6 
7 #include <rte_mbuf.h>
8 #include <rte_mbuf_ptype.h>
9 #include <rte_byteorder.h>
10 #include <rte_ether.h>
11 #include <rte_ip.h>
12 #include <rte_tcp.h>
13 #include <rte_udp.h>
14 #include <rte_sctp.h>
15 #include <rte_gre.h>
16 #include <rte_mpls.h>
17 #include <rte_net.h>
18 
19 /* get l3 packet type from ip6 next protocol */
20 static uint32_t
ptype_l3_ip6(uint8_t ip6_proto)21 ptype_l3_ip6(uint8_t ip6_proto)
22 {
23 	static const uint32_t ip6_ext_proto_map[256] = {
24 		[IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
25 		[IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
26 		[IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
27 		[IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
28 		[IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
29 		[IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
30 	};
31 
32 	return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
33 }
34 
35 /* get l3 packet type from ip version and header length */
36 static uint32_t
ptype_l3_ip(uint8_t ipv_ihl)37 ptype_l3_ip(uint8_t ipv_ihl)
38 {
39 	static const uint32_t ptype_l3_ip_proto_map[256] = {
40 		[0x45] = RTE_PTYPE_L3_IPV4,
41 		[0x46] = RTE_PTYPE_L3_IPV4_EXT,
42 		[0x47] = RTE_PTYPE_L3_IPV4_EXT,
43 		[0x48] = RTE_PTYPE_L3_IPV4_EXT,
44 		[0x49] = RTE_PTYPE_L3_IPV4_EXT,
45 		[0x4A] = RTE_PTYPE_L3_IPV4_EXT,
46 		[0x4B] = RTE_PTYPE_L3_IPV4_EXT,
47 		[0x4C] = RTE_PTYPE_L3_IPV4_EXT,
48 		[0x4D] = RTE_PTYPE_L3_IPV4_EXT,
49 		[0x4E] = RTE_PTYPE_L3_IPV4_EXT,
50 		[0x4F] = RTE_PTYPE_L3_IPV4_EXT,
51 	};
52 
53 	return ptype_l3_ip_proto_map[ipv_ihl];
54 }
55 
56 /* get l4 packet type from proto */
57 static uint32_t
ptype_l4(uint8_t proto)58 ptype_l4(uint8_t proto)
59 {
60 	static const uint32_t ptype_l4_proto[256] = {
61 		[IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
62 		[IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
63 		[IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
64 	};
65 
66 	return ptype_l4_proto[proto];
67 }
68 
69 /* get inner l3 packet type from ip6 next protocol */
70 static uint32_t
ptype_inner_l3_ip6(uint8_t ip6_proto)71 ptype_inner_l3_ip6(uint8_t ip6_proto)
72 {
73 	static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
74 		[IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
75 			RTE_PTYPE_INNER_L3_IPV6,
76 		[IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
77 			RTE_PTYPE_INNER_L3_IPV6,
78 		[IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
79 			RTE_PTYPE_INNER_L3_IPV6,
80 		[IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
81 			RTE_PTYPE_INNER_L3_IPV6,
82 		[IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
83 			RTE_PTYPE_INNER_L3_IPV6,
84 		[IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
85 			RTE_PTYPE_INNER_L3_IPV6,
86 	};
87 
88 	return RTE_PTYPE_INNER_L3_IPV6 +
89 		ptype_inner_ip6_ext_proto_map[ip6_proto];
90 }
91 
92 /* get inner l3 packet type from ip version and header length */
93 static uint32_t
ptype_inner_l3_ip(uint8_t ipv_ihl)94 ptype_inner_l3_ip(uint8_t ipv_ihl)
95 {
96 	static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
97 		[0x45] = RTE_PTYPE_INNER_L3_IPV4,
98 		[0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
99 		[0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
100 		[0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
101 		[0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
102 		[0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
103 		[0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
104 		[0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
105 		[0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
106 		[0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
107 		[0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
108 	};
109 
110 	return ptype_inner_l3_ip_proto_map[ipv_ihl];
111 }
112 
113 /* get inner l4 packet type from proto */
114 static uint32_t
ptype_inner_l4(uint8_t proto)115 ptype_inner_l4(uint8_t proto)
116 {
117 	static const uint32_t ptype_inner_l4_proto[256] = {
118 		[IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
119 		[IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
120 		[IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
121 	};
122 
123 	return ptype_inner_l4_proto[proto];
124 }
125 
126 /* get the tunnel packet type if any, update proto and off. */
127 static uint32_t
ptype_tunnel(uint16_t * proto,const struct rte_mbuf * m,uint32_t * off)128 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
129 	uint32_t *off)
130 {
131 	switch (*proto) {
132 	case IPPROTO_GRE: {
133 		static const uint8_t opt_len[16] = {
134 			[0x0] = 4,
135 			[0x1] = 8,
136 			[0x2] = 8,
137 			[0x8] = 8,
138 			[0x3] = 12,
139 			[0x9] = 12,
140 			[0xa] = 12,
141 			[0xb] = 16,
142 		};
143 		const struct rte_gre_hdr *gh;
144 		struct rte_gre_hdr gh_copy;
145 		uint16_t flags;
146 
147 		gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
148 		if (unlikely(gh == NULL))
149 			return 0;
150 
151 		flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
152 		flags >>= 12;
153 		if (opt_len[flags] == 0)
154 			return 0;
155 
156 		*off += opt_len[flags];
157 		*proto = gh->proto;
158 		if (*proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB))
159 			return RTE_PTYPE_TUNNEL_NVGRE;
160 		else
161 			return RTE_PTYPE_TUNNEL_GRE;
162 	}
163 	case IPPROTO_IPIP:
164 		*proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
165 		return RTE_PTYPE_TUNNEL_IP;
166 	case IPPROTO_IPV6:
167 		*proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
168 		return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
169 	default:
170 		return 0;
171 	}
172 }
173 
174 /* parse ipv6 extended headers, update offset and return next proto */
175 int
rte_net_skip_ip6_ext(uint16_t proto,const struct rte_mbuf * m,uint32_t * off,int * frag)176 rte_net_skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
177 	int *frag)
178 {
179 	struct ext_hdr {
180 		uint8_t next_hdr;
181 		uint8_t len;
182 	};
183 	const struct ext_hdr *xh;
184 	struct ext_hdr xh_copy;
185 	unsigned int i;
186 
187 	*frag = 0;
188 
189 #define MAX_EXT_HDRS 5
190 	for (i = 0; i < MAX_EXT_HDRS; i++) {
191 		switch (proto) {
192 		case IPPROTO_HOPOPTS:
193 		case IPPROTO_ROUTING:
194 		case IPPROTO_DSTOPTS:
195 			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
196 				&xh_copy);
197 			if (xh == NULL)
198 				return -1;
199 			*off += (xh->len + 1) * 8;
200 			proto = xh->next_hdr;
201 			break;
202 		case IPPROTO_FRAGMENT:
203 			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
204 				&xh_copy);
205 			if (xh == NULL)
206 				return -1;
207 			*off += 8;
208 			proto = xh->next_hdr;
209 			*frag = 1;
210 			return proto; /* this is always the last ext hdr */
211 		case IPPROTO_NONE:
212 			return 0;
213 		default:
214 			return proto;
215 		}
216 	}
217 	return -1;
218 }
219 
220 /* parse mbuf data to get packet type */
rte_net_get_ptype(const struct rte_mbuf * m,struct rte_net_hdr_lens * hdr_lens,uint32_t layers)221 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
222 	struct rte_net_hdr_lens *hdr_lens, uint32_t layers)
223 {
224 	struct rte_net_hdr_lens local_hdr_lens;
225 	const struct rte_ether_hdr *eh;
226 	struct rte_ether_hdr eh_copy;
227 	uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
228 	uint32_t off = 0;
229 	uint16_t proto;
230 	int ret;
231 
232 	if (hdr_lens == NULL)
233 		hdr_lens = &local_hdr_lens;
234 
235 	eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
236 	if (unlikely(eh == NULL))
237 		return 0;
238 	proto = eh->ether_type;
239 	off = sizeof(*eh);
240 	hdr_lens->l2_len = off;
241 
242 	if ((layers & RTE_PTYPE_L2_MASK) == 0)
243 		return 0;
244 
245 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))
246 		goto l3; /* fast path if packet is IPv4 */
247 
248 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN)) {
249 		const struct rte_vlan_hdr *vh;
250 		struct rte_vlan_hdr vh_copy;
251 
252 		pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
253 		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
254 		if (unlikely(vh == NULL))
255 			return pkt_type;
256 		off += sizeof(*vh);
257 		hdr_lens->l2_len += sizeof(*vh);
258 		proto = vh->eth_proto;
259 	} else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
260 		const struct rte_vlan_hdr *vh;
261 		struct rte_vlan_hdr vh_copy;
262 
263 		pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
264 		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
265 			&vh_copy);
266 		if (unlikely(vh == NULL))
267 			return pkt_type;
268 		off += 2 * sizeof(*vh);
269 		hdr_lens->l2_len += 2 * sizeof(*vh);
270 		proto = vh->eth_proto;
271 	} else if ((proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) ||
272 		(proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLSM))) {
273 		unsigned int i;
274 		const struct rte_mpls_hdr *mh;
275 		struct rte_mpls_hdr mh_copy;
276 
277 #define MAX_MPLS_HDR 5
278 		for (i = 0; i < MAX_MPLS_HDR; i++) {
279 			mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
280 				sizeof(*mh), &mh_copy);
281 			if (unlikely(mh == NULL))
282 				return pkt_type;
283 		}
284 		if (i == MAX_MPLS_HDR)
285 			return pkt_type;
286 		pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
287 		hdr_lens->l2_len += (sizeof(*mh) * i);
288 		return pkt_type;
289 	}
290 
291 l3:
292 	if ((layers & RTE_PTYPE_L3_MASK) == 0)
293 		return pkt_type;
294 
295 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
296 		const struct rte_ipv4_hdr *ip4h;
297 		struct rte_ipv4_hdr ip4h_copy;
298 
299 		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
300 		if (unlikely(ip4h == NULL))
301 			return pkt_type;
302 
303 		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
304 		hdr_lens->l3_len = rte_ipv4_hdr_len(ip4h);
305 		off += hdr_lens->l3_len;
306 
307 		if ((layers & RTE_PTYPE_L4_MASK) == 0)
308 			return pkt_type;
309 
310 		if (ip4h->fragment_offset & rte_cpu_to_be_16(
311 				RTE_IPV4_HDR_OFFSET_MASK | RTE_IPV4_HDR_MF_FLAG)) {
312 			pkt_type |= RTE_PTYPE_L4_FRAG;
313 			hdr_lens->l4_len = 0;
314 			return pkt_type;
315 		}
316 		proto = ip4h->next_proto_id;
317 		pkt_type |= ptype_l4(proto);
318 	} else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
319 		const struct rte_ipv6_hdr *ip6h;
320 		struct rte_ipv6_hdr ip6h_copy;
321 		int frag = 0;
322 
323 		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
324 		if (unlikely(ip6h == NULL))
325 			return pkt_type;
326 
327 		proto = ip6h->proto;
328 		hdr_lens->l3_len = sizeof(*ip6h);
329 		off += hdr_lens->l3_len;
330 		pkt_type |= ptype_l3_ip6(proto);
331 		if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
332 			ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
333 			if (ret < 0)
334 				return pkt_type;
335 			proto = ret;
336 			hdr_lens->l3_len = off - hdr_lens->l2_len;
337 		}
338 		if (proto == 0)
339 			return pkt_type;
340 
341 		if ((layers & RTE_PTYPE_L4_MASK) == 0)
342 			return pkt_type;
343 
344 		if (frag) {
345 			pkt_type |= RTE_PTYPE_L4_FRAG;
346 			hdr_lens->l4_len = 0;
347 			return pkt_type;
348 		}
349 		pkt_type |= ptype_l4(proto);
350 	}
351 
352 	if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
353 		hdr_lens->l4_len = sizeof(struct rte_udp_hdr);
354 		return pkt_type;
355 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
356 		const struct rte_tcp_hdr *th;
357 		struct rte_tcp_hdr th_copy;
358 
359 		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
360 		if (unlikely(th == NULL))
361 			return pkt_type & (RTE_PTYPE_L2_MASK |
362 				RTE_PTYPE_L3_MASK);
363 		hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
364 		return pkt_type;
365 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
366 		hdr_lens->l4_len = sizeof(struct rte_sctp_hdr);
367 		return pkt_type;
368 	} else {
369 		uint32_t prev_off = off;
370 
371 		hdr_lens->l4_len = 0;
372 
373 		if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0)
374 			return pkt_type;
375 
376 		pkt_type |= ptype_tunnel(&proto, m, &off);
377 		hdr_lens->tunnel_len = off - prev_off;
378 	}
379 
380 	/* same job for inner header: we need to duplicate the code
381 	 * because the packet types do not have the same value.
382 	 */
383 	if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0)
384 		return pkt_type;
385 
386 	hdr_lens->inner_l2_len = 0;
387 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB)) {
388 		eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
389 		if (unlikely(eh == NULL))
390 			return pkt_type;
391 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER;
392 		proto = eh->ether_type;
393 		off += sizeof(*eh);
394 		hdr_lens->inner_l2_len = sizeof(*eh);
395 	}
396 
397 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN)) {
398 		const struct rte_vlan_hdr *vh;
399 		struct rte_vlan_hdr vh_copy;
400 
401 		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
402 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN;
403 		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
404 		if (unlikely(vh == NULL))
405 			return pkt_type;
406 		off += sizeof(*vh);
407 		hdr_lens->inner_l2_len += sizeof(*vh);
408 		proto = vh->eth_proto;
409 	} else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
410 		const struct rte_vlan_hdr *vh;
411 		struct rte_vlan_hdr vh_copy;
412 
413 		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
414 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ;
415 		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
416 			&vh_copy);
417 		if (unlikely(vh == NULL))
418 			return pkt_type;
419 		off += 2 * sizeof(*vh);
420 		hdr_lens->inner_l2_len += 2 * sizeof(*vh);
421 		proto = vh->eth_proto;
422 	}
423 
424 	if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
425 		return pkt_type;
426 
427 	if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
428 		const struct rte_ipv4_hdr *ip4h;
429 		struct rte_ipv4_hdr ip4h_copy;
430 
431 		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
432 		if (unlikely(ip4h == NULL))
433 			return pkt_type;
434 
435 		pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
436 		hdr_lens->inner_l3_len = rte_ipv4_hdr_len(ip4h);
437 		off += hdr_lens->inner_l3_len;
438 
439 		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
440 			return pkt_type;
441 		if (ip4h->fragment_offset &
442 				rte_cpu_to_be_16(RTE_IPV4_HDR_OFFSET_MASK |
443 					RTE_IPV4_HDR_MF_FLAG)) {
444 			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
445 			hdr_lens->inner_l4_len = 0;
446 			return pkt_type;
447 		}
448 		proto = ip4h->next_proto_id;
449 		pkt_type |= ptype_inner_l4(proto);
450 	} else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
451 		const struct rte_ipv6_hdr *ip6h;
452 		struct rte_ipv6_hdr ip6h_copy;
453 		int frag = 0;
454 
455 		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
456 		if (unlikely(ip6h == NULL))
457 			return pkt_type;
458 
459 		proto = ip6h->proto;
460 		hdr_lens->inner_l3_len = sizeof(*ip6h);
461 		off += hdr_lens->inner_l3_len;
462 		pkt_type |= ptype_inner_l3_ip6(proto);
463 		if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
464 				RTE_PTYPE_INNER_L3_IPV6_EXT) {
465 			uint32_t prev_off;
466 
467 			prev_off = off;
468 			ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
469 			if (ret < 0)
470 				return pkt_type;
471 			proto = ret;
472 			hdr_lens->inner_l3_len += off - prev_off;
473 		}
474 		if (proto == 0)
475 			return pkt_type;
476 
477 		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
478 			return pkt_type;
479 
480 		if (frag) {
481 			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
482 			hdr_lens->inner_l4_len = 0;
483 			return pkt_type;
484 		}
485 		pkt_type |= ptype_inner_l4(proto);
486 	}
487 
488 	if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
489 		hdr_lens->inner_l4_len = sizeof(struct rte_udp_hdr);
490 	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
491 			RTE_PTYPE_INNER_L4_TCP) {
492 		const struct rte_tcp_hdr *th;
493 		struct rte_tcp_hdr th_copy;
494 
495 		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
496 		if (unlikely(th == NULL))
497 			return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
498 				RTE_PTYPE_INNER_L3_MASK);
499 		hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
500 	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
501 			RTE_PTYPE_INNER_L4_SCTP) {
502 		hdr_lens->inner_l4_len = sizeof(struct rte_sctp_hdr);
503 	} else {
504 		hdr_lens->inner_l4_len = 0;
505 	}
506 
507 	return pkt_type;
508 }
509