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