net: support GRE in software packet type parser
[dpdk.git] / lib / librte_net / rte_net.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2016 6WIND S.A.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
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
16  *       distribution.
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.
20  *
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.
32  */
33
34 #include <stdint.h>
35
36 #include <rte_mbuf.h>
37 #include <rte_mbuf_ptype.h>
38 #include <rte_byteorder.h>
39 #include <rte_ether.h>
40 #include <rte_ip.h>
41 #include <rte_tcp.h>
42 #include <rte_udp.h>
43 #include <rte_sctp.h>
44 #include <rte_gre.h>
45 #include <rte_net.h>
46
47 /* get l3 packet type from ip6 next protocol */
48 static uint32_t
49 ptype_l3_ip6(uint8_t ip6_proto)
50 {
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,
58         };
59
60         return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
61 }
62
63 /* get l3 packet type from ip version and header length */
64 static uint32_t
65 ptype_l3_ip(uint8_t ipv_ihl)
66 {
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,
79         };
80
81         return ptype_l3_ip_proto_map[ipv_ihl];
82 }
83
84 /* get l4 packet type from proto */
85 static uint32_t
86 ptype_l4(uint8_t proto)
87 {
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,
92         };
93
94         return ptype_l4_proto[proto];
95 }
96
97 /* get inner l3 packet type from ip6 next protocol */
98 static uint32_t
99 ptype_inner_l3_ip6(uint8_t ip6_proto)
100 {
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,
114         };
115
116         return RTE_PTYPE_INNER_L3_IPV6 +
117                 ptype_inner_ip6_ext_proto_map[ip6_proto];
118 }
119
120 /* get inner l3 packet type from ip version and header length */
121 static uint32_t
122 ptype_inner_l3_ip(uint8_t ipv_ihl)
123 {
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,
136         };
137
138         return ptype_inner_l3_ip_proto_map[ipv_ihl];
139 }
140
141 /* get inner l4 packet type from proto */
142 static uint32_t
143 ptype_inner_l4(uint8_t proto)
144 {
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,
149         };
150
151         return ptype_inner_l4_proto[proto];
152 }
153
154 /* get the tunnel packet type if any, update proto and off. */
155 static uint32_t
156 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
157         uint32_t *off)
158 {
159         switch (*proto) {
160         case IPPROTO_GRE: {
161                 static const uint8_t opt_len[16] = {
162                         [0x0] = 4,
163                         [0x1] = 8,
164                         [0x2] = 8,
165                         [0x8] = 8,
166                         [0x3] = 12,
167                         [0x9] = 12,
168                         [0xa] = 12,
169                         [0xb] = 16,
170                 };
171                 const struct gre_hdr *gh;
172                 struct gre_hdr gh_copy;
173                 uint16_t flags;
174
175                 gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
176                 if (unlikely(gh == NULL))
177                         return 0;
178
179                 flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
180                 flags >>= 12;
181                 if (opt_len[flags] == 0)
182                         return 0;
183
184                 *off += opt_len[flags];
185                 *proto = gh->proto;
186                 return RTE_PTYPE_TUNNEL_GRE;
187         }
188         case IPPROTO_IPIP:
189                 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
190                 return RTE_PTYPE_TUNNEL_IP;
191         case IPPROTO_IPV6:
192                 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
193                 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
194         default:
195                 return 0;
196         }
197 }
198
199 /* get the ipv4 header length */
200 static uint8_t
201 ip4_hlen(const struct ipv4_hdr *hdr)
202 {
203         return (hdr->version_ihl & 0xf) * 4;
204 }
205
206 /* parse ipv6 extended headers, update offset and return next proto */
207 static uint16_t
208 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
209         int *frag)
210 {
211         struct ext_hdr {
212                 uint8_t next_hdr;
213                 uint8_t len;
214         };
215         const struct ext_hdr *xh;
216         struct ext_hdr xh_copy;
217         unsigned int i;
218
219         *frag = 0;
220
221 #define MAX_EXT_HDRS 5
222         for (i = 0; i < MAX_EXT_HDRS; i++) {
223                 switch (proto) {
224                 case IPPROTO_HOPOPTS:
225                 case IPPROTO_ROUTING:
226                 case IPPROTO_DSTOPTS:
227                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
228                                 &xh_copy);
229                         if (xh == NULL)
230                                 return 0;
231                         *off += (xh->len + 1) * 8;
232                         proto = xh->next_hdr;
233                         break;
234                 case IPPROTO_FRAGMENT:
235                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
236                                 &xh_copy);
237                         if (xh == NULL)
238                                 return 0;
239                         *off += 8;
240                         proto = xh->next_hdr;
241                         *frag = 1;
242                         return proto; /* this is always the last ext hdr */
243                 case IPPROTO_NONE:
244                         return 0;
245                 default:
246                         return proto;
247                 }
248         }
249         return 0;
250 }
251
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)
255 {
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;
260         uint32_t off = 0;
261         uint16_t proto;
262
263         if (hdr_lens == NULL)
264                 hdr_lens = &local_hdr_lens;
265
266         eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
267         if (unlikely(eh == NULL))
268                 return 0;
269         proto = eh->ether_type;
270         off = sizeof(*eh);
271         hdr_lens->l2_len = off;
272
273         if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
274                 goto l3; /* fast path if packet is IPv4 */
275
276         if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
277                 const struct vlan_hdr *vh;
278                 struct vlan_hdr vh_copy;
279
280                 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
281                 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
282                 if (unlikely(vh == NULL))
283                         return pkt_type;
284                 off += sizeof(*vh);
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;
290
291                 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
292                 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
293                         &vh_copy);
294                 if (unlikely(vh == NULL))
295                         return pkt_type;
296                 off += 2 * sizeof(*vh);
297                 hdr_lens->l2_len += 2 * sizeof(*vh);
298                 proto = vh->eth_proto;
299         }
300
301  l3:
302         if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
303                 const struct ipv4_hdr *ip4h;
304                 struct ipv4_hdr ip4h_copy;
305
306                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
307                 if (unlikely(ip4h == NULL))
308                         return pkt_type;
309
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;
317                         return pkt_type;
318                 }
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;
324                 int frag = 0;
325
326                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
327                 if (unlikely(ip6h == NULL))
328                         return pkt_type;
329
330                 proto = ip6h->proto;
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;
337                 }
338                 if (proto == 0)
339                         return pkt_type;
340                 if (frag) {
341                         pkt_type |= RTE_PTYPE_L4_FRAG;
342                         hdr_lens->l4_len = 0;
343                         return pkt_type;
344                 }
345                 pkt_type |= ptype_l4(proto);
346         }
347
348         if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
349                 hdr_lens->l4_len = sizeof(struct udp_hdr);
350                 return pkt_type;
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;
354
355                 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
356                 if (unlikely(th == NULL))
357                         return pkt_type & (RTE_PTYPE_L2_MASK |
358                                 RTE_PTYPE_L3_MASK);
359                 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
360                 return pkt_type;
361         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
362                 hdr_lens->l4_len = sizeof(struct sctp_hdr);
363                 return pkt_type;
364         } else {
365                 uint32_t prev_off = off;
366
367                 hdr_lens->l4_len = 0;
368                 pkt_type |= ptype_tunnel(&proto, m, &off);
369                 hdr_lens->tunnel_len = off - prev_off;
370         }
371
372         /* same job for inner header: we need to duplicate the code
373          * because the packet types do not have the same value.
374          */
375         hdr_lens->inner_l2_len = 0;
376
377         if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
378                 const struct ipv4_hdr *ip4h;
379                 struct ipv4_hdr ip4h_copy;
380
381                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
382                 if (unlikely(ip4h == NULL))
383                         return pkt_type;
384
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 |
390                                         IPV4_HDR_MF_FLAG)) {
391                         pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
392                         hdr_lens->inner_l4_len = 0;
393                         return pkt_type;
394                 }
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;
400                 int frag = 0;
401
402                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
403                 if (unlikely(ip6h == NULL))
404                         return pkt_type;
405
406                 proto = ip6h->proto;
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) {
412                         uint32_t prev_off;
413
414                         prev_off = off;
415                         proto = skip_ip6_ext(proto, m, &off, &frag);
416                         hdr_lens->inner_l3_len += off - prev_off;
417                 }
418                 if (proto == 0)
419                         return pkt_type;
420                 if (frag) {
421                         pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
422                         hdr_lens->inner_l4_len = 0;
423                         return pkt_type;
424                 }
425                 pkt_type |= ptype_inner_l4(proto);
426         }
427
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;
434
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);
443         } else {
444                 hdr_lens->inner_l4_len = 0;
445         }
446
447         return pkt_type;
448 }