4 * Copyright 2016 6WIND S.A.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <rte_mbuf_ptype.h>
38 #include <rte_byteorder.h>
39 #include <rte_ether.h>
47 /* get l3 packet type from ip6 next protocol */
49 ptype_l3_ip6(uint8_t ip6_proto)
51 static const uint32_t ip6_ext_proto_map[256] = {
52 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
53 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
54 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
55 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
56 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
57 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
60 return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
63 /* get l3 packet type from ip version and header length */
65 ptype_l3_ip(uint8_t ipv_ihl)
67 static const uint32_t ptype_l3_ip_proto_map[256] = {
68 [0x45] = RTE_PTYPE_L3_IPV4,
69 [0x46] = RTE_PTYPE_L3_IPV4_EXT,
70 [0x47] = RTE_PTYPE_L3_IPV4_EXT,
71 [0x48] = RTE_PTYPE_L3_IPV4_EXT,
72 [0x49] = RTE_PTYPE_L3_IPV4_EXT,
73 [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
74 [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
75 [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
76 [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
77 [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
78 [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
81 return ptype_l3_ip_proto_map[ipv_ihl];
84 /* get l4 packet type from proto */
86 ptype_l4(uint8_t proto)
88 static const uint32_t ptype_l4_proto[256] = {
89 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
90 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
91 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
94 return ptype_l4_proto[proto];
97 /* get inner l3 packet type from ip6 next protocol */
99 ptype_inner_l3_ip6(uint8_t ip6_proto)
101 static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
102 [IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
103 RTE_PTYPE_INNER_L3_IPV6,
104 [IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
105 RTE_PTYPE_INNER_L3_IPV6,
106 [IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
107 RTE_PTYPE_INNER_L3_IPV6,
108 [IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
109 RTE_PTYPE_INNER_L3_IPV6,
110 [IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
111 RTE_PTYPE_INNER_L3_IPV6,
112 [IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
113 RTE_PTYPE_INNER_L3_IPV6,
116 return RTE_PTYPE_INNER_L3_IPV6 +
117 ptype_inner_ip6_ext_proto_map[ip6_proto];
120 /* get inner l3 packet type from ip version and header length */
122 ptype_inner_l3_ip(uint8_t ipv_ihl)
124 static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
125 [0x45] = RTE_PTYPE_INNER_L3_IPV4,
126 [0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
127 [0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
128 [0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
129 [0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
130 [0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
131 [0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
132 [0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
133 [0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
134 [0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
135 [0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
138 return ptype_inner_l3_ip_proto_map[ipv_ihl];
141 /* get inner l4 packet type from proto */
143 ptype_inner_l4(uint8_t proto)
145 static const uint32_t ptype_inner_l4_proto[256] = {
146 [IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
147 [IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
148 [IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
151 return ptype_inner_l4_proto[proto];
154 /* get the tunnel packet type if any, update proto and off. */
156 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
161 static const uint8_t opt_len[16] = {
171 const struct gre_hdr *gh;
172 struct gre_hdr gh_copy;
175 gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
176 if (unlikely(gh == NULL))
179 flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
181 if (opt_len[flags] == 0)
184 *off += opt_len[flags];
186 return RTE_PTYPE_TUNNEL_GRE;
189 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
190 return RTE_PTYPE_TUNNEL_IP;
192 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
193 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
199 /* get the ipv4 header length */
201 ip4_hlen(const struct ipv4_hdr *hdr)
203 return (hdr->version_ihl & 0xf) * 4;
206 /* parse ipv6 extended headers, update offset and return next proto */
208 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
215 const struct ext_hdr *xh;
216 struct ext_hdr xh_copy;
221 #define MAX_EXT_HDRS 5
222 for (i = 0; i < MAX_EXT_HDRS; i++) {
224 case IPPROTO_HOPOPTS:
225 case IPPROTO_ROUTING:
226 case IPPROTO_DSTOPTS:
227 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
231 *off += (xh->len + 1) * 8;
232 proto = xh->next_hdr;
234 case IPPROTO_FRAGMENT:
235 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
240 proto = xh->next_hdr;
242 return proto; /* this is always the last ext hdr */
252 /* parse mbuf data to get packet type */
253 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
254 struct rte_net_hdr_lens *hdr_lens)
256 struct rte_net_hdr_lens local_hdr_lens;
257 const struct ether_hdr *eh;
258 struct ether_hdr eh_copy;
259 uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
263 if (hdr_lens == NULL)
264 hdr_lens = &local_hdr_lens;
266 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
267 if (unlikely(eh == NULL))
269 proto = eh->ether_type;
271 hdr_lens->l2_len = off;
273 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
274 goto l3; /* fast path if packet is IPv4 */
276 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
277 const struct vlan_hdr *vh;
278 struct vlan_hdr vh_copy;
280 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
281 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
282 if (unlikely(vh == NULL))
285 hdr_lens->l2_len += sizeof(*vh);
286 proto = vh->eth_proto;
287 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
288 const struct vlan_hdr *vh;
289 struct vlan_hdr vh_copy;
291 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
292 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
294 if (unlikely(vh == NULL))
296 off += 2 * sizeof(*vh);
297 hdr_lens->l2_len += 2 * sizeof(*vh);
298 proto = vh->eth_proto;
302 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
303 const struct ipv4_hdr *ip4h;
304 struct ipv4_hdr ip4h_copy;
306 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
307 if (unlikely(ip4h == NULL))
310 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
311 hdr_lens->l3_len = ip4_hlen(ip4h);
312 off += hdr_lens->l3_len;
313 if (ip4h->fragment_offset & rte_cpu_to_be_16(
314 IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
315 pkt_type |= RTE_PTYPE_L4_FRAG;
316 hdr_lens->l4_len = 0;
319 proto = ip4h->next_proto_id;
320 pkt_type |= ptype_l4(proto);
321 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
322 const struct ipv6_hdr *ip6h;
323 struct ipv6_hdr ip6h_copy;
326 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
327 if (unlikely(ip6h == NULL))
331 hdr_lens->l3_len = sizeof(*ip6h);
332 off += hdr_lens->l3_len;
333 pkt_type |= ptype_l3_ip6(proto);
334 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
335 proto = skip_ip6_ext(proto, m, &off, &frag);
336 hdr_lens->l3_len = off - hdr_lens->l2_len;
341 pkt_type |= RTE_PTYPE_L4_FRAG;
342 hdr_lens->l4_len = 0;
345 pkt_type |= ptype_l4(proto);
348 if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
349 hdr_lens->l4_len = sizeof(struct udp_hdr);
351 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
352 const struct tcp_hdr *th;
353 struct tcp_hdr th_copy;
355 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
356 if (unlikely(th == NULL))
357 return pkt_type & (RTE_PTYPE_L2_MASK |
359 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
361 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
362 hdr_lens->l4_len = sizeof(struct sctp_hdr);
365 uint32_t prev_off = off;
367 hdr_lens->l4_len = 0;
368 pkt_type |= ptype_tunnel(&proto, m, &off);
369 hdr_lens->tunnel_len = off - prev_off;
372 /* same job for inner header: we need to duplicate the code
373 * because the packet types do not have the same value.
375 hdr_lens->inner_l2_len = 0;
377 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
378 const struct ipv4_hdr *ip4h;
379 struct ipv4_hdr ip4h_copy;
381 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
382 if (unlikely(ip4h == NULL))
385 pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
386 hdr_lens->inner_l3_len = ip4_hlen(ip4h);
387 off += hdr_lens->inner_l3_len;
388 if (ip4h->fragment_offset &
389 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
391 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
392 hdr_lens->inner_l4_len = 0;
395 proto = ip4h->next_proto_id;
396 pkt_type |= ptype_inner_l4(proto);
397 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
398 const struct ipv6_hdr *ip6h;
399 struct ipv6_hdr ip6h_copy;
402 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
403 if (unlikely(ip6h == NULL))
407 hdr_lens->inner_l3_len = sizeof(*ip6h);
408 off += hdr_lens->inner_l3_len;
409 pkt_type |= ptype_inner_l3_ip6(proto);
410 if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
411 RTE_PTYPE_INNER_L3_IPV6_EXT) {
415 proto = skip_ip6_ext(proto, m, &off, &frag);
416 hdr_lens->inner_l3_len += off - prev_off;
421 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
422 hdr_lens->inner_l4_len = 0;
425 pkt_type |= ptype_inner_l4(proto);
428 if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
429 hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
430 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
431 RTE_PTYPE_INNER_L4_TCP) {
432 const struct tcp_hdr *th;
433 struct tcp_hdr th_copy;
435 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
436 if (unlikely(th == NULL))
437 return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
438 RTE_PTYPE_INNER_L3_MASK);
439 hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
440 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
441 RTE_PTYPE_INNER_L4_SCTP) {
442 hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
444 hdr_lens->inner_l4_len = 0;