Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 : #include <vnet/vxlan-gpe/vxlan_gpe.h>
16 : #include <vnet/vxlan-gpe/vxlan_gpe_packet.h>
17 : #include <vnet/ip/format.h>
18 : #include <ioam/lib-vxlan-gpe/vxlan_gpe_ioam.h>
19 : #include <vnet/dpo/load_balance.h>
20 : #include <vnet/fib/ip4_fib.h>
21 : #include <vnet/fib/fib_entry.h>
22 : #include <vnet/udp/udp_local.h>
23 :
24 : vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main;
25 :
26 : int
27 0 : vxlan_gpe_ioam_set_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option,
28 : int has_pot_option, int has_ppc_option,
29 : u8 ipv6_set)
30 : {
31 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
32 : u32 size;
33 : vxlan_gpe_ioam_hdr_t *vxlan_gpe_ioam_hdr;
34 : u8 *current;
35 0 : u8 trace_data_size = 0;
36 0 : u8 pot_data_size = 0;
37 :
38 0 : if (has_trace_option == 0 && has_pot_option == 0)
39 0 : return -1;
40 :
41 : /* Work out how much space we need */
42 0 : size = sizeof (vxlan_gpe_ioam_hdr_t);
43 :
44 0 : if (has_trace_option
45 0 : && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0)
46 : {
47 0 : size += sizeof (vxlan_gpe_ioam_option_t);
48 0 : size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE];
49 : }
50 0 : if (has_pot_option
51 0 : && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0)
52 : {
53 0 : size += sizeof (vxlan_gpe_ioam_option_t);
54 0 : size += hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT];
55 : }
56 :
57 0 : t->rewrite_size = size;
58 :
59 0 : if (!ipv6_set)
60 : {
61 0 : vxlan4_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM,
62 : hm->encap_v4_next_node);
63 0 : vxlan_gpe_ioam_hdr =
64 0 : (vxlan_gpe_ioam_hdr_t *) (t->rewrite +
65 : sizeof (ip4_vxlan_gpe_header_t));
66 : }
67 : else
68 : {
69 0 : vxlan6_gpe_rewrite (t, size, VXLAN_GPE_PROTOCOL_IOAM,
70 : VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP);
71 0 : vxlan_gpe_ioam_hdr =
72 0 : (vxlan_gpe_ioam_hdr_t *) (t->rewrite +
73 : sizeof (ip6_vxlan_gpe_header_t));
74 : }
75 :
76 :
77 0 : vxlan_gpe_ioam_hdr->type = VXLAN_GPE_PROTOCOL_IOAM;
78 : /* Length of the header in octets */
79 0 : vxlan_gpe_ioam_hdr->length = size;
80 0 : vxlan_gpe_ioam_hdr->protocol = t->protocol;
81 0 : current = (u8 *) vxlan_gpe_ioam_hdr + sizeof (vxlan_gpe_ioam_hdr_t);
82 :
83 0 : if (has_trace_option
84 0 : && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] != 0)
85 : {
86 0 : if (0 != hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_TRACE] (current,
87 : &trace_data_size))
88 0 : return -1;
89 0 : current += trace_data_size;
90 : }
91 0 : if (has_pot_option
92 0 : && hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT] != 0)
93 : {
94 0 : pot_data_size =
95 0 : hm->options_size[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT];
96 0 : if (0 ==
97 0 : hm->add_options[VXLAN_GPE_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT]
98 : (current, &pot_data_size))
99 0 : current += pot_data_size;
100 : }
101 :
102 0 : return 0;
103 : }
104 :
105 : int
106 0 : vxlan_gpe_ioam_clear_rewrite (vxlan_gpe_tunnel_t * t, int has_trace_option,
107 : int has_pot_option, int has_ppc_option,
108 : u8 ipv6_set)
109 : {
110 :
111 0 : t->rewrite_size = 0;
112 :
113 0 : if (!ipv6_set)
114 : {
115 0 : vxlan4_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP);
116 : }
117 : else
118 : {
119 0 : vxlan6_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP);
120 : }
121 :
122 :
123 0 : return 0;
124 : }
125 :
126 : clib_error_t *
127 0 : vxlan_gpe_ioam_clear (vxlan_gpe_tunnel_t * t,
128 : int has_trace_option, int has_pot_option,
129 : int has_ppc_option, u8 ipv6_set)
130 : {
131 : int rv;
132 0 : rv = vxlan_gpe_ioam_clear_rewrite (t, 0, 0, 0, 0);
133 :
134 0 : if (rv == 0)
135 : {
136 0 : return (0);
137 : }
138 : else
139 : {
140 0 : return clib_error_return_code (0, rv, 0,
141 : "vxlan_gpe_ioam_clear_rewrite returned %d",
142 : rv);
143 : }
144 :
145 : }
146 :
147 :
148 : clib_error_t *
149 0 : vxlan_gpe_ioam_set (vxlan_gpe_tunnel_t * t,
150 : int has_trace_option, int has_pot_option,
151 : int has_ppc_option, u8 ipv6_set)
152 : {
153 : int rv;
154 0 : rv = vxlan_gpe_ioam_set_rewrite (t, has_trace_option,
155 : has_pot_option, has_ppc_option, ipv6_set);
156 :
157 0 : if (rv == 0)
158 : {
159 0 : return (0);
160 : }
161 : else
162 : {
163 0 : return clib_error_return_code (0, rv, 0,
164 : "vxlan_gpe_ioam_set_rewrite returned %d",
165 : rv);
166 : }
167 :
168 : }
169 :
170 : static void
171 0 : vxlan_gpe_set_clear_output_feature_on_intf (vlib_main_t * vm,
172 : u32 sw_if_index0, u8 is_add)
173 : {
174 :
175 :
176 :
177 0 : vnet_feature_enable_disable ("ip4-output", "vxlan-gpe-transit-ioam",
178 : sw_if_index0, is_add,
179 : 0 /* void *feature_config */ ,
180 : 0 /* u32 n_feature_config_bytes */ );
181 0 : return;
182 : }
183 :
184 : void
185 0 : vxlan_gpe_clear_output_feature_on_all_intfs (vlib_main_t * vm)
186 : {
187 0 : vnet_sw_interface_t *si = 0;
188 0 : vnet_main_t *vnm = vnet_get_main ();
189 0 : vnet_interface_main_t *im = &vnm->interface_main;
190 :
191 0 : pool_foreach (si, im->sw_interfaces)
192 : {
193 0 : vxlan_gpe_set_clear_output_feature_on_intf (vm, si->sw_if_index, 0);
194 : }
195 0 : return;
196 : }
197 :
198 :
199 : extern fib_forward_chain_type_t
200 : fib_entry_get_default_chain_type (const fib_entry_t * fib_entry);
201 :
202 : int
203 0 : vxlan_gpe_enable_disable_ioam_for_dest (vlib_main_t * vm,
204 : ip46_address_t dst_addr,
205 : u32 outer_fib_index,
206 : u8 is_ipv4, u8 is_add)
207 : {
208 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
209 0 : u32 fib_index0 = 0;
210 0 : u32 sw_if_index0 = ~0;
211 :
212 0 : fib_node_index_t fei = ~0;
213 : fib_entry_t *fib_entry;
214 : u32 adj_index0;
215 : ip_adjacency_t *adj0;
216 : fib_prefix_t fib_prefix;
217 : //fib_forward_chain_type_t fct;
218 : load_balance_t *lb_m, *lb_b;
219 : const dpo_id_t *dpo0, *dpo1;
220 : u32 i, j;
221 : //vnet_hw_interface_t *hw;
222 :
223 0 : if (is_ipv4)
224 : {
225 0 : clib_memset (&fib_prefix, 0, sizeof (fib_prefix_t));
226 0 : fib_prefix.fp_len = 32;
227 0 : fib_prefix.fp_proto = FIB_PROTOCOL_IP4;
228 0 : fib_prefix.fp_addr = dst_addr;
229 : }
230 : else
231 : {
232 0 : return 0;
233 : }
234 :
235 0 : fei = fib_table_lookup (fib_index0, &fib_prefix);
236 0 : fib_entry = fib_entry_get (fei);
237 :
238 : //fct = fib_entry_get_default_chain_type (fib_entry);
239 :
240 0 : if (!dpo_id_is_valid (&fib_entry->fe_lb /*[fct] */ ))
241 : {
242 0 : return (-1);
243 : }
244 :
245 0 : lb_m = load_balance_get (fib_entry->fe_lb /*[fct] */ .dpoi_index);
246 :
247 0 : for (i = 0; i < lb_m->lb_n_buckets; i++)
248 : {
249 0 : dpo0 = load_balance_get_bucket_i (lb_m, i);
250 :
251 0 : if (dpo0->dpoi_type == DPO_LOAD_BALANCE)
252 : {
253 0 : lb_b = load_balance_get (dpo0->dpoi_index);
254 :
255 0 : for (j = 0; j < lb_b->lb_n_buckets; j++)
256 : {
257 0 : dpo1 = load_balance_get_bucket_i (lb_b, j);
258 :
259 0 : if (dpo1->dpoi_type == DPO_ADJACENCY)
260 : {
261 0 : adj_index0 = dpo1->dpoi_index;
262 :
263 0 : if (ADJ_INDEX_INVALID == adj_index0)
264 : {
265 0 : continue;
266 : }
267 :
268 0 : adj0 = adj_get (adj_index0);
269 0 : sw_if_index0 = adj0->rewrite_header.sw_if_index;
270 :
271 0 : if (~0 == sw_if_index0)
272 : {
273 0 : continue;
274 : }
275 :
276 :
277 0 : if (is_add)
278 : {
279 0 : vnet_feature_enable_disable ("ip4-output",
280 : "vxlan-gpe-transit-ioam",
281 : sw_if_index0, is_add, 0
282 : /* void *feature_config */
283 : , 0 /* u32 n_feature_config_bytes */
284 : );
285 :
286 0 : vec_validate_init_empty (hm->bool_ref_by_sw_if_index,
287 : sw_if_index0, ~0);
288 0 : hm->bool_ref_by_sw_if_index[sw_if_index0] = 1;
289 : }
290 : else
291 : {
292 0 : hm->bool_ref_by_sw_if_index[sw_if_index0] = ~0;
293 : }
294 : }
295 : }
296 : }
297 : }
298 :
299 0 : if (is_ipv4)
300 : {
301 :
302 0 : uword *t = NULL;
303 : vxlan_gpe_ioam_dest_tunnels_t *t1;
304 : fib_prefix_t key4, *key4_copy;
305 : hash_pair_t *hp;
306 0 : clib_memset (&key4, 0, sizeof (key4));
307 0 : key4.fp_proto = FIB_PROTOCOL_IP4;
308 0 : key4.fp_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
309 0 : t = hash_get_mem (hm->dst_by_ip4, &key4);
310 0 : if (is_add)
311 : {
312 0 : if (t)
313 : {
314 0 : return 0;
315 : }
316 0 : pool_get_aligned (hm->dst_tunnels, t1, CLIB_CACHE_LINE_BYTES);
317 0 : clib_memset (t1, 0, sizeof (*t1));
318 0 : t1->fp_proto = FIB_PROTOCOL_IP4;
319 0 : t1->dst_addr.ip4.as_u32 = fib_prefix.fp_addr.ip4.as_u32;
320 0 : key4_copy = clib_mem_alloc (sizeof (*key4_copy));
321 0 : clib_memcpy (key4_copy, &key4, sizeof (*key4_copy));
322 0 : hash_set_mem (hm->dst_by_ip4, key4_copy, t1 - hm->dst_tunnels);
323 : /*
324 : * Attach to the FIB entry for the VxLAN-GPE destination
325 : * and become its child. The dest route will invoke a callback
326 : * when the fib entry changes, it can be used to
327 : * re-program the output feature on the egress interface.
328 : */
329 :
330 0 : const fib_prefix_t tun_dst_pfx = {
331 : .fp_len = 32,
332 : .fp_proto = FIB_PROTOCOL_IP4,
333 0 : .fp_addr = {.ip4 = t1->dst_addr.ip4,}
334 : };
335 :
336 0 : t1->fib_entry_index =
337 0 : fib_table_entry_special_add (outer_fib_index,
338 : &tun_dst_pfx,
339 : FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE);
340 0 : t1->sibling_index =
341 0 : fib_entry_child_add (t1->fib_entry_index,
342 0 : hm->fib_entry_type, t1 - hm->dst_tunnels);
343 0 : t1->outer_fib_index = outer_fib_index;
344 :
345 : }
346 : else
347 : {
348 0 : if (!t)
349 : {
350 0 : return 0;
351 : }
352 0 : t1 = pool_elt_at_index (hm->dst_tunnels, t[0]);
353 0 : hp = hash_get_pair (hm->dst_by_ip4, &key4);
354 0 : key4_copy = (void *) (hp->key);
355 0 : hash_unset_mem (hm->dst_by_ip4, &key4);
356 0 : clib_mem_free (key4_copy);
357 0 : pool_put (hm->dst_tunnels, t1);
358 : }
359 : }
360 : else
361 : {
362 : // TBD for IPv6
363 : }
364 :
365 0 : return 0;
366 : }
367 :
368 : void
369 0 : vxlan_gpe_refresh_output_feature_on_all_dest (void)
370 : {
371 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
372 : vxlan_gpe_ioam_dest_tunnels_t *t;
373 : u32 i;
374 0 : if (pool_elts (hm->dst_tunnels) == 0)
375 0 : return;
376 0 : vxlan_gpe_clear_output_feature_on_all_intfs (hm->vlib_main);
377 0 : i = vec_len (hm->bool_ref_by_sw_if_index);
378 0 : vec_free (hm->bool_ref_by_sw_if_index);
379 0 : vec_validate_init_empty (hm->bool_ref_by_sw_if_index, i, ~0);
380 0 : pool_foreach (t, hm->dst_tunnels)
381 : {
382 0 : vxlan_gpe_enable_disable_ioam_for_dest
383 : (hm->vlib_main, t->dst_addr, t->outer_fib_index,
384 0 : (t->fp_proto == FIB_PROTOCOL_IP4), 1 /* is_add */ );
385 : }
386 0 : return;
387 : }
388 :
389 : void
390 0 : vxlan_gpe_clear_output_feature_on_select_intfs (void)
391 : {
392 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
393 0 : u32 sw_if_index0 = 0;
394 0 : for (sw_if_index0 = 0;
395 0 : sw_if_index0 < vec_len (hm->bool_ref_by_sw_if_index); sw_if_index0++)
396 : {
397 0 : if (hm->bool_ref_by_sw_if_index[sw_if_index0] == 0xFF)
398 : {
399 0 : vxlan_gpe_set_clear_output_feature_on_intf
400 : (hm->vlib_main, sw_if_index0, 0);
401 : }
402 : }
403 :
404 0 : return;
405 : }
406 :
407 : static clib_error_t *
408 0 : vxlan_gpe_set_ioam_rewrite_command_fn (vlib_main_t *
409 : vm,
410 : unformat_input_t
411 : * input, vlib_cli_command_t * cmd)
412 : {
413 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
414 : ip46_address_t local, remote;
415 0 : u8 local_set = 0;
416 0 : u8 remote_set = 0;
417 0 : u8 ipv4_set = 0;
418 0 : u8 ipv6_set = 0;
419 : u32 vni;
420 0 : u8 vni_set = 0;
421 0 : u8 disable = 0;
422 0 : clib_error_t *rv = 0;
423 : vxlan4_gpe_tunnel_key_t key4;
424 : vxlan6_gpe_tunnel_key_t key6;
425 : uword *p;
426 0 : vxlan_gpe_main_t *gm = &vxlan_gpe_main;
427 0 : vxlan_gpe_tunnel_t *t = 0;
428 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
429 : {
430 0 : if (unformat (input, "local %U", unformat_ip4_address, &local.ip4))
431 : {
432 0 : local_set = 1;
433 0 : ipv4_set = 1;
434 : }
435 : else
436 0 : if (unformat (input, "remote %U", unformat_ip4_address, &remote.ip4))
437 : {
438 0 : remote_set = 1;
439 0 : ipv4_set = 1;
440 : }
441 0 : else if (unformat (input, "local %U", unformat_ip6_address, &local.ip6))
442 : {
443 0 : local_set = 1;
444 0 : ipv6_set = 1;
445 : }
446 : else
447 0 : if (unformat (input, "remote %U", unformat_ip6_address, &remote.ip6))
448 : {
449 0 : remote_set = 1;
450 0 : ipv6_set = 1;
451 : }
452 0 : else if (unformat (input, "vni %d", &vni))
453 0 : vni_set = 1;
454 0 : else if (unformat (input, "disable"))
455 0 : disable = 1;
456 : else
457 0 : break;
458 : }
459 :
460 0 : if (local_set == 0)
461 0 : return clib_error_return (0, "tunnel local address not specified");
462 0 : if (remote_set == 0)
463 0 : return clib_error_return (0, "tunnel remote address not specified");
464 0 : if (ipv4_set && ipv6_set)
465 0 : return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
466 0 : if ((ipv4_set
467 0 : && memcmp (&local.ip4, &remote.ip4,
468 0 : sizeof (local.ip4)) == 0) || (ipv6_set
469 0 : &&
470 0 : memcmp
471 : (&local.ip6,
472 : &remote.ip6,
473 : sizeof (local.ip6)) == 0))
474 0 : return clib_error_return (0, "src and dst addresses are identical");
475 0 : if (vni_set == 0)
476 0 : return clib_error_return (0, "vni not specified");
477 0 : if (!ipv6_set)
478 : {
479 0 : key4.local = local.ip4.as_u32;
480 0 : key4.remote = remote.ip4.as_u32;
481 0 : key4.vni = clib_host_to_net_u32 (vni << 8);
482 0 : key4.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE);
483 0 : p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4);
484 : }
485 : else
486 : {
487 0 : key6.local.as_u64[0] = local.ip6.as_u64[0];
488 0 : key6.local.as_u64[1] = local.ip6.as_u64[1];
489 0 : key6.remote.as_u64[0] = remote.ip6.as_u64[0];
490 0 : key6.remote.as_u64[1] = remote.ip6.as_u64[1];
491 0 : key6.vni = clib_host_to_net_u32 (vni << 8);
492 0 : key6.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN6_GPE);
493 0 : p = hash_get_mem (gm->vxlan6_gpe_tunnel_by_key, &key6);
494 : }
495 :
496 0 : if (!p)
497 0 : return clib_error_return (0, "VxLAN Tunnel not found");
498 0 : t = pool_elt_at_index (gm->tunnels, p[0]);
499 0 : if (!disable)
500 : {
501 : rv =
502 0 : vxlan_gpe_ioam_set (t, hm->has_trace_option,
503 0 : hm->has_pot_option, hm->has_ppc_option, ipv6_set);
504 : }
505 : else
506 : {
507 0 : rv = vxlan_gpe_ioam_clear (t, 0, 0, 0, 0);
508 : }
509 0 : return rv;
510 : }
511 :
512 :
513 : /* *INDENT-OFF* */
514 186217 : VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_rewrite_cmd, static) = {
515 : .path = "set vxlan-gpe-ioam",
516 : .short_help = "set vxlan-gpe-ioam vxlan <src-ip> <dst_ip> <vnid> [disable]",
517 : .function = vxlan_gpe_set_ioam_rewrite_command_fn,
518 : };
519 : /* *INDENT-ON* */
520 :
521 :
522 :
523 : clib_error_t *
524 0 : vxlan_gpe_ioam_enable (int has_trace_option,
525 : int has_pot_option, int has_ppc_option)
526 : {
527 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
528 0 : hm->has_trace_option = has_trace_option;
529 0 : hm->has_pot_option = has_pot_option;
530 0 : hm->has_ppc_option = has_ppc_option;
531 0 : if (hm->has_trace_option)
532 : {
533 0 : vxlan_gpe_trace_profile_setup ();
534 : }
535 :
536 0 : return 0;
537 : }
538 :
539 : clib_error_t *
540 0 : vxlan_gpe_ioam_disable (int
541 : has_trace_option,
542 : int has_pot_option, int has_ppc_option)
543 : {
544 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
545 0 : hm->has_trace_option = has_trace_option;
546 0 : hm->has_pot_option = has_pot_option;
547 0 : hm->has_ppc_option = has_ppc_option;
548 0 : if (!hm->has_trace_option)
549 : {
550 0 : vxlan_gpe_trace_profile_cleanup ();
551 : }
552 :
553 0 : return 0;
554 : }
555 :
556 : void
557 0 : vxlan_gpe_set_next_override (uword next)
558 : {
559 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
560 0 : hm->decap_v4_next_override = next;
561 0 : return;
562 : }
563 :
564 : static clib_error_t *
565 0 : vxlan_gpe_set_ioam_flags_command_fn (vlib_main_t * vm,
566 : unformat_input_t
567 : * input, vlib_cli_command_t * cmd)
568 : {
569 0 : int has_trace_option = 0;
570 0 : int has_pot_option = 0;
571 0 : int has_ppc_option = 0;
572 0 : clib_error_t *rv = 0;
573 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
574 : {
575 0 : if (unformat (input, "trace"))
576 0 : has_trace_option = 1;
577 0 : else if (unformat (input, "pot"))
578 0 : has_pot_option = 1;
579 0 : else if (unformat (input, "ppc encap"))
580 0 : has_ppc_option = PPC_ENCAP;
581 0 : else if (unformat (input, "ppc decap"))
582 0 : has_ppc_option = PPC_DECAP;
583 0 : else if (unformat (input, "ppc none"))
584 0 : has_ppc_option = PPC_NONE;
585 : else
586 0 : break;
587 : }
588 :
589 :
590 : rv =
591 0 : vxlan_gpe_ioam_enable (has_trace_option, has_pot_option, has_ppc_option);
592 0 : return rv;
593 : }
594 :
595 : /* *INDENT-OFF* */
596 186217 : VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_flags_cmd, static) =
597 : {
598 : .path = "set vxlan-gpe-ioam rewrite",
599 : .short_help = "set vxlan-gpe-ioam [trace] [pot] [ppc <encap|decap>]",
600 : .function = vxlan_gpe_set_ioam_flags_command_fn,};
601 : /* *INDENT-ON* */
602 :
603 :
604 0 : int vxlan_gpe_ioam_disable_for_dest
605 : (vlib_main_t * vm, ip46_address_t dst_addr, u32 outer_fib_index,
606 : u8 ipv4_set)
607 : {
608 : vxlan_gpe_ioam_dest_tunnels_t *t;
609 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
610 :
611 0 : vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main,
612 : dst_addr, outer_fib_index, ipv4_set,
613 : 0);
614 0 : if (pool_elts (hm->dst_tunnels) == 0)
615 : {
616 0 : vxlan_gpe_clear_output_feature_on_select_intfs ();
617 0 : return 0;
618 : }
619 :
620 0 : pool_foreach (t, hm->dst_tunnels)
621 : {
622 0 : vxlan_gpe_enable_disable_ioam_for_dest
623 : (hm->vlib_main,
624 : t->dst_addr,
625 : t->outer_fib_index,
626 0 : (t->fp_proto == FIB_PROTOCOL_IP4), 1 /* is_add */ );
627 : }
628 0 : vxlan_gpe_clear_output_feature_on_select_intfs ();
629 0 : return (0);
630 :
631 : }
632 :
633 0 : static clib_error_t *vxlan_gpe_set_ioam_transit_rewrite_command_fn
634 : (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
635 : {
636 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
637 : ip46_address_t dst_addr;
638 0 : u8 dst_addr_set = 0;
639 0 : u8 ipv4_set = 0;
640 0 : u8 ipv6_set = 0;
641 0 : u8 disable = 0;
642 0 : clib_error_t *rv = 0;
643 0 : u32 outer_fib_index = 0;
644 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
645 : {
646 0 : if (unformat (input, "dst-ip %U", unformat_ip4_address, &dst_addr.ip4))
647 : {
648 0 : dst_addr_set = 1;
649 0 : ipv4_set = 1;
650 : }
651 : else
652 0 : if (unformat
653 : (input, "dst-ip %U", unformat_ip6_address, &dst_addr.ip6))
654 : {
655 0 : dst_addr_set = 1;
656 0 : ipv6_set = 1;
657 : }
658 0 : else if (unformat (input, "outer-fib-index %d", &outer_fib_index))
659 : {
660 : }
661 :
662 0 : else if (unformat (input, "disable"))
663 0 : disable = 1;
664 : else
665 0 : break;
666 : }
667 :
668 0 : if (dst_addr_set == 0)
669 0 : return clib_error_return (0, "tunnel destination address not specified");
670 0 : if (ipv4_set && ipv6_set)
671 0 : return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
672 0 : if (!disable)
673 : {
674 0 : vxlan_gpe_enable_disable_ioam_for_dest (hm->vlib_main,
675 : dst_addr, outer_fib_index,
676 : ipv4_set, 1);
677 : }
678 : else
679 : {
680 0 : vxlan_gpe_ioam_disable_for_dest
681 : (vm, dst_addr, outer_fib_index, ipv4_set);
682 : }
683 0 : return rv;
684 : }
685 :
686 : /* *INDENT-OFF* */
687 186217 : VLIB_CLI_COMMAND (vxlan_gpe_set_ioam_transit_rewrite_cmd, static) = {
688 : .path = "set vxlan-gpe-ioam-transit",
689 : .short_help = "set vxlan-gpe-ioam-transit dst-ip <dst_ip> [outer-fib-index <outer_fib_index>] [disable]",
690 : .function = vxlan_gpe_set_ioam_transit_rewrite_command_fn,
691 : };
692 : /* *INDENT-ON* */
693 :
694 0 : clib_error_t *clear_vxlan_gpe_ioam_rewrite_command_fn
695 : (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
696 : {
697 0 : return (vxlan_gpe_ioam_disable (0, 0, 0));
698 : }
699 :
700 : /* *INDENT-OFF* */
701 186217 : VLIB_CLI_COMMAND (vxlan_gpe_clear_ioam_flags_cmd, static) =
702 : {
703 : .path = "clear vxlan-gpe-ioam rewrite",
704 : .short_help = "clear vxlan-gpe-ioam rewrite",
705 : .function = clear_vxlan_gpe_ioam_rewrite_command_fn,
706 : };
707 : /* *INDENT-ON* */
708 :
709 :
710 : /**
711 : * Function definition to backwalk a FIB node
712 : */
713 : static fib_node_back_walk_rc_t
714 0 : vxlan_gpe_ioam_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
715 : {
716 0 : vxlan_gpe_refresh_output_feature_on_all_dest ();
717 0 : return (FIB_NODE_BACK_WALK_CONTINUE);
718 : }
719 :
720 : /**
721 : * Function definition to get a FIB node from its index
722 : */
723 : static fib_node_t *
724 0 : vxlan_gpe_ioam_fib_node_get (fib_node_index_t index)
725 : {
726 0 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
727 0 : return (&hm->node);
728 : }
729 :
730 : /**
731 : * Function definition to inform the FIB node that its last lock has gone.
732 : */
733 : static void
734 0 : vxlan_gpe_ioam_last_lock_gone (fib_node_t * node)
735 : {
736 0 : ASSERT (0);
737 0 : }
738 :
739 :
740 : /*
741 : * Virtual function table registered by MPLS GRE tunnels
742 : * for participation in the FIB object graph.
743 : */
744 : const static fib_node_vft_t vxlan_gpe_ioam_vft = {
745 : .fnv_get = vxlan_gpe_ioam_fib_node_get,
746 : .fnv_last_lock = vxlan_gpe_ioam_last_lock_gone,
747 : .fnv_back_walk = vxlan_gpe_ioam_back_walk,
748 : };
749 :
750 : void
751 575 : vxlan_gpe_ioam_interface_init (void)
752 : {
753 575 : vxlan_gpe_ioam_main_t *hm = &vxlan_gpe_ioam_main;
754 575 : hm->fib_entry_type =
755 575 : fib_node_register_new_type ("vxlan-gpe", &vxlan_gpe_ioam_vft);
756 575 : return;
757 : }
758 :
759 : /*
760 : * fd.io coding-style-patch-verification: ON
761 : *
762 : * Local Variables:
763 : * eval: (c-set-style "gnu")
764 : * End:
765 : */
|