Line data Source code
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 780 : format_generic_header_offset (u8 * s, va_list * args)
84 : {
85 780 : generic_header_offset_t *gho = va_arg (*args, generic_header_offset_t *);
86 :
87 780 : if (gho->gho_flags & GHO_F_TUNNEL)
88 : {
89 50 : if (gho->gho_flags & GHO_F_VXLAN_TUNNEL)
90 25 : s = format (s, "vxlan-tunnel ");
91 25 : else if (gho->gho_flags & GHO_F_IPIP_TUNNEL)
92 10 : s = format (s, "ipip-tunnel ");
93 15 : else if (gho->gho_flags & GHO_F_GRE_TUNNEL)
94 0 : s = format (s, "gre-tunnel ");
95 15 : else if (gho->gho_flags & GHO_F_GENEVE_TUNNEL)
96 0 : s = format (s, "geneve-tunnel ");
97 :
98 50 : if (gho->gho_flags & GHO_F_OUTER_IP4)
99 20 : s = format (s, "outer-ipv4 ");
100 30 : else if (gho->gho_flags & GHO_F_OUTER_IP6)
101 30 : s = format (s, "outer-ipv6 ");
102 :
103 50 : if (gho->gho_flags & GHO_F_OUTER_UDP)
104 25 : s = format (s, "outer-udp ");
105 25 : else if (gho->gho_flags & GHO_F_OUTER_TCP)
106 0 : s = format (s, "outer-tcp ");
107 :
108 50 : 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 50 : gho->outer_hdr_sz, gho->outer_l2_hdr_offset,
112 50 : gho->outer_l3_hdr_offset, gho->outer_l4_hdr_offset,
113 50 : gho->outer_l4_hdr_sz);
114 : }
115 :
116 780 : if (gho->gho_flags & GHO_F_IP4)
117 682 : s = format (s, "ipv4 ");
118 98 : else if (gho->gho_flags & GHO_F_IP6)
119 98 : s = format (s, "ipv6 ");
120 :
121 780 : if (gho->gho_flags & GHO_F_TCP)
122 780 : s = format (s, "tcp ");
123 0 : else if (gho->gho_flags & GHO_F_UDP)
124 0 : s = format (s, "udp ");
125 :
126 780 : 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 780 : gho->hdr_sz, gho->l2_hdr_offset, gho->l3_hdr_offset,
130 780 : gho->l4_hdr_offset, gho->l4_hdr_sz);
131 :
132 780 : return s;
133 : }
134 :
135 : static_always_inline void
136 80 : vnet_get_inner_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
137 : {
138 80 : if ((gho->gho_flags & GHO_F_TUNNEL)
139 80 : && (gho->gho_flags & GHO_F_OUTER_HDR)
140 80 : && (b0->current_data == gho->outer_l2_hdr_offset))
141 80 : vlib_buffer_advance (b0, gho->outer_hdr_sz);
142 80 : }
143 :
144 : static_always_inline void
145 80 : vnet_get_outer_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
146 : {
147 80 : if ((gho->gho_flags & GHO_F_TUNNEL)
148 80 : && (gho->gho_flags & GHO_F_OUTER_HDR)
149 80 : && (b0->current_data == gho->l2_hdr_offset))
150 80 : vlib_buffer_advance (b0, -gho->outer_hdr_sz);
151 80 : }
152 :
153 : static_always_inline void
154 0 : vnet_geneve_inner_header_parser_inline (vlib_buffer_t * b0,
155 : generic_header_offset_t * gho)
156 : {
157 : /* not supported yet */
158 0 : if ((gho->gho_flags & GHO_F_GENEVE_TUNNEL) == 0)
159 0 : return;
160 : }
161 :
162 : static_always_inline void
163 0 : vnet_gre_inner_header_parser_inline (vlib_buffer_t * b0,
164 : generic_header_offset_t * gho)
165 : {
166 : /* not supported yet */
167 0 : if ((gho->gho_flags & GHO_F_GRE_TUNNEL) == 0)
168 0 : return;
169 : }
170 :
171 : static_always_inline void
172 40 : vnet_ipip_inner_header_parser_inline (vlib_buffer_t * b0,
173 : generic_header_offset_t * gho)
174 : {
175 40 : if ((gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL)) == 0)
176 0 : return;
177 :
178 40 : u8 l4_proto = 0;
179 40 : u8 l4_hdr_sz = 0;
180 :
181 40 : gho->outer_l2_hdr_offset = gho->l2_hdr_offset;
182 40 : gho->outer_l3_hdr_offset = gho->l3_hdr_offset;
183 40 : gho->outer_l4_hdr_offset = gho->l4_hdr_offset;
184 40 : gho->outer_l4_hdr_sz = gho->l4_hdr_sz;
185 40 : gho->outer_hdr_sz = gho->hdr_sz;
186 :
187 40 : gho->l2_hdr_offset = 0;
188 40 : gho->l3_hdr_offset = 0;
189 40 : gho->l4_hdr_offset = 0;
190 40 : gho->l4_hdr_sz = 0;
191 40 : gho->hdr_sz = 0;
192 :
193 40 : if (gho->gho_flags & GHO_F_IP4)
194 : {
195 20 : gho->gho_flags |= GHO_F_OUTER_IP4;
196 : }
197 20 : else if (gho->gho_flags & GHO_F_IP6)
198 : {
199 20 : gho->gho_flags |= GHO_F_OUTER_IP6;
200 : }
201 :
202 40 : gho->gho_flags &= ~GHO_F_INNER_HDR;
203 :
204 40 : vnet_get_inner_header (b0, gho);
205 :
206 40 : gho->l2_hdr_offset = b0->current_data;
207 40 : gho->l3_hdr_offset = 0;
208 :
209 40 : if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP_TUNNEL))
210 : {
211 20 : ip4_header_t *ip4 = (ip4_header_t *) vlib_buffer_get_current (b0);
212 20 : gho->l4_hdr_offset = ip4_header_bytes (ip4);
213 20 : l4_proto = ip4->protocol;
214 20 : gho->gho_flags |= GHO_F_IP4;
215 : }
216 20 : else if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP6_TUNNEL))
217 : {
218 20 : ip6_header_t *ip6 = (ip6_header_t *) vlib_buffer_get_current (b0);
219 : /* FIXME IPv6 EH traversal */
220 20 : gho->l4_hdr_offset = sizeof (ip6_header_t);
221 20 : l4_proto = ip6->protocol;
222 20 : gho->gho_flags |= GHO_F_IP6;
223 : }
224 40 : if (l4_proto == IP_PROTOCOL_TCP)
225 : {
226 40 : tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
227 40 : gho->l4_hdr_offset);
228 40 : l4_hdr_sz = tcp_header_bytes (tcp);
229 :
230 40 : gho->gho_flags |= GHO_F_TCP;
231 :
232 : }
233 0 : else if (l4_proto == IP_PROTOCOL_UDP)
234 : {
235 0 : udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
236 0 : gho->l4_hdr_offset);
237 0 : l4_hdr_sz = sizeof (*udp);
238 :
239 0 : gho->gho_flags |= GHO_F_UDP;
240 : }
241 :
242 40 : gho->l4_hdr_sz = l4_hdr_sz;
243 40 : gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
244 :
245 40 : vnet_get_outer_header (b0, gho);
246 : }
247 :
248 : static_always_inline void
249 40 : vnet_vxlan_inner_header_parser_inline (vlib_buffer_t * b0,
250 : generic_header_offset_t * gho)
251 : {
252 40 : u8 l4_proto = 0;
253 40 : u8 l4_hdr_sz = 0;
254 :
255 40 : if ((gho->gho_flags & GHO_F_VXLAN_TUNNEL) == 0)
256 0 : return;
257 :
258 40 : gho->outer_l2_hdr_offset = gho->l2_hdr_offset;
259 40 : gho->outer_l3_hdr_offset = gho->l3_hdr_offset;
260 40 : gho->outer_l4_hdr_offset = gho->l4_hdr_offset;
261 40 : gho->outer_l4_hdr_sz = gho->l4_hdr_sz;
262 40 : gho->outer_hdr_sz = gho->hdr_sz;
263 :
264 40 : gho->l2_hdr_offset = 0;
265 40 : gho->l3_hdr_offset = 0;
266 40 : gho->l4_hdr_offset = 0;
267 40 : gho->l4_hdr_sz = 0;
268 40 : gho->hdr_sz = 0;
269 :
270 40 : if (gho->gho_flags & GHO_F_IP4)
271 : {
272 20 : gho->gho_flags |= GHO_F_OUTER_IP4;
273 : }
274 20 : else if (gho->gho_flags & GHO_F_IP6)
275 : {
276 20 : gho->gho_flags |= GHO_F_OUTER_IP6;
277 : }
278 :
279 40 : if (gho->gho_flags & GHO_F_UDP)
280 : {
281 40 : gho->gho_flags |= GHO_F_OUTER_UDP;
282 : }
283 :
284 40 : gho->gho_flags &= ~GHO_F_INNER_HDR;
285 :
286 40 : vnet_get_inner_header (b0, gho);
287 :
288 40 : gho->l2_hdr_offset = b0->current_data;
289 :
290 40 : ethernet_header_t *eh = (ethernet_header_t *) vlib_buffer_get_current (b0);
291 40 : u16 ethertype = clib_net_to_host_u16 (eh->type);
292 40 : u16 l2hdr_sz = sizeof (ethernet_header_t);
293 :
294 40 : if (ethernet_frame_is_tagged (ethertype))
295 : {
296 0 : ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
297 :
298 0 : ethertype = clib_net_to_host_u16 (vlan->type);
299 0 : l2hdr_sz += sizeof (*vlan);
300 0 : if (ethertype == ETHERNET_TYPE_VLAN)
301 : {
302 0 : vlan++;
303 0 : ethertype = clib_net_to_host_u16 (vlan->type);
304 0 : l2hdr_sz += sizeof (*vlan);
305 : }
306 : }
307 :
308 40 : gho->l3_hdr_offset = l2hdr_sz;
309 :
310 40 : if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4))
311 : {
312 20 : ip4_header_t *ip4 =
313 20 : (ip4_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset);
314 20 : gho->l4_hdr_offset = gho->l3_hdr_offset + ip4_header_bytes (ip4);
315 20 : l4_proto = ip4->protocol;
316 20 : gho->gho_flags |= GHO_F_IP4;
317 : }
318 20 : else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6))
319 : {
320 20 : ip6_header_t *ip6 =
321 20 : (ip6_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset);
322 : /* FIXME IPv6 EH traversal */
323 20 : gho->l4_hdr_offset = gho->l3_hdr_offset + sizeof (ip6_header_t);
324 20 : l4_proto = ip6->protocol;
325 20 : gho->gho_flags |= GHO_F_IP6;
326 : }
327 40 : if (l4_proto == IP_PROTOCOL_TCP)
328 : {
329 40 : tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
330 40 : gho->l4_hdr_offset);
331 40 : l4_hdr_sz = tcp_header_bytes (tcp);
332 :
333 40 : gho->gho_flags |= GHO_F_TCP;
334 :
335 : }
336 0 : else if (l4_proto == IP_PROTOCOL_UDP)
337 : {
338 0 : udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
339 0 : gho->l4_hdr_offset);
340 0 : l4_hdr_sz = sizeof (*udp);
341 :
342 0 : gho->gho_flags |= GHO_F_UDP;
343 : }
344 :
345 40 : gho->l4_hdr_sz = l4_hdr_sz;
346 40 : gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
347 :
348 40 : vnet_get_outer_header (b0, gho);
349 : }
350 :
351 : static_always_inline void
352 80 : vnet_generic_inner_header_parser_inline (vlib_buffer_t * b0,
353 : generic_header_offset_t * gho)
354 : {
355 :
356 80 : if (gho->gho_flags & GHO_F_VXLAN_TUNNEL)
357 40 : vnet_vxlan_inner_header_parser_inline (b0, gho);
358 40 : else if (gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL))
359 40 : vnet_ipip_inner_header_parser_inline (b0, gho);
360 0 : else if (gho->gho_flags & GHO_F_GRE_TUNNEL)
361 0 : vnet_gre_inner_header_parser_inline (b0, gho);
362 0 : else if (gho->gho_flags & GHO_F_GENEVE_TUNNEL)
363 0 : vnet_geneve_inner_header_parser_inline (b0, gho);
364 80 : }
365 :
366 : static_always_inline void
367 51692502 : 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 51692502 : u8 l4_proto = 0;
372 51692502 : u8 l4_hdr_sz = 0;
373 51692502 : u16 ethertype = 0;
374 51692502 : u16 l2hdr_sz = 0;
375 :
376 51692502 : ASSERT (!(is_ip4 && is_ip6));
377 :
378 51692502 : if (is_l2)
379 : {
380 : ethernet_header_t *eh =
381 40261305 : (ethernet_header_t *) vlib_buffer_get_current (b0);
382 40261305 : ethertype = clib_net_to_host_u16 (eh->type);
383 40261305 : l2hdr_sz = sizeof (ethernet_header_t);
384 :
385 40261305 : if (ethernet_frame_is_tagged (ethertype))
386 : {
387 0 : ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
388 :
389 0 : ethertype = clib_net_to_host_u16 (vlan->type);
390 0 : l2hdr_sz += sizeof (*vlan);
391 0 : if (ethertype == ETHERNET_TYPE_VLAN)
392 : {
393 0 : vlan++;
394 0 : ethertype = clib_net_to_host_u16 (vlan->type);
395 0 : l2hdr_sz += sizeof (*vlan);
396 : }
397 : }
398 : }
399 : else
400 11431197 : l2hdr_sz = vnet_buffer (b0)->ip.save_rewrite_length;
401 :
402 51692502 : gho->l2_hdr_offset = b0->current_data;
403 51692502 : gho->l3_hdr_offset = l2hdr_sz;
404 :
405 51692502 : if (PREDICT_TRUE (is_ip4))
406 : {
407 29724179 : ip4_header_t *ip4 =
408 29724179 : (ip4_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
409 29724179 : gho->l4_hdr_offset = l2hdr_sz + ip4_header_bytes (ip4);
410 29724179 : l4_proto = ip4->protocol;
411 29724179 : gho->gho_flags |= GHO_F_IP4;
412 : }
413 21968223 : else if (PREDICT_TRUE (is_ip6))
414 : {
415 21968223 : ip6_header_t *ip6 =
416 21968223 : (ip6_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
417 : /* FIXME IPv6 EH traversal */
418 21968223 : gho->l4_hdr_offset = l2hdr_sz + sizeof (ip6_header_t);
419 21968223 : l4_proto = ip6->protocol;
420 21968223 : gho->gho_flags |= GHO_F_IP6;
421 : }
422 51692502 : if (l4_proto == IP_PROTOCOL_TCP)
423 : {
424 51692018 : tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
425 51692018 : gho->l4_hdr_offset);
426 51692018 : l4_hdr_sz = tcp_header_bytes (tcp);
427 :
428 51692018 : gho->gho_flags |= GHO_F_TCP;
429 : }
430 478 : else if (l4_proto == IP_PROTOCOL_UDP)
431 : {
432 40 : udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
433 40 : gho->l4_hdr_offset);
434 40 : l4_hdr_sz = sizeof (*udp);
435 :
436 40 : gho->gho_flags |= GHO_F_UDP;
437 :
438 40 : if (UDP_DST_PORT_vxlan == clib_net_to_host_u16 (udp->dst_port))
439 : {
440 40 : gho->gho_flags |= GHO_F_VXLAN_TUNNEL;
441 40 : gho->hdr_sz += VXLAN_HEADER_SIZE;
442 : }
443 0 : else if (UDP_DST_PORT_geneve == clib_net_to_host_u16 (udp->dst_port))
444 : {
445 0 : gho->gho_flags |= GHO_F_GENEVE_TUNNEL;
446 : }
447 : }
448 438 : else if (l4_proto == IP_PROTOCOL_IP_IN_IP)
449 : {
450 20 : l4_hdr_sz = 0;
451 20 : gho->gho_flags |= GHO_F_IPIP_TUNNEL;
452 : }
453 418 : else if (l4_proto == IP_PROTOCOL_IPV6)
454 : {
455 20 : l4_hdr_sz = 0;
456 20 : gho->gho_flags |= GHO_F_IPIP6_TUNNEL;
457 : }
458 398 : else if (l4_proto == IP_PROTOCOL_GRE)
459 : {
460 0 : l4_hdr_sz = 0;
461 0 : gho->gho_flags |= GHO_F_GRE_TUNNEL;
462 : }
463 :
464 51692502 : gho->l4_hdr_sz = l4_hdr_sz;
465 51692502 : gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
466 51692502 : }
467 :
468 : static_always_inline void
469 51692502 : 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 51692502 : vnet_generic_outer_header_parser_inline (b0, gho, is_l2, is_ip4, is_ip6);
474 :
475 51692502 : if (gho->gho_flags & GHO_F_TUNNEL)
476 : {
477 80 : vnet_generic_inner_header_parser_inline (b0, gho);
478 : }
479 51692502 : }
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 : */
|