xref: /f-stack/dpdk/lib/librte_net/rte_net.c (revision 8850115b)
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
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
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
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
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
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
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
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 gre_hdr *gh;
144 		struct 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(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(ETHER_TYPE_IPv4);
165 		return RTE_PTYPE_TUNNEL_IP;
166 	case IPPROTO_IPV6:
167 		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
168 		return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
169 	default:
170 		return 0;
171 	}
172 }
173 
174 /* get the ipv4 header length */
175 static uint8_t
176 ip4_hlen(const struct ipv4_hdr *hdr)
177 {
178 	return (hdr->version_ihl & 0xf) * 4;
179 }
180 
181 /* parse ipv6 extended headers, update offset and return next proto */
182 int __rte_experimental
183 rte_net_skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
184 	int *frag)
185 {
186 	struct ext_hdr {
187 		uint8_t next_hdr;
188 		uint8_t len;
189 	};
190 	const struct ext_hdr *xh;
191 	struct ext_hdr xh_copy;
192 	unsigned int i;
193 
194 	*frag = 0;
195 
196 #define MAX_EXT_HDRS 5
197 	for (i = 0; i < MAX_EXT_HDRS; i++) {
198 		switch (proto) {
199 		case IPPROTO_HOPOPTS:
200 		case IPPROTO_ROUTING:
201 		case IPPROTO_DSTOPTS:
202 			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
203 				&xh_copy);
204 			if (xh == NULL)
205 				return -1;
206 			*off += (xh->len + 1) * 8;
207 			proto = xh->next_hdr;
208 			break;
209 		case IPPROTO_FRAGMENT:
210 			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
211 				&xh_copy);
212 			if (xh == NULL)
213 				return -1;
214 			*off += 8;
215 			proto = xh->next_hdr;
216 			*frag = 1;
217 			return proto; /* this is always the last ext hdr */
218 		case IPPROTO_NONE:
219 			return 0;
220 		default:
221 			return proto;
222 		}
223 	}
224 	return -1;
225 }
226 
227 /* parse mbuf data to get packet type */
228 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
229 	struct rte_net_hdr_lens *hdr_lens, uint32_t layers)
230 {
231 	struct rte_net_hdr_lens local_hdr_lens;
232 	const struct ether_hdr *eh;
233 	struct ether_hdr eh_copy;
234 	uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
235 	uint32_t off = 0;
236 	uint16_t proto;
237 	int ret;
238 
239 	if (hdr_lens == NULL)
240 		hdr_lens = &local_hdr_lens;
241 
242 	eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
243 	if (unlikely(eh == NULL))
244 		return 0;
245 	proto = eh->ether_type;
246 	off = sizeof(*eh);
247 	hdr_lens->l2_len = off;
248 
249 	if ((layers & RTE_PTYPE_L2_MASK) == 0)
250 		return 0;
251 
252 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
253 		goto l3; /* fast path if packet is IPv4 */
254 
255 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
256 		const struct vlan_hdr *vh;
257 		struct vlan_hdr vh_copy;
258 
259 		pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
260 		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
261 		if (unlikely(vh == NULL))
262 			return pkt_type;
263 		off += sizeof(*vh);
264 		hdr_lens->l2_len += sizeof(*vh);
265 		proto = vh->eth_proto;
266 	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
267 		const struct vlan_hdr *vh;
268 		struct vlan_hdr vh_copy;
269 
270 		pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
271 		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
272 			&vh_copy);
273 		if (unlikely(vh == NULL))
274 			return pkt_type;
275 		off += 2 * sizeof(*vh);
276 		hdr_lens->l2_len += 2 * sizeof(*vh);
277 		proto = vh->eth_proto;
278 	} else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
279 		(proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
280 		unsigned int i;
281 		const struct mpls_hdr *mh;
282 		struct mpls_hdr mh_copy;
283 
284 #define MAX_MPLS_HDR 5
285 		for (i = 0; i < MAX_MPLS_HDR; i++) {
286 			mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
287 				sizeof(*mh), &mh_copy);
288 			if (unlikely(mh == NULL))
289 				return pkt_type;
290 		}
291 		if (i == MAX_MPLS_HDR)
292 			return pkt_type;
293 		pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
294 		hdr_lens->l2_len += (sizeof(*mh) * i);
295 		return pkt_type;
296 	}
297 
298 l3:
299 	if ((layers & RTE_PTYPE_L3_MASK) == 0)
300 		return pkt_type;
301 
302 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
303 		const struct ipv4_hdr *ip4h;
304 		struct ipv4_hdr ip4h_copy;
305 
306 		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
307 		if (unlikely(ip4h == NULL))
308 			return pkt_type;
309 
310 		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
311 		hdr_lens->l3_len = ip4_hlen(ip4h);
312 		off += hdr_lens->l3_len;
313 
314 		if ((layers & RTE_PTYPE_L4_MASK) == 0)
315 			return pkt_type;
316 
317 		if (ip4h->fragment_offset & rte_cpu_to_be_16(
318 				IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
319 			pkt_type |= RTE_PTYPE_L4_FRAG;
320 			hdr_lens->l4_len = 0;
321 			return pkt_type;
322 		}
323 		proto = ip4h->next_proto_id;
324 		pkt_type |= ptype_l4(proto);
325 	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
326 		const struct ipv6_hdr *ip6h;
327 		struct ipv6_hdr ip6h_copy;
328 		int frag = 0;
329 
330 		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
331 		if (unlikely(ip6h == NULL))
332 			return pkt_type;
333 
334 		proto = ip6h->proto;
335 		hdr_lens->l3_len = sizeof(*ip6h);
336 		off += hdr_lens->l3_len;
337 		pkt_type |= ptype_l3_ip6(proto);
338 		if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
339 			ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
340 			if (ret < 0)
341 				return pkt_type;
342 			proto = ret;
343 			hdr_lens->l3_len = off - hdr_lens->l2_len;
344 		}
345 		if (proto == 0)
346 			return pkt_type;
347 
348 		if ((layers & RTE_PTYPE_L4_MASK) == 0)
349 			return pkt_type;
350 
351 		if (frag) {
352 			pkt_type |= RTE_PTYPE_L4_FRAG;
353 			hdr_lens->l4_len = 0;
354 			return pkt_type;
355 		}
356 		pkt_type |= ptype_l4(proto);
357 	}
358 
359 	if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
360 		hdr_lens->l4_len = sizeof(struct udp_hdr);
361 		return pkt_type;
362 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
363 		const struct tcp_hdr *th;
364 		struct tcp_hdr th_copy;
365 
366 		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
367 		if (unlikely(th == NULL))
368 			return pkt_type & (RTE_PTYPE_L2_MASK |
369 				RTE_PTYPE_L3_MASK);
370 		hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
371 		return pkt_type;
372 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
373 		hdr_lens->l4_len = sizeof(struct sctp_hdr);
374 		return pkt_type;
375 	} else {
376 		uint32_t prev_off = off;
377 
378 		hdr_lens->l4_len = 0;
379 
380 		if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0)
381 			return pkt_type;
382 
383 		pkt_type |= ptype_tunnel(&proto, m, &off);
384 		hdr_lens->tunnel_len = off - prev_off;
385 	}
386 
387 	/* same job for inner header: we need to duplicate the code
388 	 * because the packet types do not have the same value.
389 	 */
390 	if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0)
391 		return pkt_type;
392 
393 	hdr_lens->inner_l2_len = 0;
394 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
395 		eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
396 		if (unlikely(eh == NULL))
397 			return pkt_type;
398 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER;
399 		proto = eh->ether_type;
400 		off += sizeof(*eh);
401 		hdr_lens->inner_l2_len = sizeof(*eh);
402 	}
403 
404 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
405 		const struct vlan_hdr *vh;
406 		struct vlan_hdr vh_copy;
407 
408 		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
409 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN;
410 		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
411 		if (unlikely(vh == NULL))
412 			return pkt_type;
413 		off += sizeof(*vh);
414 		hdr_lens->inner_l2_len += sizeof(*vh);
415 		proto = vh->eth_proto;
416 	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
417 		const struct vlan_hdr *vh;
418 		struct vlan_hdr vh_copy;
419 
420 		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
421 		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ;
422 		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
423 			&vh_copy);
424 		if (unlikely(vh == NULL))
425 			return pkt_type;
426 		off += 2 * sizeof(*vh);
427 		hdr_lens->inner_l2_len += 2 * sizeof(*vh);
428 		proto = vh->eth_proto;
429 	}
430 
431 	if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
432 		return pkt_type;
433 
434 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
435 		const struct ipv4_hdr *ip4h;
436 		struct ipv4_hdr ip4h_copy;
437 
438 		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
439 		if (unlikely(ip4h == NULL))
440 			return pkt_type;
441 
442 		pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
443 		hdr_lens->inner_l3_len = ip4_hlen(ip4h);
444 		off += hdr_lens->inner_l3_len;
445 
446 		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
447 			return pkt_type;
448 		if (ip4h->fragment_offset &
449 				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
450 					IPV4_HDR_MF_FLAG)) {
451 			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
452 			hdr_lens->inner_l4_len = 0;
453 			return pkt_type;
454 		}
455 		proto = ip4h->next_proto_id;
456 		pkt_type |= ptype_inner_l4(proto);
457 	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
458 		const struct ipv6_hdr *ip6h;
459 		struct ipv6_hdr ip6h_copy;
460 		int frag = 0;
461 
462 		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
463 		if (unlikely(ip6h == NULL))
464 			return pkt_type;
465 
466 		proto = ip6h->proto;
467 		hdr_lens->inner_l3_len = sizeof(*ip6h);
468 		off += hdr_lens->inner_l3_len;
469 		pkt_type |= ptype_inner_l3_ip6(proto);
470 		if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
471 				RTE_PTYPE_INNER_L3_IPV6_EXT) {
472 			uint32_t prev_off;
473 
474 			prev_off = off;
475 			ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
476 			if (ret < 0)
477 				return pkt_type;
478 			proto = ret;
479 			hdr_lens->inner_l3_len += off - prev_off;
480 		}
481 		if (proto == 0)
482 			return pkt_type;
483 
484 		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
485 			return pkt_type;
486 
487 		if (frag) {
488 			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
489 			hdr_lens->inner_l4_len = 0;
490 			return pkt_type;
491 		}
492 		pkt_type |= ptype_inner_l4(proto);
493 	}
494 
495 	if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
496 		hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
497 	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
498 			RTE_PTYPE_INNER_L4_TCP) {
499 		const struct tcp_hdr *th;
500 		struct tcp_hdr th_copy;
501 
502 		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
503 		if (unlikely(th == NULL))
504 			return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
505 				RTE_PTYPE_INNER_L3_MASK);
506 		hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
507 	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
508 			RTE_PTYPE_INNER_L4_SCTP) {
509 		hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
510 	} else {
511 		hdr_lens->inner_l4_len = 0;
512 	}
513 
514 	return pkt_type;
515 }
516