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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #ifndef included_hdr_offset_parser_h
17 #define included_hdr_offset_parser_h
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>
27 #define VXLAN_HEADER_SIZE 8
29 #define foreach_gho_flag \
41 _( 11, IPIP6_TUNNEL) \
44 typedef enum gho_flag_t_
46 #define _(bit, name) GHO_F_##name = (1 << bit),
51 #define GHO_F_TUNNEL (GHO_F_VXLAN_TUNNEL | \
52 GHO_F_GENEVE_TUNNEL | \
54 GHO_F_IPIP6_TUNNEL | \
57 #define GHO_F_OUTER_HDR (GHO_F_OUTER_IP4 | \
62 #define GHO_F_INNER_HDR (GHO_F_IP4 | \
69 i16 outer_l2_hdr_offset;
70 i16 outer_l3_hdr_offset;
71 i16 outer_l4_hdr_offset;
80 } generic_header_offset_t;
82 static_always_inline u8 *
83 format_generic_header_offset (u8 * s, va_list * args)
85 generic_header_offset_t *gho = va_arg (*args, generic_header_offset_t *);
87 if (gho->gho_flags & GHO_F_TUNNEL)
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 ");
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 ");
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 ");
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);
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 ");
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 ");
126 s = format (s, "hdr-sz %u l2-hdr-offset %d "
127 "l3-hdr-offset %d l4-hdr-offset %d "
129 gho->hdr_sz, gho->l2_hdr_offset, gho->l3_hdr_offset,
130 gho->l4_hdr_offset, gho->l4_hdr_sz);
135 static_always_inline void
136 vnet_get_inner_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
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);
144 static_always_inline void
145 vnet_get_outer_header (vlib_buffer_t * b0, generic_header_offset_t * gho)
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);
153 static_always_inline void
154 vnet_geneve_inner_header_parser_inline (vlib_buffer_t * b0,
155 generic_header_offset_t * gho)
157 /* not supported yet */
158 if ((gho->gho_flags & GHO_F_GENEVE_TUNNEL) == 0)
162 static_always_inline void
163 vnet_gre_inner_header_parser_inline (vlib_buffer_t * b0,
164 generic_header_offset_t * gho)
166 /* not supported yet */
167 if ((gho->gho_flags & GHO_F_GRE_TUNNEL) == 0)
171 static_always_inline void
172 vnet_ipip_inner_header_parser_inline (vlib_buffer_t * b0,
173 generic_header_offset_t * gho)
175 if ((gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL)) == 0)
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;
187 gho->l2_hdr_offset = 0;
188 gho->l3_hdr_offset = 0;
189 gho->l4_hdr_offset = 0;
193 if (gho->gho_flags & GHO_F_IP4)
195 gho->gho_flags |= GHO_F_OUTER_IP4;
197 else if (gho->gho_flags & GHO_F_IP6)
199 gho->gho_flags |= GHO_F_OUTER_IP6;
202 gho->gho_flags &= ~GHO_F_INNER_HDR;
204 vnet_get_inner_header (b0, gho);
206 gho->l2_hdr_offset = b0->current_data;
207 gho->l3_hdr_offset = 0;
209 if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP_TUNNEL))
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;
216 else if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP6_TUNNEL))
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;
224 if (l4_proto == IP_PROTOCOL_TCP)
226 tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
228 l4_hdr_sz = tcp_header_bytes (tcp);
230 gho->gho_flags |= GHO_F_TCP;
233 else if (l4_proto == IP_PROTOCOL_UDP)
235 udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
237 l4_hdr_sz = sizeof (*udp);
239 gho->gho_flags |= GHO_F_UDP;
242 gho->l4_hdr_sz = l4_hdr_sz;
243 gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
245 vnet_get_outer_header (b0, gho);
248 static_always_inline void
249 vnet_vxlan_inner_header_parser_inline (vlib_buffer_t * b0,
250 generic_header_offset_t * gho)
255 if ((gho->gho_flags & GHO_F_VXLAN_TUNNEL) == 0)
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;
264 gho->l2_hdr_offset = 0;
265 gho->l3_hdr_offset = 0;
266 gho->l4_hdr_offset = 0;
270 if (gho->gho_flags & GHO_F_IP4)
272 gho->gho_flags |= GHO_F_OUTER_IP4;
274 else if (gho->gho_flags & GHO_F_IP6)
276 gho->gho_flags |= GHO_F_OUTER_IP6;
279 if (gho->gho_flags & GHO_F_UDP)
281 gho->gho_flags |= GHO_F_OUTER_UDP;
284 gho->gho_flags &= ~GHO_F_INNER_HDR;
286 vnet_get_inner_header (b0, gho);
288 gho->l2_hdr_offset = b0->current_data;
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);
294 if (ethernet_frame_is_tagged (ethertype))
296 ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
298 ethertype = clib_net_to_host_u16 (vlan->type);
299 l2hdr_sz += sizeof (*vlan);
300 if (ethertype == ETHERNET_TYPE_VLAN)
303 ethertype = clib_net_to_host_u16 (vlan->type);
304 l2hdr_sz += sizeof (*vlan);
308 gho->l3_hdr_offset = l2hdr_sz;
310 if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_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;
318 else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_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;
327 if (l4_proto == IP_PROTOCOL_TCP)
329 tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
331 l4_hdr_sz = tcp_header_bytes (tcp);
333 gho->gho_flags |= GHO_F_TCP;
336 else if (l4_proto == IP_PROTOCOL_UDP)
338 udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
340 l4_hdr_sz = sizeof (*udp);
342 gho->gho_flags |= GHO_F_UDP;
345 gho->l4_hdr_sz = l4_hdr_sz;
346 gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
348 vnet_get_outer_header (b0, gho);
351 static_always_inline void
352 vnet_generic_inner_header_parser_inline (vlib_buffer_t * b0,
353 generic_header_offset_t * gho)
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);
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)
376 ASSERT (!(is_ip4 && is_ip6));
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);
385 if (ethernet_frame_is_tagged (ethertype))
387 ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
389 ethertype = clib_net_to_host_u16 (vlan->type);
390 l2hdr_sz += sizeof (*vlan);
391 if (ethertype == ETHERNET_TYPE_VLAN)
394 ethertype = clib_net_to_host_u16 (vlan->type);
395 l2hdr_sz += sizeof (*vlan);
400 l2hdr_sz = vnet_buffer (b0)->ip.save_rewrite_length;
402 gho->l2_hdr_offset = b0->current_data;
403 gho->l3_hdr_offset = l2hdr_sz;
405 if (PREDICT_TRUE (is_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;
413 else if (PREDICT_TRUE (is_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;
422 if (l4_proto == IP_PROTOCOL_TCP)
424 tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
426 l4_hdr_sz = tcp_header_bytes (tcp);
428 gho->gho_flags |= GHO_F_TCP;
430 else if (l4_proto == IP_PROTOCOL_UDP)
432 udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
434 l4_hdr_sz = sizeof (*udp);
436 gho->gho_flags |= GHO_F_UDP;
438 if (UDP_DST_PORT_vxlan == clib_net_to_host_u16 (udp->dst_port))
440 gho->gho_flags |= GHO_F_VXLAN_TUNNEL;
441 gho->hdr_sz += VXLAN_HEADER_SIZE;
443 else if (UDP_DST_PORT_geneve == clib_net_to_host_u16 (udp->dst_port))
445 gho->gho_flags |= GHO_F_GENEVE_TUNNEL;
448 else if (l4_proto == IP_PROTOCOL_IP_IN_IP)
451 gho->gho_flags |= GHO_F_IPIP_TUNNEL;
453 else if (l4_proto == IP_PROTOCOL_IPV6)
456 gho->gho_flags |= GHO_F_IPIP6_TUNNEL;
458 else if (l4_proto == IP_PROTOCOL_GRE)
461 gho->gho_flags |= GHO_F_GRE_TUNNEL;
464 gho->l4_hdr_sz = l4_hdr_sz;
465 gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
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)
473 vnet_generic_outer_header_parser_inline (b0, gho, is_l2, is_ip4, is_ip6);
475 if (gho->gho_flags & GHO_F_TUNNEL)
477 vnet_generic_inner_header_parser_inline (b0, gho);
481 #endif /* included_hdr_offset_parser_h */
484 * fd.io coding-style-patch-verification: ON
487 * eval: (c-set-style "gnu")