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