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 the ipv4 header length */
98 ip4_hlen(const struct ipv4_hdr *hdr)
100 return (hdr->version_ihl & 0xf) * 4;
103 /* parse ipv6 extended headers, update offset and return next proto */
105 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
112 const struct ext_hdr *xh;
113 struct ext_hdr xh_copy;
118 #define MAX_EXT_HDRS 5
119 for (i = 0; i < MAX_EXT_HDRS; i++) {
121 case IPPROTO_HOPOPTS:
122 case IPPROTO_ROUTING:
123 case IPPROTO_DSTOPTS:
124 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
128 *off += (xh->len + 1) * 8;
129 proto = xh->next_hdr;
131 case IPPROTO_FRAGMENT:
132 xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
137 proto = xh->next_hdr;
139 return proto; /* this is always the last ext hdr */
149 /* parse mbuf data to get packet type */
150 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
151 struct rte_net_hdr_lens *hdr_lens)
153 struct rte_net_hdr_lens local_hdr_lens;
154 const struct ether_hdr *eh;
155 struct ether_hdr eh_copy;
156 uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
160 if (hdr_lens == NULL)
161 hdr_lens = &local_hdr_lens;
163 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
164 if (unlikely(eh == NULL))
166 proto = eh->ether_type;
168 hdr_lens->l2_len = off;
170 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
171 goto l3; /* fast path if packet is IPv4 */
173 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
174 const struct vlan_hdr *vh;
175 struct vlan_hdr vh_copy;
177 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
178 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
179 if (unlikely(vh == NULL))
182 hdr_lens->l2_len += sizeof(*vh);
183 proto = vh->eth_proto;
184 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
185 const struct vlan_hdr *vh;
186 struct vlan_hdr vh_copy;
188 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
189 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
191 if (unlikely(vh == NULL))
193 off += 2 * sizeof(*vh);
194 hdr_lens->l2_len += 2 * sizeof(*vh);
195 proto = vh->eth_proto;
199 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
200 const struct ipv4_hdr *ip4h;
201 struct ipv4_hdr ip4h_copy;
203 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
204 if (unlikely(ip4h == NULL))
207 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
208 hdr_lens->l3_len = ip4_hlen(ip4h);
209 off += hdr_lens->l3_len;
210 if (ip4h->fragment_offset &
211 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
213 pkt_type |= RTE_PTYPE_L4_FRAG;
214 hdr_lens->l4_len = 0;
217 proto = ip4h->next_proto_id;
218 pkt_type |= ptype_l4(proto);
219 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
220 const struct ipv6_hdr *ip6h;
221 struct ipv6_hdr ip6h_copy;
224 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
225 if (unlikely(ip6h == NULL))
229 hdr_lens->l3_len = sizeof(*ip6h);
230 off += hdr_lens->l3_len;
231 pkt_type |= ptype_l3_ip6(proto);
232 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
233 proto = skip_ip6_ext(proto, m, &off, &frag);
234 hdr_lens->l3_len = off - hdr_lens->l2_len;
239 pkt_type |= RTE_PTYPE_L4_FRAG;
240 hdr_lens->l4_len = 0;
243 pkt_type |= ptype_l4(proto);
246 if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
247 hdr_lens->l4_len = sizeof(struct udp_hdr);
248 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
249 const struct tcp_hdr *th;
250 struct tcp_hdr th_copy;
252 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
253 if (unlikely(th == NULL))
254 return pkt_type & (RTE_PTYPE_L2_MASK |
256 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
257 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
258 hdr_lens->l4_len = sizeof(struct sctp_hdr);
260 hdr_lens->l4_len = 0;