misc: minimize dependencies on udp.h
[vpp.git] / src / vnet / gso / hdr_offset_parser.h
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef included_hdr_offset_parser_h
17 #define included_hdr_offset_parser_h
18
19 #include <vnet/ethernet/ethernet.h>
20 #include <vnet/ip/ip4_packet.h>
21 #include <vnet/ip/ip6_packet.h>
22 #include <vnet/udp/udp_local.h>
23 #include <vnet/udp/udp_packet.h>
24 #include <vnet/vnet.h>
25 #include <vnet/vxlan/vxlan_packet.h>
26
27 #define foreach_gho_flag        \
28   _( 0, IP4)                    \
29   _( 1, IP6)                    \
30   _( 2, TCP)                    \
31   _( 3, UDP)                    \
32   _( 4, OUTER_IP4)              \
33   _( 5, OUTER_IP6)              \
34   _( 6, OUTER_TCP)              \
35   _( 7, OUTER_UDP)              \
36   _( 8, VXLAN_TUNNEL)           \
37   _( 9, GRE_TUNNEL)             \
38   _( 10, IPIP_TUNNEL)           \
39   _( 11, IPIP6_TUNNEL)          \
40   _( 12, GENEVE_TUNNEL)
41
42 typedef enum gho_flag_t_
43 {
44 #define _(bit, name) GHO_F_##name  = (1 << bit),
45   foreach_gho_flag
46 #undef _
47 } gho_flag_t;
48
49 #define GHO_F_TUNNEL (GHO_F_VXLAN_TUNNEL  |  \
50                       GHO_F_GENEVE_TUNNEL |  \
51                       GHO_F_IPIP_TUNNEL   |  \
52                       GHO_F_IPIP6_TUNNEL  |  \
53                       GHO_F_GRE_TUNNEL)
54
55 #define GHO_F_OUTER_HDR (GHO_F_OUTER_IP4 | \
56                          GHO_F_OUTER_IP6 | \
57                          GHO_F_OUTER_TCP | \
58                          GHO_F_OUTER_UDP)
59
60 #define GHO_F_INNER_HDR (GHO_F_IP4 | \
61                          GHO_F_IP6 | \
62                          GHO_F_UDP | \
63                          GHO_F_TCP)
64
65 typedef struct
66 {
67   i16 outer_l2_hdr_offset;
68   i16 outer_l3_hdr_offset;
69   i16 outer_l4_hdr_offset;
70   u16 outer_l4_hdr_sz;
71   u16 outer_hdr_sz;
72   i16 l2_hdr_offset;
73   i16 l3_hdr_offset;
74   i16 l4_hdr_offset;
75   u16 l4_hdr_sz;
76   u16 hdr_sz;
77   gho_flag_t gho_flags;
78 } generic_header_offset_t;
79
80 static_always_inline u8 *
81 format_generic_header_offset (u8 * s, va_list * args)
82 {
83   generic_header_offset_t *gho = va_arg (*args, generic_header_offset_t *);
84
85   if (gho->gho_flags & GHO_F_TUNNEL)
86     {
87       if (gho->gho_flags & GHO_F_VXLAN_TUNNEL)
88         s = format (s, "vxlan-tunnel ");
89       else if (gho->gho_flags & GHO_F_IPIP_TUNNEL)
90         s = format (s, "ipip-tunnel ");
91       else if (gho->gho_flags & GHO_F_GRE_TUNNEL)
92         s = format (s, "gre-tunnel ");
93       else if (gho->gho_flags & GHO_F_GENEVE_TUNNEL)
94         s = format (s, "geneve-tunnel ");
95
96       if (gho->gho_flags & GHO_F_OUTER_IP4)
97         s = format (s, "outer-ipv4 ");
98       else if (gho->gho_flags & GHO_F_OUTER_IP6)
99         s = format (s, "outer-ipv6 ");
100
101       if (gho->gho_flags & GHO_F_OUTER_UDP)
102         s = format (s, "outer-udp ");
103       else if (gho->gho_flags & GHO_F_OUTER_TCP)
104         s = format (s, "outer-tcp ");
105
106       s = format (s, "outer-hdr-sz %u outer-l2-hdr-offset %d "
107                   "outer-l3-hdr-offset %d outer-l4-hdr-offset %d "
108                   "outer-l4-hdr-sz %u\n\t",
109                   gho->outer_hdr_sz, gho->outer_l2_hdr_offset,
110                   gho->outer_l3_hdr_offset, gho->outer_l4_hdr_offset,
111                   gho->outer_l4_hdr_sz);
112     }
113
114   if (gho->gho_flags & GHO_F_IP4)
115     s = format (s, "ipv4 ");
116   else if (gho->gho_flags & GHO_F_IP6)
117     s = format (s, "ipv6 ");
118
119   if (gho->gho_flags & GHO_F_TCP)
120     s = format (s, "tcp ");
121   else if (gho->gho_flags & GHO_F_UDP)
122     s = format (s, "udp ");
123
124   s = format (s, "hdr-sz %u l2-hdr-offset %d "
125               "l3-hdr-offset %d l4-hdr-offset %d "
126               "l4-hdr-sz %u",
127               gho->hdr_sz, gho->l2_hdr_offset, gho->l3_hdr_offset,
128               gho->l4_hdr_offset, gho->l4_hdr_sz);
129
130   return s;
131 }
132
133 static_always_inline void
134 vnet_get_inner_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
135 {
136   if ((gho->gho_flags & GHO_F_TUNNEL)
137       && (gho->gho_flags & GHO_F_OUTER_HDR)
138       && (b0->current_data == gho->outer_l2_hdr_offset))
139     vlib_buffer_advance (b0, gho->outer_hdr_sz);
140 }
141
142 static_always_inline void
143 vnet_get_outer_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
144 {
145   if ((gho->gho_flags & GHO_F_TUNNEL)
146       && (gho->gho_flags & GHO_F_OUTER_HDR)
147       && (b0->current_data == gho->l2_hdr_offset))
148     vlib_buffer_advance (b0, -gho->outer_hdr_sz);
149 }
150
151 static_always_inline void
152 vnet_geneve_inner_header_parser_inline (vlib_buffer_t * b0,
153                                         generic_header_offset_t * gho)
154 {
155   /* not supported yet */
156   if ((gho->gho_flags & GHO_F_GENEVE_TUNNEL) == 0)
157     return;
158
159   ASSERT (0);
160 }
161
162 static_always_inline void
163 vnet_gre_inner_header_parser_inline (vlib_buffer_t * b0,
164                                      generic_header_offset_t * gho)
165 {
166   /* not supported yet */
167   if ((gho->gho_flags & GHO_F_GRE_TUNNEL) == 0)
168     return;
169
170   ASSERT (0);
171 }
172
173 static_always_inline void
174 vnet_ipip_inner_header_parser_inline (vlib_buffer_t * b0,
175                                       generic_header_offset_t * gho)
176 {
177   if ((gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL)) == 0)
178     return;
179
180   u8 l4_proto = 0;
181   u8 l4_hdr_sz = 0;
182
183   gho->outer_l2_hdr_offset = gho->l2_hdr_offset;
184   gho->outer_l3_hdr_offset = gho->l3_hdr_offset;
185   gho->outer_l4_hdr_offset = gho->l4_hdr_offset;
186   gho->outer_l4_hdr_sz = gho->l4_hdr_sz;
187   gho->outer_hdr_sz = gho->hdr_sz;
188
189   gho->l2_hdr_offset = 0;
190   gho->l3_hdr_offset = 0;
191   gho->l4_hdr_offset = 0;
192   gho->l4_hdr_sz = 0;
193   gho->hdr_sz = 0;
194
195   if (gho->gho_flags & GHO_F_IP4)
196     {
197       gho->gho_flags |= GHO_F_OUTER_IP4;
198     }
199   else if (gho->gho_flags & GHO_F_IP6)
200     {
201       gho->gho_flags |= GHO_F_OUTER_IP6;
202     }
203
204   gho->gho_flags &= ~GHO_F_INNER_HDR;
205
206   vnet_get_inner_header (b0, gho);
207
208   gho->l2_hdr_offset = b0->current_data;
209   gho->l3_hdr_offset = 0;
210
211   if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP_TUNNEL))
212     {
213       ip4_header_t *ip4 = (ip4_header_t *) vlib_buffer_get_current (b0);
214       gho->l4_hdr_offset = ip4_header_bytes (ip4);
215       l4_proto = ip4->protocol;
216       gho->gho_flags |= GHO_F_IP4;
217     }
218   else if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP6_TUNNEL))
219     {
220       ip6_header_t *ip6 = (ip6_header_t *) vlib_buffer_get_current (b0);
221       /* FIXME IPv6 EH traversal */
222       gho->l4_hdr_offset = sizeof (ip6_header_t);
223       l4_proto = ip6->protocol;
224       gho->gho_flags |= GHO_F_IP6;
225     }
226   if (l4_proto == IP_PROTOCOL_TCP)
227     {
228       tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
229                                             gho->l4_hdr_offset);
230       l4_hdr_sz = tcp_header_bytes (tcp);
231
232       gho->gho_flags |= GHO_F_TCP;
233
234     }
235   else if (l4_proto == IP_PROTOCOL_UDP)
236     {
237       udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
238                                             gho->l4_hdr_offset);
239       l4_hdr_sz = sizeof (*udp);
240
241       gho->gho_flags |= GHO_F_UDP;
242     }
243
244   gho->l4_hdr_sz = l4_hdr_sz;
245   gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
246
247   vnet_get_outer_header (b0, gho);
248 }
249
250 static_always_inline void
251 vnet_vxlan_inner_header_parser_inline (vlib_buffer_t * b0,
252                                        generic_header_offset_t * gho)
253 {
254   u8 l4_proto = 0;
255   u8 l4_hdr_sz = 0;
256
257   if ((gho->gho_flags & GHO_F_VXLAN_TUNNEL) == 0)
258     return;
259
260   gho->outer_l2_hdr_offset = gho->l2_hdr_offset;
261   gho->outer_l3_hdr_offset = gho->l3_hdr_offset;
262   gho->outer_l4_hdr_offset = gho->l4_hdr_offset;
263   gho->outer_l4_hdr_sz = gho->l4_hdr_sz;
264   gho->outer_hdr_sz = gho->hdr_sz;
265
266   gho->l2_hdr_offset = 0;
267   gho->l3_hdr_offset = 0;
268   gho->l4_hdr_offset = 0;
269   gho->l4_hdr_sz = 0;
270   gho->hdr_sz = 0;
271
272   if (gho->gho_flags & GHO_F_IP4)
273     {
274       gho->gho_flags |= GHO_F_OUTER_IP4;
275     }
276   else if (gho->gho_flags & GHO_F_IP6)
277     {
278       gho->gho_flags |= GHO_F_OUTER_IP6;
279     }
280
281   if (gho->gho_flags & GHO_F_UDP)
282     {
283       gho->gho_flags |= GHO_F_OUTER_UDP;
284     }
285
286   gho->gho_flags &= ~GHO_F_INNER_HDR;
287
288   vnet_get_inner_header (b0, gho);
289
290   gho->l2_hdr_offset = b0->current_data;
291
292   ethernet_header_t *eh = (ethernet_header_t *) vlib_buffer_get_current (b0);
293   u16 ethertype = clib_net_to_host_u16 (eh->type);
294   u16 l2hdr_sz = sizeof (ethernet_header_t);
295
296   if (ethernet_frame_is_tagged (ethertype))
297     {
298       ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
299
300       ethertype = clib_net_to_host_u16 (vlan->type);
301       l2hdr_sz += sizeof (*vlan);
302       if (ethertype == ETHERNET_TYPE_VLAN)
303         {
304           vlan++;
305           ethertype = clib_net_to_host_u16 (vlan->type);
306           l2hdr_sz += sizeof (*vlan);
307         }
308     }
309
310   gho->l3_hdr_offset = l2hdr_sz;
311
312   if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4))
313     {
314       ip4_header_t *ip4 =
315         (ip4_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset);
316       gho->l4_hdr_offset = gho->l3_hdr_offset + ip4_header_bytes (ip4);
317       l4_proto = ip4->protocol;
318       gho->gho_flags |= GHO_F_IP4;
319     }
320   else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6))
321     {
322       ip6_header_t *ip6 =
323         (ip6_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset);
324       /* FIXME IPv6 EH traversal */
325       gho->l4_hdr_offset = gho->l3_hdr_offset + sizeof (ip6_header_t);
326       l4_proto = ip6->protocol;
327       gho->gho_flags |= GHO_F_IP6;
328     }
329   if (l4_proto == IP_PROTOCOL_TCP)
330     {
331       tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
332                                             gho->l4_hdr_offset);
333       l4_hdr_sz = tcp_header_bytes (tcp);
334
335       gho->gho_flags |= GHO_F_TCP;
336
337     }
338   else if (l4_proto == IP_PROTOCOL_UDP)
339     {
340       udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
341                                             gho->l4_hdr_offset);
342       l4_hdr_sz = sizeof (*udp);
343
344       gho->gho_flags |= GHO_F_UDP;
345     }
346
347   gho->l4_hdr_sz = l4_hdr_sz;
348   gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
349
350   vnet_get_outer_header (b0, gho);
351 }
352
353 static_always_inline void
354 vnet_generic_inner_header_parser_inline (vlib_buffer_t * b0,
355                                          generic_header_offset_t * gho)
356 {
357
358   if (gho->gho_flags & GHO_F_VXLAN_TUNNEL)
359     vnet_vxlan_inner_header_parser_inline (b0, gho);
360   else if (gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL))
361     vnet_ipip_inner_header_parser_inline (b0, gho);
362   else if (gho->gho_flags & GHO_F_GRE_TUNNEL)
363     vnet_gre_inner_header_parser_inline (b0, gho);
364   else if (gho->gho_flags & GHO_F_GENEVE_TUNNEL)
365     vnet_geneve_inner_header_parser_inline (b0, gho);
366 }
367
368 static_always_inline void
369 vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
370                                          generic_header_offset_t * gho,
371                                          int is_l2, int is_ip4, int is_ip6)
372 {
373   u8 l4_proto = 0;
374   u8 l4_hdr_sz = 0;
375   u16 ethertype = 0;
376   u16 l2hdr_sz = 0;
377
378   ASSERT (!(is_ip4 && is_ip6));
379
380   if (is_l2)
381     {
382       ethernet_header_t *eh =
383         (ethernet_header_t *) vlib_buffer_get_current (b0);
384       ethertype = clib_net_to_host_u16 (eh->type);
385       l2hdr_sz = sizeof (ethernet_header_t);
386
387       if (ethernet_frame_is_tagged (ethertype))
388         {
389           ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
390
391           ethertype = clib_net_to_host_u16 (vlan->type);
392           l2hdr_sz += sizeof (*vlan);
393           if (ethertype == ETHERNET_TYPE_VLAN)
394             {
395               vlan++;
396               ethertype = clib_net_to_host_u16 (vlan->type);
397               l2hdr_sz += sizeof (*vlan);
398             }
399         }
400     }
401   else
402     l2hdr_sz = vnet_buffer (b0)->ip.save_rewrite_length;
403
404   gho->l2_hdr_offset = b0->current_data;
405   gho->l3_hdr_offset = l2hdr_sz;
406
407   if (PREDICT_TRUE (is_ip4))
408     {
409       ip4_header_t *ip4 =
410         (ip4_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
411       gho->l4_hdr_offset = l2hdr_sz + ip4_header_bytes (ip4);
412       l4_proto = ip4->protocol;
413       gho->gho_flags |= GHO_F_IP4;
414     }
415   else if (PREDICT_TRUE (is_ip6))
416     {
417       ip6_header_t *ip6 =
418         (ip6_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
419       /* FIXME IPv6 EH traversal */
420       gho->l4_hdr_offset = l2hdr_sz + sizeof (ip6_header_t);
421       l4_proto = ip6->protocol;
422       gho->gho_flags |= GHO_F_IP6;
423     }
424   if (l4_proto == IP_PROTOCOL_TCP)
425     {
426       tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
427                                             gho->l4_hdr_offset);
428       l4_hdr_sz = tcp_header_bytes (tcp);
429
430       gho->gho_flags |= GHO_F_TCP;
431     }
432   else if (l4_proto == IP_PROTOCOL_UDP)
433     {
434       udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
435                                             gho->l4_hdr_offset);
436       l4_hdr_sz = sizeof (*udp);
437
438       gho->gho_flags |= GHO_F_UDP;
439
440       if (UDP_DST_PORT_vxlan == clib_net_to_host_u16 (udp->dst_port))
441         {
442           gho->gho_flags |= GHO_F_VXLAN_TUNNEL;
443           gho->hdr_sz += sizeof (vxlan_header_t);
444         }
445       else if (UDP_DST_PORT_geneve == clib_net_to_host_u16 (udp->dst_port))
446         {
447           gho->gho_flags |= GHO_F_GENEVE_TUNNEL;
448         }
449     }
450   else if (l4_proto == IP_PROTOCOL_IP_IN_IP)
451     {
452       l4_hdr_sz = 0;
453       gho->gho_flags |= GHO_F_IPIP_TUNNEL;
454     }
455   else if (l4_proto == IP_PROTOCOL_IPV6)
456     {
457       l4_hdr_sz = 0;
458       gho->gho_flags |= GHO_F_IPIP6_TUNNEL;
459     }
460   else if (l4_proto == IP_PROTOCOL_GRE)
461     {
462       l4_hdr_sz = 0;
463       gho->gho_flags |= GHO_F_GRE_TUNNEL;
464     }
465
466   gho->l4_hdr_sz = l4_hdr_sz;
467   gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
468 }
469
470 static_always_inline void
471 vnet_generic_header_offset_parser (vlib_buffer_t * b0,
472                                    generic_header_offset_t * gho, int is_l2,
473                                    int is_ip4, int is_ip6)
474 {
475   vnet_generic_outer_header_parser_inline (b0, gho, is_l2, is_ip4, is_ip6);
476
477   if (gho->gho_flags & GHO_F_TUNNEL)
478     {
479       vnet_generic_inner_header_parser_inline (b0, gho);
480     }
481 }
482
483 #endif /* included_hdr_offset_parser_h */
484
485 /*
486  * fd.io coding-style-patch-verification: ON
487  *
488  * Local Variables:
489  * eval: (c-set-style "gnu")
490  * End:
491  */