blob: 08037f57ea069a45b98d50b1bdbb302b32aeba5d [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>
Steven Luong48972572022-10-18 08:31:20 -070026
27#define VXLAN_HEADER_SIZE 8
Mohsin Kazmi0b042092020-04-17 16:50:56 +000028
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) \
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +020041 _( 11, IPIP6_TUNNEL) \
42 _( 12, GENEVE_TUNNEL)
Mohsin Kazmi0b042092020-04-17 16:50:56 +000043
44typedef 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
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +020051#define GHO_F_TUNNEL (GHO_F_VXLAN_TUNNEL | \
52 GHO_F_GENEVE_TUNNEL | \
53 GHO_F_IPIP_TUNNEL | \
54 GHO_F_IPIP6_TUNNEL | \
Mohsin Kazmi0b042092020-04-17 16:50:56 +000055 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
67typedef 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
82static_always_inline u8 *
83format_generic_header_offset (u8 * s, va_list * args)
84{
85 generic_header_offset_t *gho = va_arg (*args, generic_header_offset_t *);
86
Mohsin Kazmi0b042092020-04-17 16:50:56 +000087 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
135static_always_inline void
136vnet_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
144static_always_inline void
145vnet_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
153static_always_inline void
154vnet_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;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000160}
161
162static_always_inline void
163vnet_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;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000169}
170
171static_always_inline void
172vnet_ipip_inner_header_parser_inline (vlib_buffer_t * b0,
173 generic_header_offset_t * gho)
174{
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200175 if ((gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL)) == 0)
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000176 return;
177
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200178 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);
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000246}
247
248static_always_inline void
249vnet_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
351static_always_inline void
352vnet_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);
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200358 else if (gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL))
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000359 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
366static_always_inline void
367vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200368 generic_header_offset_t * gho,
369 int is_l2, int is_ip4, int is_ip6)
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000370{
371 u8 l4_proto = 0;
372 u8 l4_hdr_sz = 0;
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200373 u16 ethertype = 0;
374 u16 l2hdr_sz = 0;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000375
Vladimir Isaev698eb872020-05-21 16:34:17 +0300376 ASSERT (!(is_ip4 && is_ip6));
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000377
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200378 if (is_l2)
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000379 {
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200380 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);
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000384
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200385 if (ethernet_frame_is_tagged (ethertype))
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000386 {
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200387 ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
388
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000389 ethertype = clib_net_to_host_u16 (vlan->type);
390 l2hdr_sz += sizeof (*vlan);
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200391 if (ethertype == ETHERNET_TYPE_VLAN)
392 {
393 vlan++;
394 ethertype = clib_net_to_host_u16 (vlan->type);
395 l2hdr_sz += sizeof (*vlan);
396 }
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000397 }
398 }
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200399 else
400 l2hdr_sz = vnet_buffer (b0)->ip.save_rewrite_length;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000401
402 gho->l2_hdr_offset = b0->current_data;
403 gho->l3_hdr_offset = l2hdr_sz;
404
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200405 if (PREDICT_TRUE (is_ip4))
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000406 {
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 }
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200413 else if (PREDICT_TRUE (is_ip6))
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000414 {
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;
Steven Luong48972572022-10-18 08:31:20 -0700441 gho->hdr_sz += VXLAN_HEADER_SIZE;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000442 }
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 }
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200448 else if (l4_proto == IP_PROTOCOL_IP_IN_IP)
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000449 {
450 l4_hdr_sz = 0;
451 gho->gho_flags |= GHO_F_IPIP_TUNNEL;
452 }
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200453 else if (l4_proto == IP_PROTOCOL_IPV6)
454 {
455 l4_hdr_sz = 0;
456 gho->gho_flags |= GHO_F_IPIP6_TUNNEL;
457 }
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000458 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
468static_always_inline void
469vnet_generic_header_offset_parser (vlib_buffer_t * b0,
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200470 generic_header_offset_t * gho, int is_l2,
471 int is_ip4, int is_ip6)
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000472{
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200473 vnet_generic_outer_header_parser_inline (b0, gho, is_l2, is_ip4, is_ip6);
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000474
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 */