net: provide IP-related API on any OS
[dpdk.git] / lib / librte_net / rte_net.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  */
4
5 #include <stdint.h>
6
7 #include <rte_mbuf.h>
8 #include <rte_mbuf_ptype.h>
9 #include <rte_byteorder.h>
10 #include <rte_ether.h>
11 #include <rte_ip.h>
12 #include <rte_tcp.h>
13 #include <rte_udp.h>
14 #include <rte_sctp.h>
15 #include <rte_gre.h>
16 #include <rte_mpls.h>
17 #include <rte_net.h>
18 #include <rte_os_shim.h>
19
20 /* get l3 packet type from ip6 next protocol */
21 static uint32_t
22 ptype_l3_ip6(uint8_t ip6_proto)
23 {
24         static const uint32_t ip6_ext_proto_map[256] = {
25                 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
26                 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
27                 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
28                 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
29                 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
30                 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
31         };
32
33         return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
34 }
35
36 /* get l3 packet type from ip version and header length */
37 static uint32_t
38 ptype_l3_ip(uint8_t ipv_ihl)
39 {
40         static const uint32_t ptype_l3_ip_proto_map[256] = {
41                 [0x45] = RTE_PTYPE_L3_IPV4,
42                 [0x46] = RTE_PTYPE_L3_IPV4_EXT,
43                 [0x47] = RTE_PTYPE_L3_IPV4_EXT,
44                 [0x48] = RTE_PTYPE_L3_IPV4_EXT,
45                 [0x49] = RTE_PTYPE_L3_IPV4_EXT,
46                 [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
47                 [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
48                 [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
49                 [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
50                 [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
51                 [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
52         };
53
54         return ptype_l3_ip_proto_map[ipv_ihl];
55 }
56
57 /* get l4 packet type from proto */
58 static uint32_t
59 ptype_l4(uint8_t proto)
60 {
61         static const uint32_t ptype_l4_proto[256] = {
62                 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
63                 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
64                 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
65         };
66
67         return ptype_l4_proto[proto];
68 }
69
70 /* get inner l3 packet type from ip6 next protocol */
71 static uint32_t
72 ptype_inner_l3_ip6(uint8_t ip6_proto)
73 {
74         static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
75                 [IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
76                         RTE_PTYPE_INNER_L3_IPV6,
77                 [IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
78                         RTE_PTYPE_INNER_L3_IPV6,
79                 [IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
80                         RTE_PTYPE_INNER_L3_IPV6,
81                 [IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
82                         RTE_PTYPE_INNER_L3_IPV6,
83                 [IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
84                         RTE_PTYPE_INNER_L3_IPV6,
85                 [IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
86                         RTE_PTYPE_INNER_L3_IPV6,
87         };
88
89         return RTE_PTYPE_INNER_L3_IPV6 +
90                 ptype_inner_ip6_ext_proto_map[ip6_proto];
91 }
92
93 /* get inner l3 packet type from ip version and header length */
94 static uint32_t
95 ptype_inner_l3_ip(uint8_t ipv_ihl)
96 {
97         static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
98                 [0x45] = RTE_PTYPE_INNER_L3_IPV4,
99                 [0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
100                 [0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
101                 [0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
102                 [0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
103                 [0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
104                 [0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
105                 [0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
106                 [0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
107                 [0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
108                 [0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
109         };
110
111         return ptype_inner_l3_ip_proto_map[ipv_ihl];
112 }
113
114 /* get inner l4 packet type from proto */
115 static uint32_t
116 ptype_inner_l4(uint8_t proto)
117 {
118         static const uint32_t ptype_inner_l4_proto[256] = {
119                 [IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
120                 [IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
121                 [IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
122         };
123
124         return ptype_inner_l4_proto[proto];
125 }
126
127 /* get the tunnel packet type if any, update proto and off. */
128 static uint32_t
129 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
130         uint32_t *off)
131 {
132         switch (*proto) {
133         case IPPROTO_GRE: {
134                 static const uint8_t opt_len[16] = {
135                         [0x0] = 4,
136                         [0x1] = 8,
137                         [0x2] = 8,
138                         [0x8] = 8,
139                         [0x3] = 12,
140                         [0x9] = 12,
141                         [0xa] = 12,
142                         [0xb] = 16,
143                 };
144                 const struct rte_gre_hdr *gh;
145                 struct rte_gre_hdr gh_copy;
146                 uint16_t flags;
147
148                 gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
149                 if (unlikely(gh == NULL))
150                         return 0;
151
152                 flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
153                 flags >>= 12;
154                 if (opt_len[flags] == 0)
155                         return 0;
156
157                 *off += opt_len[flags];
158                 *proto = gh->proto;
159                 if (*proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB))
160                         return RTE_PTYPE_TUNNEL_NVGRE;
161                 else
162                         return RTE_PTYPE_TUNNEL_GRE;
163         }
164         case IPPROTO_IPIP:
165                 *proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
166                 return RTE_PTYPE_TUNNEL_IP;
167         case IPPROTO_IPV6:
168                 *proto = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
169                 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
170         default:
171                 return 0;
172         }
173 }
174
175 /* parse ipv6 extended headers, update offset and return next proto */
176 int
177 rte_net_skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
178         int *frag)
179 {
180         struct ext_hdr {
181                 uint8_t next_hdr;
182                 uint8_t len;
183         };
184         const struct ext_hdr *xh;
185         struct ext_hdr xh_copy;
186         unsigned int i;
187
188         *frag = 0;
189
190 #define MAX_EXT_HDRS 5
191         for (i = 0; i < MAX_EXT_HDRS; i++) {
192                 switch (proto) {
193                 case IPPROTO_HOPOPTS:
194                 case IPPROTO_ROUTING:
195                 case IPPROTO_DSTOPTS:
196                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
197                                 &xh_copy);
198                         if (xh == NULL)
199                                 return -1;
200                         *off += (xh->len + 1) * 8;
201                         proto = xh->next_hdr;
202                         break;
203                 case IPPROTO_FRAGMENT:
204                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
205                                 &xh_copy);
206                         if (xh == NULL)
207                                 return -1;
208                         *off += 8;
209                         proto = xh->next_hdr;
210                         *frag = 1;
211                         return proto; /* this is always the last ext hdr */
212                 case IPPROTO_NONE:
213                         return 0;
214                 default:
215                         return proto;
216                 }
217         }
218         return -1;
219 }
220
221 /* parse mbuf data to get packet type */
222 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
223         struct rte_net_hdr_lens *hdr_lens, uint32_t layers)
224 {
225         struct rte_net_hdr_lens local_hdr_lens;
226         const struct rte_ether_hdr *eh;
227         struct rte_ether_hdr eh_copy;
228         uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
229         uint32_t off = 0;
230         uint16_t proto;
231         int ret;
232
233         if (hdr_lens == NULL)
234                 hdr_lens = &local_hdr_lens;
235
236         eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
237         if (unlikely(eh == NULL))
238                 return 0;
239         proto = eh->ether_type;
240         off = sizeof(*eh);
241         hdr_lens->l2_len = off;
242
243         if ((layers & RTE_PTYPE_L2_MASK) == 0)
244                 return 0;
245
246         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4))
247                 goto l3; /* fast path if packet is IPv4 */
248
249         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN)) {
250                 const struct rte_vlan_hdr *vh;
251                 struct rte_vlan_hdr vh_copy;
252
253                 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
254                 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
255                 if (unlikely(vh == NULL))
256                         return pkt_type;
257                 off += sizeof(*vh);
258                 hdr_lens->l2_len += sizeof(*vh);
259                 proto = vh->eth_proto;
260         } else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
261                 const struct rte_vlan_hdr *vh;
262                 struct rte_vlan_hdr vh_copy;
263
264                 pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
265                 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
266                         &vh_copy);
267                 if (unlikely(vh == NULL))
268                         return pkt_type;
269                 off += 2 * sizeof(*vh);
270                 hdr_lens->l2_len += 2 * sizeof(*vh);
271                 proto = vh->eth_proto;
272         } else if ((proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) ||
273                 (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLSM))) {
274                 unsigned int i;
275                 const struct rte_mpls_hdr *mh;
276                 struct rte_mpls_hdr mh_copy;
277
278 #define MAX_MPLS_HDR 5
279                 for (i = 0; i < MAX_MPLS_HDR; i++) {
280                         mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
281                                 sizeof(*mh), &mh_copy);
282                         if (unlikely(mh == NULL))
283                                 return pkt_type;
284                 }
285                 if (i == MAX_MPLS_HDR)
286                         return pkt_type;
287                 pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
288                 hdr_lens->l2_len += (sizeof(*mh) * i);
289                 return pkt_type;
290         }
291
292 l3:
293         if ((layers & RTE_PTYPE_L3_MASK) == 0)
294                 return pkt_type;
295
296         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
297                 const struct rte_ipv4_hdr *ip4h;
298                 struct rte_ipv4_hdr ip4h_copy;
299
300                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
301                 if (unlikely(ip4h == NULL))
302                         return pkt_type;
303
304                 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
305                 hdr_lens->l3_len = rte_ipv4_hdr_len(ip4h);
306                 off += hdr_lens->l3_len;
307
308                 if ((layers & RTE_PTYPE_L4_MASK) == 0)
309                         return pkt_type;
310
311                 if (ip4h->fragment_offset & rte_cpu_to_be_16(
312                                 RTE_IPV4_HDR_OFFSET_MASK | RTE_IPV4_HDR_MF_FLAG)) {
313                         pkt_type |= RTE_PTYPE_L4_FRAG;
314                         hdr_lens->l4_len = 0;
315                         return pkt_type;
316                 }
317                 proto = ip4h->next_proto_id;
318                 pkt_type |= ptype_l4(proto);
319         } else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
320                 const struct rte_ipv6_hdr *ip6h;
321                 struct rte_ipv6_hdr ip6h_copy;
322                 int frag = 0;
323
324                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
325                 if (unlikely(ip6h == NULL))
326                         return pkt_type;
327
328                 proto = ip6h->proto;
329                 hdr_lens->l3_len = sizeof(*ip6h);
330                 off += hdr_lens->l3_len;
331                 pkt_type |= ptype_l3_ip6(proto);
332                 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
333                         ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
334                         if (ret < 0)
335                                 return pkt_type;
336                         proto = ret;
337                         hdr_lens->l3_len = off - hdr_lens->l2_len;
338                 }
339                 if (proto == 0)
340                         return pkt_type;
341
342                 if ((layers & RTE_PTYPE_L4_MASK) == 0)
343                         return pkt_type;
344
345                 if (frag) {
346                         pkt_type |= RTE_PTYPE_L4_FRAG;
347                         hdr_lens->l4_len = 0;
348                         return pkt_type;
349                 }
350                 pkt_type |= ptype_l4(proto);
351         }
352
353         if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
354                 hdr_lens->l4_len = sizeof(struct rte_udp_hdr);
355                 return pkt_type;
356         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
357                 const struct rte_tcp_hdr *th;
358                 struct rte_tcp_hdr th_copy;
359
360                 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
361                 if (unlikely(th == NULL))
362                         return pkt_type & (RTE_PTYPE_L2_MASK |
363                                 RTE_PTYPE_L3_MASK);
364                 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
365                 return pkt_type;
366         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
367                 hdr_lens->l4_len = sizeof(struct rte_sctp_hdr);
368                 return pkt_type;
369         } else {
370                 uint32_t prev_off = off;
371
372                 hdr_lens->l4_len = 0;
373
374                 if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0)
375                         return pkt_type;
376
377                 pkt_type |= ptype_tunnel(&proto, m, &off);
378                 hdr_lens->tunnel_len = off - prev_off;
379         }
380
381         /* same job for inner header: we need to duplicate the code
382          * because the packet types do not have the same value.
383          */
384         if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0)
385                 return pkt_type;
386
387         hdr_lens->inner_l2_len = 0;
388         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB)) {
389                 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
390                 if (unlikely(eh == NULL))
391                         return pkt_type;
392                 pkt_type |= RTE_PTYPE_INNER_L2_ETHER;
393                 proto = eh->ether_type;
394                 off += sizeof(*eh);
395                 hdr_lens->inner_l2_len = sizeof(*eh);
396         }
397
398         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN)) {
399                 const struct rte_vlan_hdr *vh;
400                 struct rte_vlan_hdr vh_copy;
401
402                 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
403                 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN;
404                 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
405                 if (unlikely(vh == NULL))
406                         return pkt_type;
407                 off += sizeof(*vh);
408                 hdr_lens->inner_l2_len += sizeof(*vh);
409                 proto = vh->eth_proto;
410         } else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
411                 const struct rte_vlan_hdr *vh;
412                 struct rte_vlan_hdr vh_copy;
413
414                 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
415                 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ;
416                 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
417                         &vh_copy);
418                 if (unlikely(vh == NULL))
419                         return pkt_type;
420                 off += 2 * sizeof(*vh);
421                 hdr_lens->inner_l2_len += 2 * sizeof(*vh);
422                 proto = vh->eth_proto;
423         }
424
425         if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
426                 return pkt_type;
427
428         if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
429                 const struct rte_ipv4_hdr *ip4h;
430                 struct rte_ipv4_hdr ip4h_copy;
431
432                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
433                 if (unlikely(ip4h == NULL))
434                         return pkt_type;
435
436                 pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
437                 hdr_lens->inner_l3_len = rte_ipv4_hdr_len(ip4h);
438                 off += hdr_lens->inner_l3_len;
439
440                 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
441                         return pkt_type;
442                 if (ip4h->fragment_offset &
443                                 rte_cpu_to_be_16(RTE_IPV4_HDR_OFFSET_MASK |
444                                         RTE_IPV4_HDR_MF_FLAG)) {
445                         pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
446                         hdr_lens->inner_l4_len = 0;
447                         return pkt_type;
448                 }
449                 proto = ip4h->next_proto_id;
450                 pkt_type |= ptype_inner_l4(proto);
451         } else if (proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
452                 const struct rte_ipv6_hdr *ip6h;
453                 struct rte_ipv6_hdr ip6h_copy;
454                 int frag = 0;
455
456                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
457                 if (unlikely(ip6h == NULL))
458                         return pkt_type;
459
460                 proto = ip6h->proto;
461                 hdr_lens->inner_l3_len = sizeof(*ip6h);
462                 off += hdr_lens->inner_l3_len;
463                 pkt_type |= ptype_inner_l3_ip6(proto);
464                 if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
465                                 RTE_PTYPE_INNER_L3_IPV6_EXT) {
466                         uint32_t prev_off;
467
468                         prev_off = off;
469                         ret = rte_net_skip_ip6_ext(proto, m, &off, &frag);
470                         if (ret < 0)
471                                 return pkt_type;
472                         proto = ret;
473                         hdr_lens->inner_l3_len += off - prev_off;
474                 }
475                 if (proto == 0)
476                         return pkt_type;
477
478                 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
479                         return pkt_type;
480
481                 if (frag) {
482                         pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
483                         hdr_lens->inner_l4_len = 0;
484                         return pkt_type;
485                 }
486                 pkt_type |= ptype_inner_l4(proto);
487         }
488
489         if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
490                 hdr_lens->inner_l4_len = sizeof(struct rte_udp_hdr);
491         } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
492                         RTE_PTYPE_INNER_L4_TCP) {
493                 const struct rte_tcp_hdr *th;
494                 struct rte_tcp_hdr th_copy;
495
496                 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
497                 if (unlikely(th == NULL))
498                         return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
499                                 RTE_PTYPE_INNER_L3_MASK);
500                 hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
501         } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
502                         RTE_PTYPE_INNER_L4_SCTP) {
503                 hdr_lens->inner_l4_len = sizeof(struct rte_sctp_hdr);
504         } else {
505                 hdr_lens->inner_l4_len = 0;
506         }
507
508         return pkt_type;
509 }