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