Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * @file
17 : * @brief Common utility functions for IPv4 and IPv6 VXLAN GPE tunnels
18 : *
19 : */
20 : #include <vnet/vxlan-gpe/vxlan_gpe.h>
21 : #include <vnet/fib/fib.h>
22 : #include <vnet/ip/format.h>
23 : #include <vnet/fib/fib_entry.h>
24 : #include <vnet/fib/fib_table.h>
25 : #include <vnet/fib/fib_entry_track.h>
26 : #include <vnet/mfib/mfib_table.h>
27 : #include <vnet/adj/adj_mcast.h>
28 : #include <vnet/interface.h>
29 : #include <vnet/udp/udp_local.h>
30 : #include <vlib/vlib.h>
31 :
32 : /**
33 : * @file
34 : * @brief VXLAN-GPE.
35 : *
36 : * VXLAN-GPE provides the features needed to allow L2 bridge domains (BDs)
37 : * to span multiple servers. This is done by building an L2 overlay on
38 : * top of an L3 network underlay using VXLAN-GPE tunnels.
39 : *
40 : * This makes it possible for servers to be co-located in the same data
41 : * center or be separated geographically as long as they are reachable
42 : * through the underlay L3 network.
43 : *
44 : * You can refer to this kind of L2 overlay bridge domain as a VXLAN-GPE segment.
45 : */
46 :
47 : vxlan_gpe_main_t vxlan_gpe_main;
48 :
49 : static u8 *
50 0 : format_decap_next (u8 * s, va_list * args)
51 : {
52 0 : vxlan_gpe_tunnel_t *t = va_arg (*args, vxlan_gpe_tunnel_t *);
53 :
54 0 : switch (t->protocol)
55 : {
56 0 : case VXLAN_GPE_PROTOCOL_IP4:
57 0 : s = format (s, "protocol ip4 fib-idx %d", t->decap_fib_index);
58 0 : break;
59 0 : case VXLAN_GPE_PROTOCOL_IP6:
60 0 : s = format (s, "protocol ip6 fib-idx %d", t->decap_fib_index);
61 0 : break;
62 0 : case VXLAN_GPE_PROTOCOL_ETHERNET:
63 0 : s = format (s, "protocol ethernet");
64 0 : break;
65 0 : case VXLAN_GPE_PROTOCOL_NSH:
66 0 : s = format (s, "protocol nsh");
67 0 : break;
68 0 : default:
69 0 : s = format (s, "protocol unknown %d", t->protocol);
70 : }
71 :
72 0 : return s;
73 : }
74 :
75 : /**
76 : * @brief Format function for VXLAN GPE tunnel
77 : *
78 : * @param *s formatting string
79 : * @param *args
80 : *
81 : * @return *s formatted string
82 : *
83 : */
84 : u8 *
85 0 : format_vxlan_gpe_tunnel (u8 * s, va_list * args)
86 : {
87 0 : vxlan_gpe_tunnel_t *t = va_arg (*args, vxlan_gpe_tunnel_t *);
88 0 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
89 :
90 0 : s = format (s,
91 : "[%d] lcl %U rmt %U lcl_port %d rmt_port %d vni %d "
92 : "fib-idx %d sw-if-idx %d ",
93 0 : t - ngm->tunnels, format_ip46_address, &t->local, IP46_TYPE_ANY,
94 0 : format_ip46_address, &t->remote, IP46_TYPE_ANY, t->local_port,
95 0 : t->remote_port, t->vni, t->encap_fib_index, t->sw_if_index);
96 :
97 : #if 0
98 : /* next_dpo not yet used by vxlan-gpe-encap node */
99 : s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
100 : */
101 : #endif
102 0 : s = format (s, "decap-next-%U ", format_decap_next, t);
103 :
104 0 : if (PREDICT_FALSE (ip46_address_is_multicast (&t->remote)))
105 0 : s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
106 :
107 0 : return s;
108 : }
109 :
110 : /**
111 : * @brief Naming for VXLAN GPE tunnel
112 : *
113 : * @param *s formatting string
114 : * @param *args
115 : *
116 : * @return *s formatted string
117 : *
118 : */
119 : static u8 *
120 0 : format_vxlan_gpe_name (u8 * s, va_list * args)
121 : {
122 0 : u32 dev_instance = va_arg (*args, u32);
123 0 : return format (s, "vxlan_gpe_tunnel%d", dev_instance);
124 : }
125 :
126 : /**
127 : * @brief CLI function for VXLAN GPE admin up/down
128 : *
129 : * @param *vnm
130 : * @param hw_if_index
131 : * @param flag
132 : *
133 : * @return *rc
134 : *
135 : */
136 : static clib_error_t *
137 0 : vxlan_gpe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
138 : u32 flags)
139 : {
140 0 : u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
141 : VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
142 0 : vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
143 :
144 0 : return 0;
145 : }
146 :
147 : /* *INDENT-OFF* */
148 12095 : VNET_DEVICE_CLASS (vxlan_gpe_device_class,static) = {
149 : .name = "VXLAN_GPE",
150 : .format_device_name = format_vxlan_gpe_name,
151 : .format_tx_trace = format_vxlan_gpe_encap_trace,
152 : .admin_up_down_function = vxlan_gpe_interface_admin_up_down,
153 : };
154 : /* *INDENT-ON* */
155 :
156 :
157 : /**
158 : * @brief Formatting function for tracing VXLAN GPE with length
159 : *
160 : * @param *s
161 : * @param *args
162 : *
163 : * @return *s
164 : *
165 : */
166 : static u8 *
167 0 : format_vxlan_gpe_header_with_length (u8 * s, va_list * args)
168 : {
169 0 : u32 dev_instance = va_arg (*args, u32);
170 0 : s = format (s, "unimplemented dev %u", dev_instance);
171 0 : return s;
172 : }
173 :
174 : /* *INDENT-OFF* */
175 8063 : VNET_HW_INTERFACE_CLASS (vxlan_gpe_hw_class) = {
176 : .name = "VXLAN_GPE",
177 : .format_header = format_vxlan_gpe_header_with_length,
178 : .build_rewrite = default_build_rewrite,
179 : };
180 : /* *INDENT-ON* */
181 :
182 : static void
183 0 : vxlan_gpe_tunnel_restack_dpo (vxlan_gpe_tunnel_t * t)
184 : {
185 0 : dpo_id_t dpo = DPO_INVALID;
186 0 : u32 encap_index = vxlan_gpe_encap_node.index;
187 0 : fib_forward_chain_type_t forw_type = ip46_address_is_ip4 (&t->remote) ?
188 0 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
189 :
190 0 : fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
191 0 : dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
192 0 : dpo_reset (&dpo);
193 0 : }
194 :
195 : static vxlan_gpe_tunnel_t *
196 0 : vxlan_gpe_tunnel_from_fib_node (fib_node_t * node)
197 : {
198 0 : ASSERT (FIB_NODE_TYPE_VXLAN_GPE_TUNNEL == node->fn_type);
199 0 : return ((vxlan_gpe_tunnel_t *) (((char *) node) -
200 : STRUCT_OFFSET_OF (vxlan_gpe_tunnel_t,
201 : node)));
202 : }
203 :
204 : /**
205 : * Function definition to backwalk a FIB node -
206 : * Here we will restack the new dpo of VXLAN_GPE DIP to encap node.
207 : */
208 : static fib_node_back_walk_rc_t
209 0 : vxlan_gpe_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
210 : {
211 0 : vxlan_gpe_tunnel_restack_dpo (vxlan_gpe_tunnel_from_fib_node (node));
212 0 : return (FIB_NODE_BACK_WALK_CONTINUE);
213 : }
214 :
215 : /**
216 : * Function definition to get a FIB node from its index
217 : */
218 : static fib_node_t *
219 0 : vxlan_gpe_tunnel_fib_node_get (fib_node_index_t index)
220 : {
221 : vxlan_gpe_tunnel_t *t;
222 0 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
223 :
224 0 : t = pool_elt_at_index (ngm->tunnels, index);
225 :
226 0 : return (&t->node);
227 : }
228 :
229 : /**
230 : * Function definition to inform the FIB node that its last lock has gone.
231 : */
232 : static void
233 0 : vxlan_gpe_tunnel_last_lock_gone (fib_node_t * node)
234 : {
235 : /*
236 : * The VXLAN_GPE tunnel is a root of the graph. As such
237 : * it never has children and thus is never locked.
238 : */
239 0 : ASSERT (0);
240 0 : }
241 :
242 : /*
243 : * Virtual function table registered by VXLAN_GPE tunnels
244 : * for participation in the FIB object graph.
245 : */
246 : const static fib_node_vft_t vxlan_gpe_vft = {
247 : .fnv_get = vxlan_gpe_tunnel_fib_node_get,
248 : .fnv_last_lock = vxlan_gpe_tunnel_last_lock_gone,
249 : .fnv_back_walk = vxlan_gpe_tunnel_back_walk,
250 : };
251 :
252 : #define foreach_gpe_copy_field \
253 : _ (vni) \
254 : _ (protocol) \
255 : _ (mcast_sw_if_index) \
256 : _ (encap_fib_index) \
257 : _ (decap_fib_index) \
258 : _ (local_port) \
259 : _ (remote_port)
260 :
261 : #define foreach_copy_ipv4 { \
262 : _(local.ip4.as_u32) \
263 : _(remote.ip4.as_u32) \
264 : }
265 :
266 : #define foreach_copy_ipv6 { \
267 : _(local.ip6.as_u64[0]) \
268 : _(local.ip6.as_u64[1]) \
269 : _(remote.ip6.as_u64[0]) \
270 : _(remote.ip6.as_u64[1]) \
271 : }
272 :
273 :
274 : /**
275 : * @brief Calculate IPv4 VXLAN GPE rewrite header
276 : *
277 : * @param *t
278 : *
279 : * @return rc
280 : *
281 : */
282 : int
283 0 : vxlan4_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size,
284 : u8 protocol_override, uword encap_next_node)
285 : {
286 0 : u8 *rw = 0;
287 : ip4_header_t *ip0;
288 : ip4_vxlan_gpe_header_t *h0;
289 : int len;
290 :
291 0 : len = sizeof (*h0) + extension_size;
292 :
293 0 : vec_free (t->rewrite);
294 0 : vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
295 :
296 0 : h0 = (ip4_vxlan_gpe_header_t *) rw;
297 :
298 : /* Fixed portion of the (outer) ip4 header */
299 0 : ip0 = &h0->ip4;
300 0 : ip0->ip_version_and_header_length = 0x45;
301 0 : ip0->ttl = 254;
302 0 : ip0->protocol = IP_PROTOCOL_UDP;
303 :
304 : /* we fix up the ip4 header length and checksum after-the-fact */
305 0 : ip0->src_address.as_u32 = t->local.ip4.as_u32;
306 0 : ip0->dst_address.as_u32 = t->remote.ip4.as_u32;
307 0 : ip0->checksum = ip4_header_checksum (ip0);
308 :
309 : /* UDP header, randomize src port on something, maybe? */
310 0 : h0->udp.src_port = clib_host_to_net_u16 (t->local_port);
311 0 : h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port);
312 :
313 : /* VXLAN header. Are we having fun yet? */
314 0 : h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
315 0 : h0->vxlan.ver_res = VXLAN_GPE_VERSION;
316 0 : if (protocol_override)
317 : {
318 0 : h0->vxlan.protocol = protocol_override;
319 : }
320 : else
321 : {
322 0 : h0->vxlan.protocol = t->protocol;
323 : }
324 0 : t->rewrite_size = sizeof (ip4_vxlan_gpe_header_t) + extension_size;
325 0 : h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni << 8);
326 :
327 0 : t->rewrite = rw;
328 0 : t->encap_next_node = encap_next_node;
329 0 : return (0);
330 : }
331 :
332 : /**
333 : * @brief Calculate IPv6 VXLAN GPE rewrite header
334 : *
335 : * @param *t
336 : *
337 : * @return rc
338 : *
339 : */
340 : int
341 0 : vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size,
342 : u8 protocol_override, uword encap_next_node)
343 : {
344 0 : u8 *rw = 0;
345 : ip6_header_t *ip0;
346 : ip6_vxlan_gpe_header_t *h0;
347 : int len;
348 :
349 0 : len = sizeof (*h0) + extension_size;
350 :
351 0 : vec_free (t->rewrite);
352 0 : vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
353 :
354 0 : h0 = (ip6_vxlan_gpe_header_t *) rw;
355 :
356 : /* Fixed portion of the (outer) ip4 header */
357 0 : ip0 = &h0->ip6;
358 0 : ip0->ip_version_traffic_class_and_flow_label =
359 0 : clib_host_to_net_u32 (6 << 28);
360 0 : ip0->hop_limit = 255;
361 0 : ip0->protocol = IP_PROTOCOL_UDP;
362 :
363 0 : ip0->src_address.as_u64[0] = t->local.ip6.as_u64[0];
364 0 : ip0->src_address.as_u64[1] = t->local.ip6.as_u64[1];
365 0 : ip0->dst_address.as_u64[0] = t->remote.ip6.as_u64[0];
366 0 : ip0->dst_address.as_u64[1] = t->remote.ip6.as_u64[1];
367 :
368 : /* UDP header, randomize src port on something, maybe? */
369 0 : h0->udp.src_port = clib_host_to_net_u16 (t->local_port);
370 0 : h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port);
371 :
372 : /* VXLAN header. Are we having fun yet? */
373 0 : h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
374 0 : h0->vxlan.ver_res = VXLAN_GPE_VERSION;
375 0 : if (protocol_override)
376 : {
377 0 : h0->vxlan.protocol = t->protocol;
378 : }
379 : else
380 : {
381 0 : h0->vxlan.protocol = protocol_override;
382 : }
383 0 : t->rewrite_size = sizeof (ip4_vxlan_gpe_header_t) + extension_size;
384 0 : h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni << 8);
385 :
386 0 : t->rewrite = rw;
387 0 : t->encap_next_node = encap_next_node;
388 0 : return (0);
389 : }
390 :
391 : /* *INDENT-OFF* */
392 : typedef CLIB_PACKED(union {
393 : struct {
394 : fib_node_index_t mfib_entry_index;
395 : adj_index_t mcast_adj_index;
396 : };
397 : u64 as_u64;
398 : }) mcast_shared_t;
399 : /* *INDENT-ON* */
400 :
401 : static inline mcast_shared_t
402 0 : mcast_shared_get (ip46_address_t * ip)
403 : {
404 0 : ASSERT (ip46_address_is_multicast (ip));
405 0 : uword *p = hash_get_mem (vxlan_gpe_main.mcast_shared, ip);
406 0 : ALWAYS_ASSERT (p);
407 0 : return (mcast_shared_t)
408 : {
409 0 : .as_u64 = *p};
410 : }
411 :
412 : static inline void
413 0 : mcast_shared_add (ip46_address_t * remote,
414 : fib_node_index_t mfei, adj_index_t ai)
415 : {
416 0 : mcast_shared_t new_ep = {
417 : .mcast_adj_index = ai,
418 : .mfib_entry_index = mfei,
419 : };
420 :
421 0 : hash_set_mem_alloc (&vxlan_gpe_main.mcast_shared, remote, new_ep.as_u64);
422 0 : }
423 :
424 : static inline void
425 0 : mcast_shared_remove (ip46_address_t * remote)
426 : {
427 0 : mcast_shared_t ep = mcast_shared_get (remote);
428 :
429 0 : adj_unlock (ep.mcast_adj_index);
430 0 : mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_VXLAN_GPE);
431 :
432 0 : hash_unset_mem_free (&vxlan_gpe_main.mcast_shared, remote);
433 0 : }
434 :
435 : /**
436 : * @brief Add or Del a VXLAN GPE tunnel
437 : *
438 : * @param *a
439 : * @param *sw_if_index
440 : *
441 : * @return rc
442 : *
443 : */
444 0 : int vnet_vxlan_gpe_add_del_tunnel
445 : (vnet_vxlan_gpe_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
446 : {
447 0 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
448 0 : vxlan_gpe_tunnel_t *t = 0;
449 0 : vnet_main_t *vnm = ngm->vnet_main;
450 : vnet_hw_interface_t *hi;
451 : uword *p;
452 0 : u32 hw_if_index = ~0;
453 0 : u32 sw_if_index = ~0;
454 : int rv;
455 : vxlan4_gpe_tunnel_key_t key4, *key4_copy;
456 : vxlan6_gpe_tunnel_key_t key6, *key6_copy;
457 0 : u32 is_ip6 = a->is_ip6;
458 :
459 : /* Set udp-ports */
460 0 : if (a->local_port == 0)
461 0 : a->local_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE;
462 :
463 0 : if (a->remote_port == 0)
464 0 : a->remote_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE;
465 :
466 0 : if (!is_ip6)
467 : {
468 0 : key4.local = a->local.ip4.as_u32;
469 0 : key4.remote = a->remote.ip4.as_u32;
470 0 : key4.vni = clib_host_to_net_u32 (a->vni << 8);
471 0 : key4.port = (u32) clib_host_to_net_u16 (a->local_port);
472 :
473 0 : p = hash_get_mem (ngm->vxlan4_gpe_tunnel_by_key, &key4);
474 : }
475 : else
476 : {
477 0 : key6.local.as_u64[0] = a->local.ip6.as_u64[0];
478 0 : key6.local.as_u64[1] = a->local.ip6.as_u64[1];
479 0 : key6.remote.as_u64[0] = a->remote.ip6.as_u64[0];
480 0 : key6.remote.as_u64[1] = a->remote.ip6.as_u64[1];
481 0 : key6.vni = clib_host_to_net_u32 (a->vni << 8);
482 0 : key6.port = (u32) clib_host_to_net_u16 (a->local_port);
483 :
484 0 : p = hash_get_mem (ngm->vxlan6_gpe_tunnel_by_key, &key6);
485 : }
486 :
487 0 : if (a->is_add)
488 : {
489 0 : l2input_main_t *l2im = &l2input_main;
490 :
491 : /* adding a tunnel: tunnel must not already exist */
492 0 : if (p)
493 0 : return VNET_API_ERROR_TUNNEL_EXIST;
494 :
495 0 : pool_get_aligned (ngm->tunnels, t, CLIB_CACHE_LINE_BYTES);
496 0 : clib_memset (t, 0, sizeof (*t));
497 :
498 : /* copy from arg structure */
499 : /* *INDENT-OFF* */
500 : #define _(x) t->x = a->x;
501 0 : foreach_gpe_copy_field;
502 0 : if (!a->is_ip6)
503 0 : foreach_copy_ipv4
504 : else
505 0 : foreach_copy_ipv6
506 : #undef _
507 : /* *INDENT-ON* */
508 :
509 0 : if (!a->is_ip6)
510 0 : t->flags |= VXLAN_GPE_TUNNEL_IS_IPV4;
511 :
512 0 : if (!a->is_ip6)
513 : {
514 0 : rv = vxlan4_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP);
515 : }
516 : else
517 : {
518 0 : rv = vxlan6_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP);
519 : }
520 :
521 0 : if (rv)
522 : {
523 0 : pool_put (ngm->tunnels, t);
524 0 : return rv;
525 : }
526 :
527 0 : if (!is_ip6)
528 : {
529 0 : key4_copy = clib_mem_alloc (sizeof (*key4_copy));
530 0 : clib_memcpy_fast (key4_copy, &key4, sizeof (*key4_copy));
531 0 : hash_set_mem (ngm->vxlan4_gpe_tunnel_by_key, key4_copy,
532 : t - ngm->tunnels);
533 : }
534 : else
535 : {
536 0 : key6_copy = clib_mem_alloc (sizeof (*key6_copy));
537 0 : clib_memcpy_fast (key6_copy, &key6, sizeof (*key6_copy));
538 0 : hash_set_mem (ngm->vxlan6_gpe_tunnel_by_key, key6_copy,
539 : t - ngm->tunnels);
540 : }
541 :
542 0 : if (vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) > 0)
543 0 : {
544 0 : vnet_interface_main_t *im = &vnm->interface_main;
545 0 : hw_if_index = ngm->free_vxlan_gpe_tunnel_hw_if_indices
546 0 : [vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) - 1];
547 0 : vec_dec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices, 1);
548 :
549 0 : hi = vnet_get_hw_interface (vnm, hw_if_index);
550 0 : hi->dev_instance = t - ngm->tunnels;
551 0 : hi->hw_instance = hi->dev_instance;
552 : /* clear old stats of freed tunnel before reuse */
553 0 : sw_if_index = hi->sw_if_index;
554 0 : vnet_interface_counter_lock (im);
555 0 : vlib_zero_combined_counter
556 0 : (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
557 : sw_if_index);
558 0 : vlib_zero_combined_counter (&im->combined_sw_if_counters
559 : [VNET_INTERFACE_COUNTER_RX],
560 : sw_if_index);
561 0 : vlib_zero_simple_counter (&im->sw_if_counters
562 : [VNET_INTERFACE_COUNTER_DROP],
563 : sw_if_index);
564 0 : vnet_interface_counter_unlock (im);
565 : }
566 : else
567 : {
568 0 : hw_if_index = vnet_register_interface
569 0 : (vnm, vxlan_gpe_device_class.index, t - ngm->tunnels,
570 0 : vxlan_gpe_hw_class.index, t - ngm->tunnels);
571 0 : hi = vnet_get_hw_interface (vnm, hw_if_index);
572 : }
573 :
574 : /* Set vxlan-gpe tunnel output node */
575 0 : u32 encap_index = vxlan_gpe_encap_node.index;
576 0 : vnet_set_interface_output_node (vnm, hw_if_index, encap_index);
577 :
578 0 : t->hw_if_index = hw_if_index;
579 0 : t->sw_if_index = sw_if_index = hi->sw_if_index;
580 0 : vec_validate_init_empty (ngm->tunnel_index_by_sw_if_index, sw_if_index,
581 : ~0);
582 0 : ngm->tunnel_index_by_sw_if_index[sw_if_index] = t - ngm->tunnels;
583 :
584 : /* setup l2 input config with l2 feature and bd 0 to drop packet */
585 0 : vec_validate (l2im->configs, sw_if_index);
586 0 : l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
587 0 : l2im->configs[sw_if_index].bd_index = 0;
588 :
589 0 : vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
590 0 : si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
591 0 : vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
592 : VNET_SW_INTERFACE_FLAG_ADMIN_UP);
593 0 : fib_node_init (&t->node, FIB_NODE_TYPE_VXLAN_GPE_TUNNEL);
594 : fib_prefix_t tun_remote_pfx;
595 0 : vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
596 :
597 0 : fib_protocol_t fp = fib_ip_proto (is_ip6);
598 0 : fib_prefix_from_ip46_addr (fp, &t->remote, &tun_remote_pfx);
599 0 : if (!ip46_address_is_multicast (&t->remote))
600 : {
601 : /* Unicast tunnel -
602 : * source the FIB entry for the tunnel's destination
603 : * and become a child thereof. The tunnel will then get poked
604 : * when the forwarding for the entry updates, and the tunnel can
605 : * re-stack accordingly
606 : */
607 0 : vtep_addr_ref (&ngm->vtep_table, t->encap_fib_index, &t->local);
608 0 : t->fib_entry_index = fib_entry_track (t->encap_fib_index,
609 : &tun_remote_pfx,
610 : FIB_NODE_TYPE_VXLAN_GPE_TUNNEL,
611 0 : t - ngm->tunnels,
612 0 : &t->sibling_index);
613 0 : vxlan_gpe_tunnel_restack_dpo (t);
614 : }
615 : else
616 : {
617 : /* Multicast tunnel -
618 : * as the same mcast group can be used for multiple mcast tunnels
619 : * with different VNIs, create the output fib adjacency only if
620 : * it does not already exist
621 : */
622 0 : if (vtep_addr_ref (&ngm->vtep_table,
623 0 : t->encap_fib_index, &t->remote) == 1)
624 : {
625 : fib_node_index_t mfei;
626 : adj_index_t ai;
627 0 : fib_route_path_t path = {
628 0 : .frp_proto = fib_proto_to_dpo (fp),
629 : .frp_addr = zero_addr,
630 : .frp_sw_if_index = 0xffffffff,
631 : .frp_fib_index = ~0,
632 : .frp_weight = 1,
633 : .frp_flags = FIB_ROUTE_PATH_LOCAL,
634 : .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
635 : };
636 0 : const mfib_prefix_t mpfx = {
637 : .fp_proto = fp,
638 : .fp_len = (is_ip6 ? 128 : 32),
639 : .fp_grp_addr = tun_remote_pfx.fp_addr,
640 : };
641 :
642 : /*
643 : * Setup the (*,G) to receive traffic on the mcast group
644 : * - the forwarding interface is for-us
645 : * - the accepting interface is that from the API
646 : */
647 0 : mfib_table_entry_path_update (t->encap_fib_index, &mpfx,
648 : MFIB_SOURCE_VXLAN_GPE,
649 : MFIB_ENTRY_FLAG_NONE, &path);
650 :
651 0 : path.frp_sw_if_index = a->mcast_sw_if_index;
652 0 : path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
653 0 : path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
654 0 : mfei = mfib_table_entry_path_update (
655 0 : t->encap_fib_index, &mpfx, MFIB_SOURCE_VXLAN_GPE,
656 : MFIB_ENTRY_FLAG_NONE, &path);
657 :
658 : /*
659 : * Create the mcast adjacency to send traffic to the group
660 : */
661 0 : ai = adj_mcast_add_or_lock (fp,
662 0 : fib_proto_to_link (fp),
663 : a->mcast_sw_if_index);
664 :
665 : /*
666 : * create a new end-point
667 : */
668 0 : mcast_shared_add (&t->remote, mfei, ai);
669 : }
670 :
671 0 : dpo_id_t dpo = DPO_INVALID;
672 0 : mcast_shared_t ep = mcast_shared_get (&t->remote);
673 :
674 : /* Stack shared mcast remote mac addr rewrite on encap */
675 0 : dpo_set (&dpo, DPO_ADJACENCY_MCAST,
676 0 : fib_proto_to_dpo (fp), ep.mcast_adj_index);
677 :
678 0 : dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
679 0 : dpo_reset (&dpo);
680 0 : flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
681 : }
682 :
683 0 : vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
684 : flood_class;
685 : }
686 : else
687 : {
688 : /* deleting a tunnel: tunnel must exist */
689 0 : if (!p)
690 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
691 :
692 0 : t = pool_elt_at_index (ngm->tunnels, p[0]);
693 :
694 0 : sw_if_index = t->sw_if_index;
695 0 : vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
696 0 : vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
697 0 : si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
698 0 : set_int_l2_mode (ngm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
699 : L2_BD_PORT_TYPE_NORMAL, 0, 0);
700 0 : vec_add1 (ngm->free_vxlan_gpe_tunnel_hw_if_indices, t->hw_if_index);
701 :
702 0 : ngm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
703 :
704 0 : if (!is_ip6)
705 0 : hash_unset (ngm->vxlan4_gpe_tunnel_by_key, key4.as_u64);
706 : else
707 0 : hash_unset_mem_free (&ngm->vxlan6_gpe_tunnel_by_key, &key6);
708 :
709 0 : if (!ip46_address_is_multicast (&t->remote))
710 : {
711 0 : vtep_addr_unref (&ngm->vtep_table, t->encap_fib_index, &t->local);
712 0 : fib_entry_untrack (t->fib_entry_index, t->sibling_index);
713 : }
714 0 : else if (vtep_addr_unref (&ngm->vtep_table,
715 0 : t->encap_fib_index, &t->remote) == 0)
716 : {
717 0 : mcast_shared_remove (&t->remote);
718 : }
719 :
720 0 : fib_node_deinit (&t->node);
721 0 : vec_free (t->rewrite);
722 0 : pool_put (ngm->tunnels, t);
723 : }
724 :
725 0 : if (sw_if_indexp)
726 0 : *sw_if_indexp = sw_if_index;
727 :
728 0 : if (a->is_add)
729 : {
730 : /* register udp ports */
731 0 : if (!is_ip6 && !udp_is_valid_dst_port (a->local_port, 1))
732 0 : udp_register_dst_port (ngm->vlib_main, a->local_port,
733 : vxlan4_gpe_input_node.index, 1 /* is_ip4 */);
734 0 : if (is_ip6 && !udp_is_valid_dst_port (a->remote_port, 0))
735 0 : udp_register_dst_port (ngm->vlib_main, a->remote_port,
736 : vxlan6_gpe_input_node.index, 0 /* is_ip4 */);
737 : }
738 :
739 0 : return 0;
740 : }
741 :
742 : static clib_error_t *
743 0 : vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm,
744 : unformat_input_t * input,
745 : vlib_cli_command_t * cmd)
746 : {
747 0 : unformat_input_t _line_input, *line_input = &_line_input;
748 0 : u8 is_add = 1;
749 : ip46_address_t local, remote;
750 0 : u8 local_set = 0;
751 0 : u8 remote_set = 0;
752 0 : u8 grp_set = 0;
753 0 : u8 ipv4_set = 0;
754 0 : u8 ipv6_set = 0;
755 0 : u32 mcast_sw_if_index = ~0;
756 0 : u32 encap_fib_index = 0;
757 0 : u32 decap_fib_index = 0;
758 0 : u8 protocol = VXLAN_GPE_PROTOCOL_IP4;
759 : u32 vni;
760 0 : u8 vni_set = 0;
761 0 : u32 local_port = 0;
762 0 : u32 remote_port = 0;
763 : int rv;
764 : u32 tmp;
765 0 : vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a;
766 : u32 sw_if_index;
767 0 : clib_error_t *error = NULL;
768 :
769 : /* Get a line of input. */
770 0 : if (!unformat_user (input, unformat_line_input, line_input))
771 0 : return 0;
772 :
773 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
774 : {
775 0 : if (unformat (line_input, "del"))
776 0 : is_add = 0;
777 0 : else if (unformat (line_input, "local %U",
778 : unformat_ip4_address, &local.ip4))
779 : {
780 0 : local_set = 1;
781 0 : ipv4_set = 1;
782 : }
783 0 : else if (unformat (line_input, "remote %U",
784 : unformat_ip4_address, &remote.ip4))
785 : {
786 0 : remote_set = 1;
787 0 : ipv4_set = 1;
788 : }
789 0 : else if (unformat (line_input, "local %U",
790 : unformat_ip6_address, &local.ip6))
791 : {
792 0 : local_set = 1;
793 0 : ipv6_set = 1;
794 : }
795 0 : else if (unformat (line_input, "remote %U",
796 : unformat_ip6_address, &remote.ip6))
797 : {
798 0 : remote_set = 1;
799 0 : ipv6_set = 1;
800 : }
801 0 : else if (unformat (line_input, "group %U %U",
802 : unformat_ip4_address, &remote.ip4,
803 : unformat_vnet_sw_interface,
804 : vnet_get_main (), &mcast_sw_if_index))
805 : {
806 0 : grp_set = remote_set = 1;
807 0 : ipv4_set = 1;
808 : }
809 0 : else if (unformat (line_input, "group %U %U",
810 : unformat_ip6_address, &remote.ip6,
811 : unformat_vnet_sw_interface,
812 : vnet_get_main (), &mcast_sw_if_index))
813 : {
814 0 : grp_set = remote_set = 1;
815 0 : ipv6_set = 1;
816 : }
817 0 : else if (unformat (line_input, "encap-vrf-id %d", &tmp))
818 : {
819 0 : if (ipv6_set)
820 0 : encap_fib_index = fib_table_find (FIB_PROTOCOL_IP6, tmp);
821 : else
822 0 : encap_fib_index = fib_table_find (FIB_PROTOCOL_IP4, tmp);
823 :
824 0 : if (encap_fib_index == ~0)
825 : {
826 : error =
827 0 : clib_error_return (0, "nonexistent encap fib id %d", tmp);
828 0 : goto done;
829 : }
830 : }
831 0 : else if (unformat (line_input, "decap-vrf-id %d", &tmp))
832 : {
833 0 : if (ipv6_set)
834 0 : decap_fib_index = fib_table_find (FIB_PROTOCOL_IP6, tmp);
835 : else
836 0 : decap_fib_index = fib_table_find (FIB_PROTOCOL_IP4, tmp);
837 :
838 0 : if (decap_fib_index == ~0)
839 : {
840 : error =
841 0 : clib_error_return (0, "nonexistent decap fib id %d", tmp);
842 0 : goto done;
843 : }
844 : }
845 0 : else if (unformat (line_input, "vni %d", &vni))
846 0 : vni_set = 1;
847 0 : else if (unformat (line_input, "local_port %d", &local_port))
848 : ;
849 0 : else if (unformat (line_input, "remote_port %d", &remote_port))
850 : ;
851 0 : else if (unformat (line_input, "next-ip4"))
852 0 : protocol = VXLAN_GPE_PROTOCOL_IP4;
853 0 : else if (unformat (line_input, "next-ip6"))
854 0 : protocol = VXLAN_GPE_PROTOCOL_IP6;
855 0 : else if (unformat (line_input, "next-ethernet"))
856 0 : protocol = VXLAN_GPE_PROTOCOL_ETHERNET;
857 0 : else if (unformat (line_input, "next-nsh"))
858 0 : protocol = VXLAN_GPE_PROTOCOL_NSH;
859 : else
860 : {
861 0 : error = clib_error_return (0, "parse error: '%U'",
862 : format_unformat_error, line_input);
863 0 : goto done;
864 : }
865 : }
866 :
867 0 : if (local_set == 0)
868 : {
869 0 : error = clib_error_return (0, "tunnel local address not specified");
870 0 : goto done;
871 : }
872 :
873 0 : if (remote_set == 0)
874 : {
875 0 : error = clib_error_return (0, "tunnel remote address not specified");
876 0 : goto done;
877 : }
878 :
879 0 : if (grp_set && !ip46_address_is_multicast (&remote))
880 : {
881 0 : error = clib_error_return (0, "tunnel group address not multicast");
882 0 : goto done;
883 : }
884 :
885 0 : if (grp_set == 0 && ip46_address_is_multicast (&remote))
886 : {
887 0 : error = clib_error_return (0, "remote address must be unicast");
888 0 : goto done;
889 : }
890 :
891 0 : if (grp_set && mcast_sw_if_index == ~0)
892 : {
893 0 : error = clib_error_return (0, "tunnel nonexistent multicast device");
894 0 : goto done;
895 : }
896 0 : if (ipv4_set && ipv6_set)
897 : {
898 0 : error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
899 0 : goto done;
900 : }
901 :
902 0 : if ((ipv4_set && memcmp (&local.ip4, &remote.ip4, sizeof (local.ip4)) == 0)
903 0 : || (ipv6_set
904 0 : && memcmp (&local.ip6, &remote.ip6, sizeof (local.ip6)) == 0))
905 : {
906 0 : error = clib_error_return (0, "src and remote addresses are identical");
907 0 : goto done;
908 : }
909 :
910 0 : if (vni_set == 0)
911 : {
912 0 : error = clib_error_return (0, "vni not specified");
913 0 : goto done;
914 : }
915 :
916 0 : clib_memset (a, 0, sizeof (*a));
917 :
918 0 : a->is_add = is_add;
919 0 : a->is_ip6 = ipv6_set;
920 :
921 : /* *INDENT-OFF* */
922 : #define _(x) a->x = x;
923 0 : foreach_gpe_copy_field;
924 0 : if (ipv4_set)
925 0 : foreach_copy_ipv4
926 : else
927 0 : foreach_copy_ipv6
928 : #undef _
929 : /* *INDENT-ON* */
930 :
931 0 : rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index);
932 :
933 0 : switch (rv)
934 : {
935 0 : case 0:
936 0 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
937 : vnet_get_main (), sw_if_index);
938 0 : break;
939 0 : case VNET_API_ERROR_INVALID_DECAP_NEXT:
940 0 : error = clib_error_return (0, "invalid decap-next...");
941 0 : goto done;
942 :
943 0 : case VNET_API_ERROR_TUNNEL_EXIST:
944 0 : error = clib_error_return (0, "tunnel already exists...");
945 0 : goto done;
946 :
947 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
948 0 : error = clib_error_return (0, "tunnel does not exist...");
949 0 : goto done;
950 :
951 0 : default:
952 0 : error = clib_error_return
953 : (0, "vnet_vxlan_gpe_add_del_tunnel returned %d", rv);
954 0 : goto done;
955 : }
956 :
957 0 : done:
958 0 : unformat_free (line_input);
959 :
960 0 : return error;
961 : }
962 :
963 : /*?
964 : * Add or delete a VXLAN-GPE Tunnel.
965 : *
966 : * VXLAN-GPE provides the features needed to allow L2 bridge domains (BDs)
967 : * to span multiple servers. This is done by building an L2 overlay on
968 : * top of an L3 network underlay using VXLAN-GPE tunnels.
969 : *
970 : * This makes it possible for servers to be co-located in the same data
971 : * center or be separated geographically as long as they are reachable
972 : * through the underlay L3 network.
973 : *
974 : * You can refer to this kind of L2 overlay bridge domain as a VXLAN-GPE segment.
975 : *
976 : * @cliexpar
977 : * Example of how to create a VXLAN-GPE Tunnel:
978 : * @cliexcmd{create vxlan-gpe tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 encap-vrf-id 7}
979 : * Example of how to delete a VXLAN-GPE Tunnel:
980 : * @cliexcmd{create vxlan-gpe tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 del}
981 : ?*/
982 : /* *INDENT-OFF* */
983 285289 : VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = {
984 : .path = "create vxlan-gpe tunnel",
985 : .short_help =
986 : "create vxlan-gpe tunnel local <local-addr> "
987 : " {remote <remote-addr>|group <mcast-addr> <intf-name>}"
988 : " vni <nn> [next-ip4][next-ip6][next-ethernet][next-nsh]"
989 : " [encap-vrf-id <nn>] [decap-vrf-id <nn>] [del]\n",
990 : .function = vxlan_gpe_add_del_tunnel_command_fn,
991 : };
992 : /* *INDENT-ON* */
993 :
994 : /**
995 : * @brief CLI function for showing VXLAN GPE tunnels
996 : *
997 : * @param *vm
998 : * @param *input
999 : * @param *cmd
1000 : *
1001 : * @return error
1002 : *
1003 : */
1004 : static clib_error_t *
1005 0 : show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm,
1006 : unformat_input_t * input,
1007 : vlib_cli_command_t * cmd)
1008 : {
1009 0 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
1010 : vxlan_gpe_tunnel_t *t;
1011 :
1012 0 : if (pool_elts (ngm->tunnels) == 0)
1013 0 : vlib_cli_output (vm, "No vxlan-gpe tunnels configured.");
1014 :
1015 : /* *INDENT-OFF* */
1016 0 : pool_foreach (t, ngm->tunnels)
1017 : {
1018 0 : vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t);
1019 : }
1020 : /* *INDENT-ON* */
1021 :
1022 0 : return 0;
1023 : }
1024 :
1025 : /*?
1026 : * Display all the VXLAN-GPE Tunnel entries.
1027 : *
1028 : * @cliexpar
1029 : * Example of how to display the VXLAN-GPE Tunnel entries:
1030 : * @cliexstart{show vxlan-gpe tunnel}
1031 : * [0] local 10.0.3.1 remote 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2
1032 : * @cliexend
1033 : ?*/
1034 : /* *INDENT-OFF* */
1035 285289 : VLIB_CLI_COMMAND (show_vxlan_gpe_tunnel_command, static) = {
1036 : .path = "show vxlan-gpe",
1037 : .function = show_vxlan_gpe_tunnel_command_fn,
1038 : };
1039 : /* *INDENT-ON* */
1040 :
1041 : void
1042 0 : vnet_int_vxlan_gpe_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
1043 : {
1044 0 : if (is_ip6)
1045 0 : vnet_feature_enable_disable ("ip6-unicast", "ip6-vxlan-gpe-bypass",
1046 : sw_if_index, is_enable, 0, 0);
1047 : else
1048 0 : vnet_feature_enable_disable ("ip4-unicast", "ip4-vxlan-gpe-bypass",
1049 : sw_if_index, is_enable, 0, 0);
1050 0 : }
1051 :
1052 :
1053 : static clib_error_t *
1054 0 : set_ip_vxlan_gpe_bypass (u32 is_ip6,
1055 : unformat_input_t * input, vlib_cli_command_t * cmd)
1056 : {
1057 0 : unformat_input_t _line_input, *line_input = &_line_input;
1058 0 : vnet_main_t *vnm = vnet_get_main ();
1059 0 : clib_error_t *error = 0;
1060 : u32 sw_if_index, is_enable;
1061 :
1062 0 : sw_if_index = ~0;
1063 0 : is_enable = 1;
1064 :
1065 0 : if (!unformat_user (input, unformat_line_input, line_input))
1066 0 : return 0;
1067 :
1068 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1069 : {
1070 0 : if (unformat_user
1071 : (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1072 : ;
1073 0 : else if (unformat (line_input, "del"))
1074 0 : is_enable = 0;
1075 : else
1076 : {
1077 0 : error = unformat_parse_error (line_input);
1078 0 : goto done;
1079 : }
1080 : }
1081 :
1082 0 : if (~0 == sw_if_index)
1083 : {
1084 0 : error = clib_error_return (0, "unknown interface `%U'",
1085 : format_unformat_error, line_input);
1086 0 : goto done;
1087 : }
1088 :
1089 0 : vnet_int_vxlan_gpe_bypass_mode (sw_if_index, is_ip6, is_enable);
1090 :
1091 0 : done:
1092 0 : unformat_free (line_input);
1093 :
1094 0 : return error;
1095 : }
1096 :
1097 : static clib_error_t *
1098 0 : set_ip4_vxlan_gpe_bypass (vlib_main_t * vm,
1099 : unformat_input_t * input, vlib_cli_command_t * cmd)
1100 : {
1101 0 : return set_ip_vxlan_gpe_bypass (0, input, cmd);
1102 : }
1103 :
1104 : /*?
1105 : * This command adds the 'ip4-vxlan-gpe-bypass' graph node for a given
1106 : * interface. By adding the IPv4 vxlan-gpe-bypass graph node to an interface,
1107 : * the node checks for and validate input vxlan_gpe packet and bypass
1108 : * ip4-lookup, ip4-local, ip4-udp-lookup nodes to speedup vxlan_gpe packet
1109 : * forwarding. This node will cause extra overhead to for non-vxlan_gpe
1110 : * packets which is kept at a minimum.
1111 : *
1112 : * @cliexpar
1113 : * @parblock
1114 : * Example of graph node before ip4-vxlan-gpe-bypass is enabled:
1115 : * @cliexstart{show vlib graph ip4-vxlan-gpe-bypass}
1116 : * Name Next Previous
1117 : * ip4-vxlan-gpe-bypass error-drop [0]
1118 : * vxlan4-gpe-input [1]
1119 : * ip4-lookup [2]
1120 : * @cliexend
1121 : *
1122 : * Example of how to enable ip4-vxlan-gpe-bypass on an interface:
1123 : * @cliexcmd{set interface ip vxlan-gpe-bypass GigabitEthernet2/0/0}
1124 : *
1125 : * Example of graph node after ip4-vxlan-gpe-bypass is enabled:
1126 : * @cliexstart{show vlib graph ip4-vxlan-gpe-bypass}
1127 : * Name Next Previous
1128 : * ip4-vxlan-gpe-bypass error-drop [0] ip4-input
1129 : * vxlan4-gpe-input [1] ip4-input-no-checksum
1130 : * ip4-lookup [2]
1131 : * @cliexend
1132 : *
1133 : * Example of how to display the feature enabled on an interface:
1134 : * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1135 : * IP feature paths configured on GigabitEthernet2/0/0...
1136 : * ...
1137 : * ipv4 unicast:
1138 : * ip4-vxlan-gpe-bypass
1139 : * ip4-lookup
1140 : * ...
1141 : * @cliexend
1142 : *
1143 : * Example of how to disable ip4-vxlan-gpe-bypass on an interface:
1144 : * @cliexcmd{set interface ip vxlan-gpe-bypass GigabitEthernet2/0/0 del}
1145 : * @endparblock
1146 : ?*/
1147 : /* *INDENT-OFF* */
1148 285289 : VLIB_CLI_COMMAND (set_interface_ip_vxlan_gpe_bypass_command, static) = {
1149 : .path = "set interface ip vxlan-gpe-bypass",
1150 : .function = set_ip4_vxlan_gpe_bypass,
1151 : .short_help = "set interface ip vxlan-gpe-bypass <interface> [del]",
1152 : };
1153 : /* *INDENT-ON* */
1154 :
1155 : static clib_error_t *
1156 0 : set_ip6_vxlan_gpe_bypass (vlib_main_t * vm,
1157 : unformat_input_t * input, vlib_cli_command_t * cmd)
1158 : {
1159 0 : return set_ip_vxlan_gpe_bypass (1, input, cmd);
1160 : }
1161 :
1162 : /*?
1163 : * This command adds the 'ip6-vxlan-gpe-bypass' graph node for a given
1164 : * interface. By adding the IPv6 vxlan-gpe-bypass graph node to an interface,
1165 : * the node checks for and validate input vxlan_gpe packet and bypass
1166 : * ip6-lookup, ip6-local, ip6-udp-lookup nodes to speedup vxlan_gpe packet
1167 : * forwarding. This node will cause extra overhead to for non-vxlan_gpe packets
1168 : * which is kept at a minimum.
1169 : *
1170 : * @cliexpar
1171 : * @parblock
1172 : * Example of graph node before ip6-vxlan-gpe-bypass is enabled:
1173 : * @cliexstart{show vlib graph ip6-vxlan-gpe-bypass}
1174 : * Name Next Previous
1175 : * ip6-vxlan-gpe-bypass error-drop [0]
1176 : * vxlan6-gpe-input [1]
1177 : * ip6-lookup [2]
1178 : * @cliexend
1179 : *
1180 : * Example of how to enable ip6-vxlan-gpe-bypass on an interface:
1181 : * @cliexcmd{set interface ip6 vxlan-gpe-bypass GigabitEthernet2/0/0}
1182 : *
1183 : * Example of graph node after ip6-vxlan-gpe-bypass is enabled:
1184 : * @cliexstart{show vlib graph ip6-vxlan-gpe-bypass}
1185 : * Name Next Previous
1186 : * ip6-vxlan-gpe-bypass error-drop [0] ip6-input
1187 : * vxlan6-gpe-input [1] ip4-input-no-checksum
1188 : * ip6-lookup [2]
1189 : * @cliexend
1190 : *
1191 : * Example of how to display the feature enabled on an interface:
1192 : * @cliexstart{show ip interface features GigabitEthernet2/0/0}
1193 : * IP feature paths configured on GigabitEthernet2/0/0...
1194 : * ...
1195 : * ipv6 unicast:
1196 : * ip6-vxlan-gpe-bypass
1197 : * ip6-lookup
1198 : * ...
1199 : * @cliexend
1200 : *
1201 : * Example of how to disable ip6-vxlan-gpe-bypass on an interface:
1202 : * @cliexcmd{set interface ip6 vxlan-gpe-bypass GigabitEthernet2/0/0 del}
1203 : * @endparblock
1204 : ?*/
1205 : /* *INDENT-OFF* */
1206 285289 : VLIB_CLI_COMMAND (set_interface_ip6_vxlan_gpe_bypass_command, static) = {
1207 : .path = "set interface ip6 vxlan-gpe-bypass",
1208 : .function = set_ip6_vxlan_gpe_bypass,
1209 : .short_help = "set interface ip6 vxlan-gpe-bypass <interface> [del]",
1210 : };
1211 : /* *INDENT-ON* */
1212 :
1213 : /* *INDENT-OFF* */
1214 76635 : VNET_FEATURE_INIT (ip4_vxlan_gpe_bypass, static) =
1215 : {
1216 : .arc_name = "ip4-unicast",
1217 : .node_name = "ip4-vxlan-gpe-bypass",
1218 : .runs_before = VNET_FEATURES ("ip4-lookup"),
1219 : };
1220 :
1221 76635 : VNET_FEATURE_INIT (ip6_vxlan_gpe_bypass, static) =
1222 : {
1223 : .arc_name = "ip6-unicast",
1224 : .node_name = "ip6-vxlan-gpe-bypass",
1225 : .runs_before = VNET_FEATURES ("ip6-lookup"),
1226 : };
1227 : /* *INDENT-ON* */
1228 :
1229 : /**
1230 : * @brief Feature init function for VXLAN GPE
1231 : *
1232 : * @param *vm
1233 : *
1234 : * @return error
1235 : *
1236 : */
1237 : clib_error_t *
1238 575 : vxlan_gpe_init (vlib_main_t * vm)
1239 : {
1240 575 : vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
1241 :
1242 575 : ngm->vnet_main = vnet_get_main ();
1243 575 : ngm->vlib_main = vm;
1244 :
1245 : ngm->vxlan4_gpe_tunnel_by_key
1246 575 : = hash_create_mem (0, sizeof (vxlan4_gpe_tunnel_key_t), sizeof (uword));
1247 :
1248 : ngm->vxlan6_gpe_tunnel_by_key
1249 575 : = hash_create_mem (0, sizeof (vxlan6_gpe_tunnel_key_t), sizeof (uword));
1250 :
1251 :
1252 575 : ngm->mcast_shared = hash_create_mem (0,
1253 : sizeof (ip46_address_t),
1254 : sizeof (mcast_shared_t));
1255 575 : ngm->vtep_table = vtep_table_create ();
1256 :
1257 : /* Register the list of standard decap protocols supported */
1258 575 : vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IP4,
1259 : VXLAN_GPE_INPUT_NEXT_IP4_INPUT);
1260 575 : vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IP6,
1261 : VXLAN_GPE_INPUT_NEXT_IP6_INPUT);
1262 575 : vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_ETHERNET,
1263 : VXLAN_GPE_INPUT_NEXT_L2_INPUT);
1264 :
1265 575 : fib_node_register_type (FIB_NODE_TYPE_VXLAN_GPE_TUNNEL, &vxlan_gpe_vft);
1266 :
1267 575 : return 0;
1268 : }
1269 :
1270 65663 : VLIB_INIT_FUNCTION (vxlan_gpe_init);
1271 :
1272 :
1273 : /*
1274 : * fd.io coding-style-patch-verification: ON
1275 : *
1276 : * Local Variables:
1277 : * eval: (c-set-style "gnu")
1278 : * End:
1279 : */
|