Line data Source code
1 : /*
2 : * gre.c: gre
3 : *
4 : * Copyright (c) 2012 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/vnet.h>
19 : #include <gre/gre.h>
20 : #include <vnet/adj/adj_midchain.h>
21 : #include <vnet/tunnel/tunnel_dp.h>
22 : #include <vpp/app/version.h>
23 : #include <vnet/plugin/plugin.h>
24 :
25 : extern gre_main_t gre_main;
26 :
27 : #ifndef CLIB_MARCH_VARIANT
28 : gre_main_t gre_main;
29 :
30 : typedef struct
31 : {
32 : union
33 : {
34 : ip4_and_gre_header_t ip4_and_gre;
35 : u64 as_u64[3];
36 : };
37 : } ip4_and_gre_union_t;
38 :
39 : typedef struct
40 : {
41 : union
42 : {
43 : ip6_and_gre_header_t ip6_and_gre;
44 : u64 as_u64[3];
45 : };
46 : } ip6_and_gre_union_t;
47 : #endif /* CLIB_MARCH_VARIANT */
48 :
49 : /* Packet trace structure */
50 : typedef struct
51 : {
52 : /* Tunnel-id / index in tunnel vector */
53 : u32 tunnel_id;
54 :
55 : /* pkt length */
56 : u32 length;
57 :
58 : /* tunnel ip addresses */
59 : ip46_address_t src;
60 : ip46_address_t dst;
61 : } gre_tx_trace_t;
62 :
63 : extern u8 *format_gre_tx_trace (u8 *s, va_list *args);
64 :
65 : #ifndef CLIB_MARCH_VARIANT
66 : u8 *
67 1699 : format_gre_tx_trace (u8 *s, va_list *args)
68 : {
69 1699 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70 1699 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71 1699 : gre_tx_trace_t *t = va_arg (*args, gre_tx_trace_t *);
72 :
73 1699 : s = format (s, "GRE: tunnel %d len %d src %U dst %U", t->tunnel_id,
74 : t->length, format_ip46_address, &t->src, IP46_TYPE_ANY,
75 : format_ip46_address, &t->dst, IP46_TYPE_ANY);
76 1699 : return s;
77 : }
78 :
79 : u8 *
80 16527 : format_gre_protocol (u8 *s, va_list *args)
81 : {
82 16527 : gre_protocol_t p = va_arg (*args, u32);
83 16527 : gre_main_t *gm = &gre_main;
84 16527 : gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
85 :
86 16527 : if (pi)
87 16524 : s = format (s, "%s", pi->name);
88 : else
89 3 : s = format (s, "0x%04x", p);
90 :
91 16527 : return s;
92 : }
93 :
94 : u8 *
95 16527 : format_gre_header_with_length (u8 *s, va_list *args)
96 : {
97 16527 : gre_main_t *gm = &gre_main;
98 16527 : gre_header_t *h = va_arg (*args, gre_header_t *);
99 16527 : u32 max_header_bytes = va_arg (*args, u32);
100 16527 : gre_protocol_t p = clib_net_to_host_u16 (h->protocol);
101 : u32 indent, header_bytes;
102 :
103 16527 : header_bytes = sizeof (h[0]);
104 16527 : if (max_header_bytes != 0 && header_bytes > max_header_bytes)
105 0 : return format (s, "gre header truncated");
106 :
107 16527 : indent = format_get_indent (s);
108 :
109 16527 : s = format (s, "GRE %U", format_gre_protocol, p);
110 :
111 16527 : if (max_header_bytes != 0 && header_bytes < max_header_bytes)
112 : {
113 0 : gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
114 0 : vlib_node_t *node = vlib_get_node (gm->vlib_main, pi->node_index);
115 0 : if (node->format_buffer)
116 : s =
117 0 : format (s, "\n%U%U", format_white_space, indent, node->format_buffer,
118 0 : (void *) (h + 1), max_header_bytes - header_bytes);
119 : }
120 :
121 16527 : return s;
122 : }
123 :
124 : u8 *
125 16527 : format_gre_header (u8 *s, va_list *args)
126 : {
127 16527 : gre_header_t *h = va_arg (*args, gre_header_t *);
128 16527 : return format (s, "%U", format_gre_header_with_length, h, 0);
129 : }
130 :
131 : /* Returns gre protocol as an int in host byte order. */
132 : uword
133 0 : unformat_gre_protocol_host_byte_order (unformat_input_t *input, va_list *args)
134 : {
135 0 : u16 *result = va_arg (*args, u16 *);
136 0 : gre_main_t *gm = &gre_main;
137 : int i;
138 :
139 : /* Named type. */
140 0 : if (unformat_user (input, unformat_vlib_number_by_name,
141 : gm->protocol_info_by_name, &i))
142 : {
143 0 : gre_protocol_info_t *pi = vec_elt_at_index (gm->protocol_infos, i);
144 0 : *result = pi->protocol;
145 0 : return 1;
146 : }
147 :
148 0 : return 0;
149 : }
150 :
151 : uword
152 0 : unformat_gre_protocol_net_byte_order (unformat_input_t *input, va_list *args)
153 : {
154 0 : u16 *result = va_arg (*args, u16 *);
155 0 : if (!unformat_user (input, unformat_gre_protocol_host_byte_order, result))
156 0 : return 0;
157 0 : *result = clib_host_to_net_u16 ((u16) *result);
158 0 : return 1;
159 : }
160 :
161 : uword
162 0 : unformat_gre_header (unformat_input_t *input, va_list *args)
163 : {
164 0 : u8 **result = va_arg (*args, u8 **);
165 0 : gre_header_t _h, *h = &_h;
166 : u16 p;
167 :
168 0 : if (!unformat (input, "%U", unformat_gre_protocol_host_byte_order, &p))
169 0 : return 0;
170 :
171 0 : h->protocol = clib_host_to_net_u16 (p);
172 :
173 : /* Add header to result. */
174 : {
175 : void *p;
176 0 : u32 n_bytes = sizeof (h[0]);
177 :
178 0 : vec_add2 (*result, p, n_bytes);
179 0 : clib_memcpy (p, h, n_bytes);
180 : }
181 :
182 0 : return 1;
183 : }
184 :
185 : static int
186 142 : gre_proto_from_vnet_link (vnet_link_t link)
187 : {
188 142 : switch (link)
189 : {
190 62 : case VNET_LINK_IP4:
191 62 : return (GRE_PROTOCOL_ip4);
192 64 : case VNET_LINK_IP6:
193 64 : return (GRE_PROTOCOL_ip6);
194 1 : case VNET_LINK_MPLS:
195 1 : return (GRE_PROTOCOL_mpls_unicast);
196 15 : case VNET_LINK_ETHERNET:
197 15 : return (GRE_PROTOCOL_teb);
198 0 : case VNET_LINK_ARP:
199 0 : return (GRE_PROTOCOL_arp);
200 0 : case VNET_LINK_NSH:
201 0 : ASSERT (0);
202 0 : break;
203 : }
204 0 : ASSERT (0);
205 0 : return (GRE_PROTOCOL_ip4);
206 : }
207 :
208 : static u8 *
209 143 : gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type,
210 : const void *dst_address)
211 : {
212 143 : gre_main_t *gm = &gre_main;
213 : const ip46_address_t *dst;
214 : ip4_and_gre_header_t *h4;
215 : ip6_and_gre_header_t *h6;
216 : gre_header_t *gre;
217 143 : u8 *rewrite = NULL;
218 : gre_tunnel_t *t;
219 : u32 ti;
220 : u8 is_ipv6;
221 :
222 143 : dst = dst_address;
223 143 : ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
224 :
225 143 : if (~0 == ti)
226 : /* not one of ours */
227 0 : return (0);
228 :
229 143 : t = pool_elt_at_index (gm->tunnels, ti);
230 :
231 143 : is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
232 :
233 143 : if (!is_ipv6)
234 : {
235 87 : vec_validate (rewrite, sizeof (*h4) - 1);
236 87 : h4 = (ip4_and_gre_header_t *) rewrite;
237 87 : gre = &h4->gre;
238 87 : h4->ip4.ip_version_and_header_length = 0x45;
239 87 : h4->ip4.ttl = 254;
240 87 : h4->ip4.protocol = IP_PROTOCOL_GRE;
241 : /* fixup ip4 header length and checksum after-the-fact */
242 87 : h4->ip4.src_address.as_u32 = t->tunnel_src.ip4.as_u32;
243 87 : h4->ip4.dst_address.as_u32 = dst->ip4.as_u32;
244 87 : h4->ip4.checksum = ip4_header_checksum (&h4->ip4);
245 : }
246 : else
247 : {
248 56 : vec_validate (rewrite, sizeof (*h6) - 1);
249 56 : h6 = (ip6_and_gre_header_t *) rewrite;
250 56 : gre = &h6->gre;
251 56 : h6->ip6.ip_version_traffic_class_and_flow_label =
252 56 : clib_host_to_net_u32 (6 << 28);
253 56 : h6->ip6.hop_limit = 255;
254 56 : h6->ip6.protocol = IP_PROTOCOL_GRE;
255 : /* fixup ip6 header length and checksum after-the-fact */
256 56 : h6->ip6.src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
257 56 : h6->ip6.src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
258 56 : h6->ip6.dst_address.as_u64[0] = dst->ip6.as_u64[0];
259 56 : h6->ip6.dst_address.as_u64[1] = dst->ip6.as_u64[1];
260 : }
261 :
262 143 : if (PREDICT_FALSE (t->type == GRE_TUNNEL_TYPE_ERSPAN))
263 : {
264 1 : gre->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_erspan);
265 1 : gre->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_SEQUENCE);
266 : }
267 : else
268 142 : gre->protocol =
269 142 : clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type));
270 :
271 143 : return (rewrite);
272 : }
273 :
274 : static void
275 13690 : gre44_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
276 : const void *data)
277 : {
278 : tunnel_encap_decap_flags_t flags;
279 : ip4_and_gre_header_t *ip0;
280 :
281 13690 : ip0 = vlib_buffer_get_current (b0);
282 13690 : flags = pointer_to_uword (data);
283 :
284 : /* Fixup the checksum and len fields in the GRE tunnel encap
285 : * that was applied at the midchain node */
286 13690 : ip0->ip4.length =
287 13690 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
288 13690 : tunnel_encap_fixup_4o4 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip4);
289 13690 : ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
290 13690 : }
291 :
292 : static void
293 385 : gre64_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
294 : const void *data)
295 : {
296 : tunnel_encap_decap_flags_t flags;
297 : ip4_and_gre_header_t *ip0;
298 :
299 385 : ip0 = vlib_buffer_get_current (b0);
300 385 : flags = pointer_to_uword (data);
301 :
302 : /* Fixup the checksum and len fields in the GRE tunnel encap
303 : * that was applied at the midchain node */
304 385 : ip0->ip4.length =
305 385 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
306 385 : tunnel_encap_fixup_6o4 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip4);
307 385 : ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
308 385 : }
309 :
310 : static void
311 2576 : grex4_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
312 : const void *data)
313 : {
314 : ip4_header_t *ip0;
315 :
316 2576 : ip0 = vlib_buffer_get_current (b0);
317 :
318 : /* Fixup the checksum and len fields in the GRE tunnel encap
319 : * that was applied at the midchain node */
320 2576 : ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
321 2576 : ip0->checksum = ip4_header_checksum (ip0);
322 2576 : }
323 :
324 : static void
325 257 : gre46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
326 : const void *data)
327 : {
328 : tunnel_encap_decap_flags_t flags;
329 : ip6_and_gre_header_t *ip0;
330 :
331 257 : ip0 = vlib_buffer_get_current (b0);
332 257 : flags = pointer_to_uword (data);
333 :
334 : /* Fixup the payload length field in the GRE tunnel encap that was applied
335 : * at the midchain node */
336 514 : ip0->ip6.payload_length = clib_host_to_net_u16 (
337 257 : vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
338 257 : tunnel_encap_fixup_4o6 (flags, b0, (ip4_header_t *) (ip0 + 1), &ip0->ip6);
339 257 : }
340 :
341 : static void
342 6407 : gre66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
343 : const void *data)
344 : {
345 : tunnel_encap_decap_flags_t flags;
346 : ip6_and_gre_header_t *ip0;
347 :
348 6407 : ip0 = vlib_buffer_get_current (b0);
349 6407 : flags = pointer_to_uword (data);
350 :
351 : /* Fixup the payload length field in the GRE tunnel encap that was applied
352 : * at the midchain node */
353 12814 : ip0->ip6.payload_length = clib_host_to_net_u16 (
354 6407 : vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
355 6407 : tunnel_encap_fixup_6o6 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip6);
356 6407 : }
357 :
358 : static void
359 0 : grex6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
360 : const void *data)
361 : {
362 : ip6_and_gre_header_t *ip0;
363 :
364 0 : ip0 = vlib_buffer_get_current (b0);
365 :
366 : /* Fixup the payload length field in the GRE tunnel encap that was applied
367 : * at the midchain node */
368 0 : ip0->ip6.payload_length = clib_host_to_net_u16 (
369 0 : vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
370 0 : }
371 :
372 : /**
373 : * return the appropriate fixup function given the overlay (link-type) and
374 : * underlay (fproto) combination
375 : */
376 : static adj_midchain_fixup_t
377 215 : gre_get_fixup (fib_protocol_t fproto, vnet_link_t lt)
378 : {
379 215 : if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP6)
380 64 : return (gre66_fixup);
381 151 : if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP4)
382 1 : return (gre46_fixup);
383 150 : if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP6)
384 9 : return (gre64_fixup);
385 141 : if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP4)
386 124 : return (gre44_fixup);
387 17 : if (fproto == FIB_PROTOCOL_IP6)
388 0 : return (grex6_fixup);
389 17 : if (fproto == FIB_PROTOCOL_IP4)
390 17 : return (grex4_fixup);
391 :
392 0 : ASSERT (0);
393 0 : return (gre44_fixup);
394 : }
395 :
396 : void
397 47 : gre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
398 : {
399 47 : gre_main_t *gm = &gre_main;
400 : gre_tunnel_t *t;
401 : adj_flags_t af;
402 : u32 ti;
403 :
404 47 : ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
405 47 : t = pool_elt_at_index (gm->tunnels, ti);
406 47 : af = ADJ_FLAG_NONE;
407 :
408 : /*
409 : * the user has not requested that the load-balancing be based on
410 : * a flow hash of the inner packet. so use the stacking to choose
411 : * a path.
412 : */
413 47 : if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
414 47 : af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
415 :
416 94 : adj_nbr_midchain_update_rewrite (
417 47 : ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
418 47 : uword_to_pointer (t->flags, void *), af,
419 47 : gre_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai),
420 47 : &t->tunnel_dst.fp_addr));
421 :
422 47 : gre_tunnel_stack (ai);
423 47 : }
424 :
425 : adj_walk_rc_t
426 96 : mgre_mk_complete_walk (adj_index_t ai, void *data)
427 : {
428 96 : mgre_walk_ctx_t *ctx = data;
429 : adj_flags_t af;
430 :
431 96 : af = ADJ_FLAG_NONE;
432 :
433 : /*
434 : * the user has not requested that the load-balancing be based on
435 : * a flow hash of the inner packet. so use the stacking to choose
436 : * a path.
437 : */
438 96 : if (!(ctx->t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
439 96 : af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
440 :
441 192 : adj_nbr_midchain_update_rewrite (
442 96 : ai, gre_get_fixup (ctx->t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
443 96 : uword_to_pointer (ctx->t->flags, void *), af,
444 96 : gre_build_rewrite (vnet_get_main (), ctx->t->sw_if_index,
445 96 : adj_get_link_type (ai),
446 96 : &teib_entry_get_nh (ctx->ne)->fp_addr));
447 :
448 96 : teib_entry_adj_stack (ctx->ne, ai);
449 :
450 96 : return (ADJ_WALK_RC_CONTINUE);
451 : }
452 :
453 : adj_walk_rc_t
454 50 : mgre_mk_incomplete_walk (adj_index_t ai, void *data)
455 : {
456 50 : gre_tunnel_t *t = data;
457 :
458 50 : adj_nbr_midchain_update_rewrite (
459 50 : ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)), NULL,
460 : ADJ_FLAG_NONE, NULL);
461 :
462 50 : adj_midchain_delegate_unstack (ai);
463 :
464 50 : return (ADJ_WALK_RC_CONTINUE);
465 : }
466 :
467 : void
468 45 : mgre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
469 : {
470 45 : gre_main_t *gm = &gre_main;
471 : ip_adjacency_t *adj;
472 : teib_entry_t *ne;
473 : gre_tunnel_t *t;
474 : u32 ti;
475 :
476 45 : adj = adj_get (ai);
477 45 : ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
478 45 : t = pool_elt_at_index (gm->tunnels, ti);
479 :
480 45 : ne = teib_entry_find_46 (sw_if_index, adj->ia_nh_proto,
481 45 : &adj->sub_type.nbr.next_hop);
482 :
483 45 : if (NULL == ne)
484 : {
485 : // no TEIB entry to provide the next-hop
486 22 : adj_nbr_midchain_update_rewrite (
487 22 : ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
488 22 : uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
489 22 : return;
490 : }
491 :
492 23 : mgre_walk_ctx_t ctx = { .t = t, .ne = ne };
493 23 : adj_nbr_walk_nh (sw_if_index, adj->ia_nh_proto, &adj->sub_type.nbr.next_hop,
494 : mgre_mk_complete_walk, &ctx);
495 : }
496 : #endif /* CLIB_MARCH_VARIANT */
497 :
498 : typedef enum
499 : {
500 : GRE_ENCAP_NEXT_L2_MIDCHAIN,
501 : GRE_ENCAP_N_NEXT,
502 : } gre_encap_next_t;
503 :
504 : /**
505 : * @brief TX function. Only called for L2 payload including TEB or ERSPAN.
506 : * L3 traffic uses the adj-midchains.
507 : */
508 : static_always_inline u32
509 28 : gre_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
510 : vlib_frame_t *frame, gre_tunnel_type_t type)
511 : {
512 28 : gre_main_t *gm = &gre_main;
513 : u32 *from, n_left_from;
514 28 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
515 28 : u32 sw_if_index[2] = { ~0, ~0 };
516 28 : const gre_tunnel_t *gt[2] = { 0 };
517 28 : adj_index_t adj_index[2] = { ADJ_INDEX_INVALID, ADJ_INDEX_INVALID };
518 :
519 28 : from = vlib_frame_vector_args (frame);
520 28 : n_left_from = frame->n_vectors;
521 28 : vlib_get_buffers (vm, from, bufs, n_left_from);
522 :
523 1048 : while (n_left_from >= 2)
524 : {
525 :
526 1020 : if (PREDICT_FALSE (sw_if_index[0] !=
527 : vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
528 : {
529 : const vnet_hw_interface_t *hi;
530 10 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
531 10 : hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
532 10 : gt[0] = &gm->tunnels[hi->dev_instance];
533 10 : adj_index[0] = gt[0]->l2_adj_index;
534 : }
535 1020 : if (PREDICT_FALSE (sw_if_index[1] !=
536 : vnet_buffer (b[1])->sw_if_index[VLIB_TX]))
537 : {
538 : const vnet_hw_interface_t *hi;
539 10 : sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
540 10 : hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[1]);
541 10 : gt[1] = &gm->tunnels[hi->dev_instance];
542 10 : adj_index[1] = gt[1]->l2_adj_index;
543 : }
544 :
545 1020 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
546 1020 : vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = adj_index[1];
547 :
548 1020 : if (type == GRE_TUNNEL_TYPE_ERSPAN)
549 : {
550 : /* Encap GRE seq# and ERSPAN type II header */
551 : erspan_t2_t *h0;
552 : u32 seq_num;
553 : u64 hdr;
554 128 : vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
555 128 : h0 = vlib_buffer_get_current (b[0]);
556 128 : seq_num = clib_atomic_fetch_add (>[0]->gre_sn->seq_num, 1);
557 128 : hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
558 128 : h0->seq_num = clib_host_to_net_u32 (seq_num);
559 128 : h0->t2_u64 = hdr;
560 128 : h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
561 : }
562 1020 : if (type == GRE_TUNNEL_TYPE_ERSPAN)
563 : {
564 : /* Encap GRE seq# and ERSPAN type II header */
565 : erspan_t2_t *h0;
566 : u32 seq_num;
567 : u64 hdr;
568 128 : vlib_buffer_advance (b[1], -sizeof (erspan_t2_t));
569 128 : h0 = vlib_buffer_get_current (b[1]);
570 128 : seq_num = clib_atomic_fetch_add (>[1]->gre_sn->seq_num, 1);
571 128 : hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
572 128 : h0->seq_num = clib_host_to_net_u32 (seq_num);
573 128 : h0->t2_u64 = hdr;
574 128 : h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[1]->session_id);
575 : }
576 :
577 1020 : if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
578 : {
579 1020 : gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
580 1020 : tr->tunnel_id = gt[0] - gm->tunnels;
581 1020 : tr->src = gt[0]->tunnel_src;
582 1020 : tr->dst = gt[0]->tunnel_dst.fp_addr;
583 1020 : tr->length = vlib_buffer_length_in_chain (vm, b[0]);
584 : }
585 1020 : if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
586 : {
587 1020 : gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[1], sizeof (*tr));
588 1020 : tr->tunnel_id = gt[1] - gm->tunnels;
589 1020 : tr->src = gt[1]->tunnel_src;
590 1020 : tr->dst = gt[1]->tunnel_dst.fp_addr;
591 1020 : tr->length = vlib_buffer_length_in_chain (vm, b[1]);
592 : }
593 :
594 1020 : b += 2;
595 1020 : n_left_from -= 2;
596 : }
597 :
598 50 : while (n_left_from >= 1)
599 : {
600 :
601 22 : if (PREDICT_FALSE (sw_if_index[0] !=
602 : vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
603 : {
604 : const vnet_hw_interface_t *hi;
605 18 : sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
606 18 : hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
607 18 : gt[0] = &gm->tunnels[hi->dev_instance];
608 18 : adj_index[0] = gt[0]->l2_adj_index;
609 : }
610 :
611 22 : vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
612 :
613 22 : if (type == GRE_TUNNEL_TYPE_ERSPAN)
614 : {
615 : /* Encap GRE seq# and ERSPAN type II header */
616 : erspan_t2_t *h0;
617 : u32 seq_num;
618 : u64 hdr;
619 1 : ASSERT (gt[0]->type == GRE_TUNNEL_TYPE_ERSPAN);
620 1 : vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
621 1 : h0 = vlib_buffer_get_current (b[0]);
622 1 : seq_num = clib_atomic_fetch_add (>[0]->gre_sn->seq_num, 1);
623 1 : hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
624 1 : h0->seq_num = clib_host_to_net_u32 (seq_num);
625 1 : h0->t2_u64 = hdr;
626 1 : h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
627 : }
628 :
629 22 : if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
630 : {
631 22 : gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
632 22 : tr->tunnel_id = gt[0] - gm->tunnels;
633 22 : tr->src = gt[0]->tunnel_src;
634 22 : tr->dst = gt[0]->tunnel_dst.fp_addr;
635 22 : tr->length = vlib_buffer_length_in_chain (vm, b[0]);
636 : }
637 :
638 22 : b += 1;
639 22 : n_left_from -= 1;
640 : }
641 :
642 28 : vlib_buffer_enqueue_to_single_next (
643 28 : vm, node, from, GRE_ENCAP_NEXT_L2_MIDCHAIN, frame->n_vectors);
644 :
645 28 : vlib_node_increment_counter (vm, node->node_index, GRE_ERROR_PKTS_ENCAP,
646 28 : frame->n_vectors);
647 :
648 28 : return frame->n_vectors;
649 : }
650 :
651 : static char *gre_error_strings[] = {
652 : #define gre_error(n, s) s,
653 : #include "error.def"
654 : #undef gre_error
655 : };
656 :
657 2262 : VLIB_NODE_FN (gre_teb_encap_node)
658 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
659 : {
660 26 : return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_TEB));
661 : }
662 :
663 2238 : VLIB_NODE_FN (gre_erspan_encap_node)
664 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
665 : {
666 2 : return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_ERSPAN));
667 : }
668 :
669 : /* *INDENT-OFF* */
670 133880 : VLIB_REGISTER_NODE (gre_teb_encap_node) =
671 : {
672 : .name = "gre-teb-encap",
673 : .vector_size = sizeof (u32),
674 : .format_trace = format_gre_tx_trace,
675 : .type = VLIB_NODE_TYPE_INTERNAL,
676 : .n_errors = GRE_N_ERROR,
677 : .error_strings = gre_error_strings,
678 : .n_next_nodes = GRE_ENCAP_N_NEXT,
679 : .next_nodes = {
680 : [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
681 : },
682 : };
683 133880 : VLIB_REGISTER_NODE (gre_erspan_encap_node) =
684 : {
685 : .name = "gre-erspan-encap",
686 : .vector_size = sizeof (u32),
687 : .format_trace = format_gre_tx_trace,
688 : .type = VLIB_NODE_TYPE_INTERNAL,
689 : .n_errors = GRE_N_ERROR,
690 : .error_strings = gre_error_strings,
691 : .n_next_nodes = GRE_ENCAP_N_NEXT,
692 : .next_nodes = {
693 : [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
694 : },
695 : };
696 : /* *INDENT-ON* */
697 :
698 : #ifndef CLIB_MARCH_VARIANT
699 : static u8 *
700 107 : format_gre_tunnel_name (u8 *s, va_list *args)
701 : {
702 107 : u32 dev_instance = va_arg (*args, u32);
703 107 : gre_main_t *gm = &gre_main;
704 : gre_tunnel_t *t;
705 :
706 107 : if (dev_instance >= vec_len (gm->tunnels))
707 0 : return format (s, "<improperly-referenced>");
708 :
709 107 : t = pool_elt_at_index (gm->tunnels, dev_instance);
710 107 : return format (s, "gre%d", t->user_instance);
711 : }
712 :
713 : static u8 *
714 60 : format_gre_device (u8 *s, va_list *args)
715 : {
716 60 : u32 dev_instance = va_arg (*args, u32);
717 60 : CLIB_UNUSED (int verbose) = va_arg (*args, int);
718 :
719 60 : s = format (s, "GRE tunnel: id %d\n", dev_instance);
720 60 : return s;
721 : }
722 :
723 : static int
724 54 : gre_tunnel_desc (u32 sw_if_index, ip46_address_t *src, ip46_address_t *dst,
725 : u8 *is_l2)
726 : {
727 54 : gre_main_t *gm = &gre_main;
728 : gre_tunnel_t *t;
729 : u32 ti;
730 :
731 54 : ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
732 :
733 54 : if (~0 == ti)
734 : /* not one of ours */
735 0 : return -1;
736 :
737 54 : t = pool_elt_at_index (gm->tunnels, ti);
738 :
739 54 : *src = t->tunnel_src;
740 54 : *dst = t->tunnel_dst.fp_addr;
741 54 : *is_l2 = t->type == GRE_TUNNEL_TYPE_TEB;
742 :
743 54 : return (0);
744 : }
745 :
746 : /* *INDENT-OFF* */
747 8399 : VNET_DEVICE_CLASS (gre_device_class) = {
748 : .name = "GRE tunnel device",
749 : .format_device_name = format_gre_tunnel_name,
750 : .format_device = format_gre_device,
751 : .format_tx_trace = format_gre_tx_trace,
752 : .admin_up_down_function = gre_interface_admin_up_down,
753 : .ip_tun_desc = gre_tunnel_desc,
754 : #ifdef SOON
755 : .clear counter = 0;
756 : #endif
757 : }
758 : ;
759 :
760 5039 : VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
761 : .name = "GRE",
762 : .format_header = format_gre_header_with_length,
763 : .unformat_header = unformat_gre_header,
764 : .build_rewrite = gre_build_rewrite,
765 : .update_adjacency = gre_update_adj,
766 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
767 : };
768 :
769 5039 : VNET_HW_INTERFACE_CLASS (mgre_hw_interface_class) = {
770 : .name = "mGRE",
771 : .format_header = format_gre_header_with_length,
772 : .unformat_header = unformat_gre_header,
773 : .build_rewrite = gre_build_rewrite,
774 : .update_adjacency = mgre_update_adj,
775 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
776 : };
777 : /* *INDENT-ON* */
778 : #endif /* CLIB_MARCH_VARIANT */
779 :
780 : static void
781 3913 : add_protocol (gre_main_t *gm, gre_protocol_t protocol, char *protocol_name)
782 : {
783 : gre_protocol_info_t *pi;
784 : u32 i;
785 :
786 3913 : vec_add2 (gm->protocol_infos, pi, 1);
787 3913 : i = pi - gm->protocol_infos;
788 :
789 3913 : pi->name = protocol_name;
790 3913 : pi->protocol = protocol;
791 3913 : pi->next_index = pi->node_index = ~0;
792 :
793 3913 : hash_set (gm->protocol_info_by_protocol, protocol, i);
794 7826 : hash_set_mem (gm->protocol_info_by_name, pi->name, i);
795 3913 : }
796 :
797 : static clib_error_t *
798 559 : gre_init (vlib_main_t *vm)
799 : {
800 559 : gre_main_t *gm = &gre_main;
801 : clib_error_t *error;
802 559 : ip_main_t *im = &ip_main;
803 : ip_protocol_info_t *pi;
804 :
805 559 : clib_memset (gm, 0, sizeof (gm[0]));
806 559 : gm->vlib_main = vm;
807 559 : gm->vnet_main = vnet_get_main ();
808 :
809 559 : if ((error = vlib_call_init_function (vm, ip_main_init)))
810 0 : return error;
811 :
812 559 : if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
813 0 : return error;
814 :
815 559 : if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
816 0 : return error;
817 :
818 : /* Set up the ip packet generator */
819 559 : pi = ip_get_protocol_info (im, IP_PROTOCOL_GRE);
820 559 : pi->format_header = format_gre_header;
821 559 : pi->unformat_pg_edit = unformat_pg_gre_header;
822 :
823 559 : gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
824 559 : gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
825 559 : gm->tunnel_by_key4 =
826 559 : hash_create_mem (0, sizeof (gre_tunnel_key4_t), sizeof (uword));
827 559 : gm->tunnel_by_key6 =
828 559 : hash_create_mem (0, sizeof (gre_tunnel_key6_t), sizeof (uword));
829 559 : gm->seq_num_by_key =
830 559 : hash_create_mem (0, sizeof (gre_sn_key_t), sizeof (uword));
831 :
832 : #define _(n, s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
833 559 : foreach_gre_protocol
834 : #undef _
835 559 : return vlib_call_init_function (vm, gre_input_init);
836 : }
837 :
838 1119 : VLIB_INIT_FUNCTION (gre_init);
839 :
840 : /*
841 : * fd.io coding-style-patch-verification: ON
842 : *
843 : * Local Variables:
844 : * eval: (c-set-style "gnu")
845 : * End:
846 : */
|