1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
8 #include <rte_mbuf_ptype.h>
9 #include <rte_byteorder.h>
10 #include <rte_ether.h>
18 /* get l3 packet type from ip6 next protocol */
20 ptype_l3_ip6(uint8_t ip6_proto)
22 static const uint32_t ip6_ext_proto_map[256] = {
23 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
24 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
25 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
26 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
27 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
28 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
31 return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
34 /* get l3 packet type from ip version and header length */
36 ptype_l3_ip(uint8_t ipv_ihl)
38 static const uint32_t ptype_l3_ip_proto_map[256] = {
39 [0x45] = RTE_PTYPE_L3_IPV4,
40 [0x46] = RTE_PTYPE_L3_IPV4_EXT,
41 [0x47] = RTE_PTYPE_L3_IPV4_EXT,
42 [0x48] = RTE_PTYPE_L3_IPV4_EXT,
43 [0x49] = RTE_PTYPE_L3_IPV4_EXT,
44 [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
45 [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
46 [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
47 [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
48 [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
49 [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
52 return ptype_l3_ip_proto_map[ipv_ihl];
55 /* get l4 packet type from proto */
57 ptype_l4(uint8_t proto)
59 static const uint32_t ptype_l4_proto[256] = {
60 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
61 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
62 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
65 return ptype_l4_proto[proto];
68 /* get inner l3 packet type from ip6 next protocol */
70 ptype_inner_l3_ip6(uint8_t ip6_proto)
72 static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
73 [IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
74 RTE_PTYPE_INNER_L3_IPV6,
75 [IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
76 RTE_PTYPE_INNER_L3_IPV6,
77 [IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
78 RTE_PTYPE_INNER_L3_IPV6,
79 [IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
80 RTE_PTYPE_INNER_L3_IPV6,
81 [IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
82 RTE_PTYPE_INNER_L3_IPV6,
83 [IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
84 RTE_PTYPE_INNER_L3_IPV6,
87 return RTE_PTYPE_INNER_L3_IPV6 +
88 ptype_inner_ip6_ext_proto_map[ip6_proto];
91 /* get inner l3 packet type from ip version and header length */
93 ptype_inner_l3_ip(uint8_t ipv_ihl)
95 static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
96 [0x45] = RTE_PTYPE_INNER_L3_IPV4,
97 [0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
98 [0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
99 [0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
100 [0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
101 [0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
102 [0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
103 [0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
104 [0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
105 [0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
106 [0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
109 return ptype_inner_l3_ip_proto_map[ipv_ihl];
112 /* get inner l4 packet type from proto */
114 ptype_inner_l4(uint8_t proto)
116 static const uint32_t ptype_inner_l4_proto[256] = {
117 [IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
118 [IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
119 [IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
122 return ptype_inner_l4_proto[proto];
125 /* get the tunnel packet type if any, update proto and off. */
127 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
132 static const uint8_t opt_len[16] = {
142 const struct gre_hdr *gh;
143 struct gre_hdr gh_copy;
146 gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
147 if (unlikely(gh == NULL))
150 flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
152 if (opt_len[flags] == 0)
155 *off += opt_len[flags];
157 if (*proto == rte_cpu_to_be_16(ETHER_TYPE_TEB))
158 return RTE_PTYPE_TUNNEL_NVGRE;
160 return RTE_PTYPE_TUNNEL_GRE;
163 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
164 return RTE_PTYPE_TUNNEL_IP;
166 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
167 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
173 /* get the ipv4 header length */
175 ip4_hlen(const struct ipv4_hdr *hdr)
177 return (hdr->version_ihl & 0xf) * 4;
180 /* parse ipv6 extended headers, update offset and return next proto */
182 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
189 const struct ext_hdr *xh;
190 struct ext_hdr xh_copy;
195 #define MAX_EXT_HDRS 5
196 for (i = 0; i < MAX_EXT_HDRS; i++) {
198 case IPPROTO_HOPOPTS:
199 case IPPROTO_ROUTING:
200 case IPPROTO_DSTOPTS:
201 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
205 *off += (xh->len + 1) * 8;
206 proto = xh->next_hdr;
208 case IPPROTO_FRAGMENT:
209 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
214 proto = xh->next_hdr;
216 return proto; /* this is always the last ext hdr */
226 /* parse mbuf data to get packet type */
227 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
228 struct rte_net_hdr_lens *hdr_lens, uint32_t layers)
230 struct rte_net_hdr_lens local_hdr_lens;
231 const struct ether_hdr *eh;
232 struct ether_hdr eh_copy;
233 uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
237 if (hdr_lens == NULL)
238 hdr_lens = &local_hdr_lens;
240 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
241 if (unlikely(eh == NULL))
243 proto = eh->ether_type;
245 hdr_lens->l2_len = off;
247 if ((layers & RTE_PTYPE_L2_MASK) == 0)
250 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
251 goto l3; /* fast path if packet is IPv4 */
253 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
254 const struct vlan_hdr *vh;
255 struct vlan_hdr vh_copy;
257 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
258 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
259 if (unlikely(vh == NULL))
262 hdr_lens->l2_len += sizeof(*vh);
263 proto = vh->eth_proto;
264 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
265 const struct vlan_hdr *vh;
266 struct vlan_hdr vh_copy;
268 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
269 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
271 if (unlikely(vh == NULL))
273 off += 2 * sizeof(*vh);
274 hdr_lens->l2_len += 2 * sizeof(*vh);
275 proto = vh->eth_proto;
279 if ((layers & RTE_PTYPE_L3_MASK) == 0)
282 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
283 const struct ipv4_hdr *ip4h;
284 struct ipv4_hdr ip4h_copy;
286 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
287 if (unlikely(ip4h == NULL))
290 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
291 hdr_lens->l3_len = ip4_hlen(ip4h);
292 off += hdr_lens->l3_len;
294 if ((layers & RTE_PTYPE_L4_MASK) == 0)
297 if (ip4h->fragment_offset & rte_cpu_to_be_16(
298 IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
299 pkt_type |= RTE_PTYPE_L4_FRAG;
300 hdr_lens->l4_len = 0;
303 proto = ip4h->next_proto_id;
304 pkt_type |= ptype_l4(proto);
305 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
306 const struct ipv6_hdr *ip6h;
307 struct ipv6_hdr ip6h_copy;
310 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
311 if (unlikely(ip6h == NULL))
315 hdr_lens->l3_len = sizeof(*ip6h);
316 off += hdr_lens->l3_len;
317 pkt_type |= ptype_l3_ip6(proto);
318 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
319 proto = skip_ip6_ext(proto, m, &off, &frag);
320 hdr_lens->l3_len = off - hdr_lens->l2_len;
325 if ((layers & RTE_PTYPE_L4_MASK) == 0)
329 pkt_type |= RTE_PTYPE_L4_FRAG;
330 hdr_lens->l4_len = 0;
333 pkt_type |= ptype_l4(proto);
336 if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
337 hdr_lens->l4_len = sizeof(struct udp_hdr);
339 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
340 const struct tcp_hdr *th;
341 struct tcp_hdr th_copy;
343 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
344 if (unlikely(th == NULL))
345 return pkt_type & (RTE_PTYPE_L2_MASK |
347 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
349 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
350 hdr_lens->l4_len = sizeof(struct sctp_hdr);
353 uint32_t prev_off = off;
355 hdr_lens->l4_len = 0;
357 if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0)
360 pkt_type |= ptype_tunnel(&proto, m, &off);
361 hdr_lens->tunnel_len = off - prev_off;
364 /* same job for inner header: we need to duplicate the code
365 * because the packet types do not have the same value.
367 if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0)
370 hdr_lens->inner_l2_len = 0;
371 if (proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
372 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
373 if (unlikely(eh == NULL))
375 pkt_type |= RTE_PTYPE_INNER_L2_ETHER;
376 proto = eh->ether_type;
378 hdr_lens->inner_l2_len = sizeof(*eh);
381 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
382 const struct vlan_hdr *vh;
383 struct vlan_hdr vh_copy;
385 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
386 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN;
387 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
388 if (unlikely(vh == NULL))
391 hdr_lens->inner_l2_len += sizeof(*vh);
392 proto = vh->eth_proto;
393 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
394 const struct vlan_hdr *vh;
395 struct vlan_hdr vh_copy;
397 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
398 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ;
399 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
401 if (unlikely(vh == NULL))
403 off += 2 * sizeof(*vh);
404 hdr_lens->inner_l2_len += 2 * sizeof(*vh);
405 proto = vh->eth_proto;
408 if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
411 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
412 const struct ipv4_hdr *ip4h;
413 struct ipv4_hdr ip4h_copy;
415 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
416 if (unlikely(ip4h == NULL))
419 pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
420 hdr_lens->inner_l3_len = ip4_hlen(ip4h);
421 off += hdr_lens->inner_l3_len;
423 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
425 if (ip4h->fragment_offset &
426 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
428 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
429 hdr_lens->inner_l4_len = 0;
432 proto = ip4h->next_proto_id;
433 pkt_type |= ptype_inner_l4(proto);
434 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
435 const struct ipv6_hdr *ip6h;
436 struct ipv6_hdr ip6h_copy;
439 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
440 if (unlikely(ip6h == NULL))
444 hdr_lens->inner_l3_len = sizeof(*ip6h);
445 off += hdr_lens->inner_l3_len;
446 pkt_type |= ptype_inner_l3_ip6(proto);
447 if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
448 RTE_PTYPE_INNER_L3_IPV6_EXT) {
452 proto = skip_ip6_ext(proto, m, &off, &frag);
453 hdr_lens->inner_l3_len += off - prev_off;
458 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
462 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
463 hdr_lens->inner_l4_len = 0;
466 pkt_type |= ptype_inner_l4(proto);
469 if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
470 hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
471 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
472 RTE_PTYPE_INNER_L4_TCP) {
473 const struct tcp_hdr *th;
474 struct tcp_hdr th_copy;
476 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
477 if (unlikely(th == NULL))
478 return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
479 RTE_PTYPE_INNER_L3_MASK);
480 hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
481 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
482 RTE_PTYPE_INNER_L4_SCTP) {
483 hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
485 hdr_lens->inner_l4_len = 0;