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>
46 /* get l3 packet type from ip6 next protocol */
48 ptype_l3_ip6(uint8_t ip6_proto)
50 static const uint32_t ip6_ext_proto_map[256] = {
51 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
52 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
53 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
54 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
55 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
56 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
59 return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
62 /* get l3 packet type from ip version and header length */
64 ptype_l3_ip(uint8_t ipv_ihl)
66 static const uint32_t ptype_l3_ip_proto_map[256] = {
67 [0x45] = RTE_PTYPE_L3_IPV4,
68 [0x46] = RTE_PTYPE_L3_IPV4_EXT,
69 [0x47] = RTE_PTYPE_L3_IPV4_EXT,
70 [0x48] = RTE_PTYPE_L3_IPV4_EXT,
71 [0x49] = RTE_PTYPE_L3_IPV4_EXT,
72 [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
73 [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
74 [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
75 [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
76 [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
77 [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
80 return ptype_l3_ip_proto_map[ipv_ihl];
83 /* get l4 packet type from proto */
85 ptype_l4(uint8_t proto)
87 static const uint32_t ptype_l4_proto[256] = {
88 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
89 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
90 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
93 return ptype_l4_proto[proto];
96 /* get inner l3 packet type from ip6 next protocol */
98 ptype_inner_l3_ip6(uint8_t ip6_proto)
100 static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
101 [IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
102 RTE_PTYPE_INNER_L3_IPV6,
103 [IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
104 RTE_PTYPE_INNER_L3_IPV6,
105 [IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
106 RTE_PTYPE_INNER_L3_IPV6,
107 [IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
108 RTE_PTYPE_INNER_L3_IPV6,
109 [IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
110 RTE_PTYPE_INNER_L3_IPV6,
111 [IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
112 RTE_PTYPE_INNER_L3_IPV6,
115 return RTE_PTYPE_INNER_L3_IPV6 +
116 ptype_inner_ip6_ext_proto_map[ip6_proto];
119 /* get inner l3 packet type from ip version and header length */
121 ptype_inner_l3_ip(uint8_t ipv_ihl)
123 static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
124 [0x45] = RTE_PTYPE_INNER_L3_IPV4,
125 [0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
126 [0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
127 [0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
128 [0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
129 [0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
130 [0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
131 [0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
132 [0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
133 [0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
134 [0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
137 return ptype_inner_l3_ip_proto_map[ipv_ihl];
140 /* get inner l4 packet type from proto */
142 ptype_inner_l4(uint8_t proto)
144 static const uint32_t ptype_inner_l4_proto[256] = {
145 [IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
146 [IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
147 [IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
150 return ptype_inner_l4_proto[proto];
153 /* get the tunnel packet type if any, update proto. */
155 ptype_tunnel(uint16_t *proto)
159 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
160 return RTE_PTYPE_TUNNEL_IP;
162 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
163 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
169 /* get the ipv4 header length */
171 ip4_hlen(const struct ipv4_hdr *hdr)
173 return (hdr->version_ihl & 0xf) * 4;
176 /* parse ipv6 extended headers, update offset and return next proto */
178 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
185 const struct ext_hdr *xh;
186 struct ext_hdr xh_copy;
191 #define MAX_EXT_HDRS 5
192 for (i = 0; i < MAX_EXT_HDRS; i++) {
194 case IPPROTO_HOPOPTS:
195 case IPPROTO_ROUTING:
196 case IPPROTO_DSTOPTS:
197 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
201 *off += (xh->len + 1) * 8;
202 proto = xh->next_hdr;
204 case IPPROTO_FRAGMENT:
205 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
210 proto = xh->next_hdr;
212 return proto; /* this is always the last ext hdr */
222 /* parse mbuf data to get packet type */
223 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
224 struct rte_net_hdr_lens *hdr_lens)
226 struct rte_net_hdr_lens local_hdr_lens;
227 const struct ether_hdr *eh;
228 struct ether_hdr eh_copy;
229 uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
233 if (hdr_lens == NULL)
234 hdr_lens = &local_hdr_lens;
236 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
237 if (unlikely(eh == NULL))
239 proto = eh->ether_type;
241 hdr_lens->l2_len = off;
243 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
244 goto l3; /* fast path if packet is IPv4 */
246 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
247 const struct vlan_hdr *vh;
248 struct vlan_hdr vh_copy;
250 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
251 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
252 if (unlikely(vh == NULL))
255 hdr_lens->l2_len += sizeof(*vh);
256 proto = vh->eth_proto;
257 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
258 const struct vlan_hdr *vh;
259 struct vlan_hdr vh_copy;
261 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
262 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
264 if (unlikely(vh == NULL))
266 off += 2 * sizeof(*vh);
267 hdr_lens->l2_len += 2 * sizeof(*vh);
268 proto = vh->eth_proto;
272 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
273 const struct ipv4_hdr *ip4h;
274 struct ipv4_hdr ip4h_copy;
276 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
277 if (unlikely(ip4h == NULL))
280 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
281 hdr_lens->l3_len = ip4_hlen(ip4h);
282 off += hdr_lens->l3_len;
283 if (ip4h->fragment_offset & rte_cpu_to_be_16(
284 IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
285 pkt_type |= RTE_PTYPE_L4_FRAG;
286 hdr_lens->l4_len = 0;
289 proto = ip4h->next_proto_id;
290 pkt_type |= ptype_l4(proto);
291 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
292 const struct ipv6_hdr *ip6h;
293 struct ipv6_hdr ip6h_copy;
296 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
297 if (unlikely(ip6h == NULL))
301 hdr_lens->l3_len = sizeof(*ip6h);
302 off += hdr_lens->l3_len;
303 pkt_type |= ptype_l3_ip6(proto);
304 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
305 proto = skip_ip6_ext(proto, m, &off, &frag);
306 hdr_lens->l3_len = off - hdr_lens->l2_len;
311 pkt_type |= RTE_PTYPE_L4_FRAG;
312 hdr_lens->l4_len = 0;
315 pkt_type |= ptype_l4(proto);
318 if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
319 hdr_lens->l4_len = sizeof(struct udp_hdr);
321 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
322 const struct tcp_hdr *th;
323 struct tcp_hdr th_copy;
325 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
326 if (unlikely(th == NULL))
327 return pkt_type & (RTE_PTYPE_L2_MASK |
329 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
331 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
332 hdr_lens->l4_len = sizeof(struct sctp_hdr);
335 hdr_lens->l4_len = 0;
336 pkt_type |= ptype_tunnel(&proto);
337 hdr_lens->tunnel_len = 0;
340 /* same job for inner header: we need to duplicate the code
341 * because the packet types do not have the same value.
343 hdr_lens->inner_l2_len = 0;
345 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
346 const struct ipv4_hdr *ip4h;
347 struct ipv4_hdr ip4h_copy;
349 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
350 if (unlikely(ip4h == NULL))
353 pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
354 hdr_lens->inner_l3_len = ip4_hlen(ip4h);
355 off += hdr_lens->inner_l3_len;
356 if (ip4h->fragment_offset &
357 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
359 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
360 hdr_lens->inner_l4_len = 0;
363 proto = ip4h->next_proto_id;
364 pkt_type |= ptype_inner_l4(proto);
365 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
366 const struct ipv6_hdr *ip6h;
367 struct ipv6_hdr ip6h_copy;
370 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
371 if (unlikely(ip6h == NULL))
375 hdr_lens->inner_l3_len = sizeof(*ip6h);
376 off += hdr_lens->inner_l3_len;
377 pkt_type |= ptype_inner_l3_ip6(proto);
378 if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
379 RTE_PTYPE_INNER_L3_IPV6_EXT) {
383 proto = skip_ip6_ext(proto, m, &off, &frag);
384 hdr_lens->inner_l3_len += off - prev_off;
389 pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
390 hdr_lens->inner_l4_len = 0;
393 pkt_type |= ptype_inner_l4(proto);
396 if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
397 hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
398 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
399 RTE_PTYPE_INNER_L4_TCP) {
400 const struct tcp_hdr *th;
401 struct tcp_hdr th_copy;
403 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
404 if (unlikely(th == NULL))
405 return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
406 RTE_PTYPE_INNER_L3_MASK);
407 hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
408 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
409 RTE_PTYPE_INNER_L4_SCTP) {
410 hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
412 hdr_lens->inner_l4_len = 0;