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