Line data Source code
1 : /*
2 : * vrrp_cli.c - vrrp plugin debug CLI commands
3 : *
4 : * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5 : *
6 : * SPDX-License-Identifier: Apache-2.0
7 : *
8 : */
9 :
10 : #include <vnet/vnet.h>
11 : #include <vnet/plugin/plugin.h>
12 : #include <vrrp/vrrp.h>
13 :
14 : #include <vlibapi/api.h>
15 : #include <vlibmemory/api.h>
16 : #include <vpp/app/version.h>
17 :
18 :
19 : static clib_error_t *
20 0 : vrrp_vr_add_del_command_fn (vlib_main_t * vm,
21 : unformat_input_t * input,
22 : vlib_cli_command_t * cmd, u8 is_add)
23 : {
24 0 : vrrp_main_t *vmp = &vrrp_main;
25 : vrrp_vr_config_t vr_conf;
26 : u32 sw_if_index, vr_id, priority, interval;
27 : ip46_address_t addr, *addrs;
28 : u8 n_addrs4, n_addrs6;
29 0 : clib_error_t *ret = 0;
30 : int rv;
31 :
32 0 : clib_memset (&vr_conf, 0, sizeof (vr_conf));
33 :
34 : /* RFC 5798 - preempt enabled by default */
35 0 : vr_conf.flags = VRRP_VR_PREEMPT;
36 :
37 0 : addrs = 0;
38 0 : n_addrs4 = n_addrs6 = 0;
39 :
40 : /* defaults */
41 0 : sw_if_index = ~0;
42 0 : vr_id = 0;
43 0 : priority = 100;
44 0 : interval = 100;
45 :
46 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
47 : {
48 0 : clib_memset (&addr, 0, sizeof (addr));
49 :
50 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
51 : &sw_if_index))
52 : ;
53 0 : else if (unformat (input, "vr_id %u", &vr_id))
54 : ;
55 0 : else if (unformat (input, "ipv6"))
56 0 : vr_conf.flags |= VRRP_VR_IPV6;
57 0 : else if (unformat (input, "priority %u", &priority))
58 : ;
59 0 : else if (unformat (input, "interval %u", &interval))
60 : ;
61 0 : else if (unformat (input, "no_preempt"))
62 0 : vr_conf.flags &= ~VRRP_VR_PREEMPT;
63 0 : else if (unformat (input, "accept_mode"))
64 0 : vr_conf.flags |= VRRP_VR_ACCEPT;
65 0 : else if (unformat (input, "unicast"))
66 0 : vr_conf.flags |= VRRP_VR_UNICAST;
67 0 : else if (unformat (input, "%U", unformat_ip4_address, &addr.ip4))
68 : {
69 0 : n_addrs4++;
70 0 : vec_add1 (addrs, addr);
71 : }
72 0 : else if (unformat (input, "%U", unformat_ip6_address, &addr.ip6))
73 : {
74 0 : n_addrs6++;
75 0 : vec_add1 (addrs, addr);
76 : }
77 : else
78 0 : break;
79 : }
80 :
81 0 : if (sw_if_index == ~0)
82 0 : ret = clib_error_return (0, "Please specify an interface...");
83 0 : else if (!vr_id || vr_id > 0xff)
84 0 : ret = clib_error_return (0, "VR ID must be between 1 and 255...");
85 :
86 0 : if (is_add)
87 : {
88 0 : if (!priority || priority > 0xff)
89 0 : ret = clib_error_return (0, "priority must be between 1 and 255...");
90 0 : else if (interval > 0xffff)
91 0 : ret = clib_error_return (0, "interval must be <= 65535...");
92 0 : else if (n_addrs4 && (n_addrs6 || vr_conf.flags & VRRP_VR_IPV6))
93 0 : ret = clib_error_return (0, "Mismatched address families");
94 : }
95 :
96 0 : if (ret) /* data validation failed */
97 0 : goto done;
98 :
99 0 : vr_conf.sw_if_index = sw_if_index;
100 0 : vr_conf.vr_id = (u8) vr_id;
101 0 : vr_conf.priority = (u8) priority;
102 0 : vr_conf.adv_interval = (u16) interval;
103 0 : vr_conf.vr_addrs = addrs;
104 :
105 0 : rv = vrrp_vr_add_del (is_add, &vr_conf, NULL);
106 :
107 0 : switch (rv)
108 : {
109 0 : case 0:
110 0 : break;
111 :
112 : /* adding */
113 0 : case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
114 0 : ret = clib_error_return (0, "Failed to add VR that already exists");
115 0 : goto done;
116 : break;
117 :
118 0 : case VNET_API_ERROR_INVALID_SRC_ADDRESS:
119 0 : ret = clib_error_return (0, "Failed to add VR with no IP addresses");
120 0 : goto done;
121 : break;
122 :
123 0 : case VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE:
124 0 : ret = clib_error_return (0, "Failed to add VR with priority 255 - "
125 : "VR IP addresses not configured on interface");
126 0 : goto done;
127 : break;
128 :
129 : /* deleting */
130 0 : case VNET_API_ERROR_NO_SUCH_ENTRY:
131 0 : ret = clib_error_return (0, "Failed to delete VR which does not exist");
132 0 : goto done;
133 : break;
134 :
135 0 : default:
136 0 : ret = clib_error_return (0, "vrrp_vr_add_del returned %d", rv);
137 0 : goto done;
138 : break;
139 : }
140 :
141 0 : done:
142 0 : vec_free (addrs);
143 :
144 0 : return ret;
145 : }
146 :
147 : static clib_error_t *
148 0 : vrrp_vr_add_command_fn (vlib_main_t * vm, unformat_input_t * input,
149 : vlib_cli_command_t * cmd)
150 : {
151 0 : return vrrp_vr_add_del_command_fn (vm, input, cmd, 1 /* is_add */ );
152 : }
153 :
154 : /* *INDENT-OFF* */
155 7839 : VLIB_CLI_COMMAND (vrrp_vr_add_command, static) =
156 : {
157 : .path = "vrrp vr add",
158 : .short_help =
159 : "vrrp vr add <interface> [vr_id <n>] [ipv6] [priority <value>] [interval <value>] [no_preempt] [accept_mode] [unicast] [<ip_addr> ...]",
160 : .function = vrrp_vr_add_command_fn,
161 : };
162 : /* *INDENT-ON* */
163 :
164 : static clib_error_t *
165 0 : vrrp_vr_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
166 : vlib_cli_command_t * cmd)
167 : {
168 0 : return vrrp_vr_add_del_command_fn (vm, input, cmd, 0 /* is_add */ );
169 : }
170 :
171 : /* *INDENT-OFF* */
172 7839 : VLIB_CLI_COMMAND (vrrp_vr_del_command, static) =
173 : {
174 : .path = "vrrp vr del",
175 : .short_help = "vrrp vr del <interface> [vr_id <n>] [ipv6]",
176 : .function = vrrp_vr_del_command_fn,
177 : };
178 : /* *INDENT-ON* */
179 :
180 : static clib_error_t *
181 0 : vrrp_show_vr_command_fn (vlib_main_t * vm,
182 : unformat_input_t * input, vlib_cli_command_t * cmd)
183 : {
184 0 : vrrp_main_t *vmp = &vrrp_main;
185 : vrrp_vr_t *vr;
186 0 : u32 sw_if_index = ~0;
187 :
188 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
189 : {
190 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
191 : &sw_if_index))
192 : ;
193 0 : else if (unformat (input, "sw_if_index %u", &sw_if_index))
194 : ;
195 : else
196 0 : break;
197 : }
198 :
199 0 : pool_foreach (vr, vmp->vrs)
200 : {
201 :
202 0 : if (sw_if_index && (sw_if_index != ~0) &&
203 0 : (sw_if_index != vr->config.sw_if_index))
204 0 : continue;
205 0 : vlib_cli_output (vm, "%U", format_vrrp_vr, vr);
206 : }
207 :
208 0 : return 0;
209 : }
210 :
211 : /* *INDENT-OFF* */
212 7839 : VLIB_CLI_COMMAND (vrrp_show_vr_command, static) =
213 : {
214 : .path = "show vrrp vr",
215 : .short_help =
216 : "show vrrp vr [(<intf_name>|sw_if_index <n>)]",
217 : .function = vrrp_show_vr_command_fn,
218 : };
219 : /* *INDENT-ON* */
220 :
221 : static clib_error_t *
222 0 : vrrp_proto_start_stop_command_fn (vlib_main_t * vm,
223 : unformat_input_t * input,
224 : vlib_cli_command_t * cmd)
225 : {
226 0 : vrrp_main_t *vmp = &vrrp_main;
227 : vrrp_vr_key_t vr_key;
228 : u32 sw_if_index;
229 : u32 vr_id;
230 : u8 is_ipv6, is_start, is_stop;
231 : int rv;
232 :
233 0 : clib_memset (&vr_key, 0, sizeof (vr_key));
234 :
235 : /* defaults */
236 0 : sw_if_index = ~0;
237 0 : vr_id = 0;
238 0 : is_ipv6 = is_start = is_stop = 0;
239 :
240 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
241 : {
242 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
243 : &sw_if_index))
244 : ;
245 0 : else if (unformat (input, "sw_if_index %u", &sw_if_index))
246 : ;
247 0 : else if (unformat (input, "vr_id %u", &vr_id))
248 : ;
249 0 : else if (unformat (input, "ipv6"))
250 0 : is_ipv6 = 1;
251 0 : else if (unformat (input, "start"))
252 0 : is_start = 1;
253 0 : else if (unformat (input, "stop"))
254 0 : is_stop = 1;
255 : else
256 0 : return clib_error_return (0, "unknown input `%U'",
257 : format_unformat_error, input);
258 : }
259 :
260 0 : if (is_start == is_stop)
261 0 : return clib_error_return (0, "One of start or stop must be specified");
262 0 : else if (sw_if_index == ~0)
263 0 : return clib_error_return (0, "Please specify an interface...");
264 0 : else if (!vr_id)
265 0 : return clib_error_return (0, "Invalid VR ID...");
266 :
267 0 : vr_key.sw_if_index = sw_if_index;
268 0 : vr_key.vr_id = vr_id;
269 0 : vr_key.is_ipv6 = (is_ipv6 != 0);
270 :
271 0 : rv = vrrp_vr_start_stop (is_start, &vr_key);
272 :
273 0 : switch (rv)
274 : {
275 0 : case 0:
276 0 : break;
277 0 : case VNET_API_ERROR_INIT_FAILED:
278 0 : return clib_error_return (0, "Cannot start unicast VR without peers");
279 : break;
280 0 : default:
281 0 : return clib_error_return (0, "vrrp_vr_start_stop returned %d", rv);
282 : break;
283 : }
284 :
285 0 : return 0;
286 : }
287 :
288 : static clib_error_t *
289 0 : vrrp_peers_command_fn (vlib_main_t * vm, unformat_input_t * input,
290 : vlib_cli_command_t * cmd)
291 : {
292 0 : vrrp_main_t *vmp = &vrrp_main;
293 : vrrp_vr_key_t vr_key;
294 : u32 sw_if_index;
295 : u32 vr_id;
296 : u8 is_ipv6;
297 : int rv;
298 : ip46_address_t addr, *addrs;
299 : u8 n_addrs4, n_addrs6;
300 0 : clib_error_t *ret = 0;
301 :
302 0 : clib_memset (&vr_key, 0, sizeof (vr_key));
303 :
304 : /* defaults */
305 0 : addrs = 0;
306 0 : n_addrs4 = n_addrs6 = 0;
307 0 : sw_if_index = ~0;
308 0 : vr_id = 0;
309 0 : is_ipv6 = 0;
310 :
311 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
312 : {
313 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
314 : &sw_if_index))
315 : ;
316 0 : else if (unformat (input, "sw_if_index %u", &sw_if_index))
317 : ;
318 0 : else if (unformat (input, "vr_id %u", &vr_id))
319 : ;
320 0 : else if (unformat (input, "ipv6"))
321 0 : is_ipv6 = 1;
322 0 : else if (unformat (input, "%U", unformat_ip4_address, &addr.ip4))
323 : {
324 0 : n_addrs4++;
325 0 : vec_add1 (addrs, addr);
326 : }
327 0 : else if (unformat (input, "%U", unformat_ip6_address, &addr.ip6))
328 : {
329 0 : n_addrs6++;
330 0 : vec_add1 (addrs, addr);
331 : }
332 : else
333 : {
334 0 : ret = clib_error_return (0, "unknown input `%U'",
335 : format_unformat_error, input);
336 0 : goto done;
337 : }
338 : }
339 :
340 0 : if (sw_if_index == ~0)
341 0 : ret = clib_error_return (0, "Please specify an interface...");
342 0 : else if (!vr_id)
343 0 : ret = clib_error_return (0, "Invalid VR ID...");
344 0 : else if (n_addrs4 && (n_addrs6 || is_ipv6))
345 0 : ret = clib_error_return (0, "Mismatched address families");
346 :
347 0 : if (ret) /* data validation failed */
348 0 : goto done;
349 :
350 0 : vr_key.sw_if_index = sw_if_index;
351 0 : vr_key.vr_id = vr_id;
352 0 : vr_key.is_ipv6 = (is_ipv6 != 0);
353 :
354 0 : rv = vrrp_vr_set_peers (&vr_key, addrs);
355 :
356 0 : switch (rv)
357 : {
358 0 : case 0:
359 0 : break;
360 0 : case VNET_API_ERROR_INVALID_ARGUMENT:
361 0 : ret = clib_error_return (0, "Peers can only be set on a unicast VR");
362 0 : break;
363 0 : case VNET_API_ERROR_RSRC_IN_USE:
364 0 : ret = clib_error_return (0, "Cannot set peers on a running VR");
365 0 : break;
366 0 : case VNET_API_ERROR_INVALID_DST_ADDRESS:
367 0 : ret = clib_error_return (0, "No peer addresses provided");
368 0 : break;
369 0 : default:
370 0 : ret = clib_error_return (0, "vrrp_vr_set_peers returned %d", rv);
371 0 : break;
372 : }
373 :
374 0 : done:
375 0 : vec_free (addrs);
376 :
377 0 : return ret;
378 : }
379 :
380 : /* *INDENT-OFF* */
381 7839 : VLIB_CLI_COMMAND (vrrp_proto_start_stop_command, static) =
382 : {
383 : .path = "vrrp proto",
384 : .short_help =
385 : "vrrp proto (start|stop) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6]",
386 : .function = vrrp_proto_start_stop_command_fn,
387 : };
388 : /* *INDENT-ON* */
389 :
390 : /* *INDENT-OFF* */
391 7839 : VLIB_CLI_COMMAND (vrrp_peers_command, static) =
392 : {
393 : .path = "vrrp peers",
394 : .short_help =
395 : "vrrp peers (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] <peer1_addr> [<peer2_addr> ...]",
396 : .function = vrrp_peers_command_fn,
397 : };
398 : /* *INDENT-ON* */
399 :
400 : static clib_error_t *
401 0 : vrrp_vr_track_if_command_fn (vlib_main_t * vm,
402 : unformat_input_t * input,
403 : vlib_cli_command_t * cmd)
404 : {
405 0 : vnet_main_t *vnm = vnet_get_main ();
406 0 : vrrp_main_t *vmp = &vrrp_main;
407 : u32 sw_if_index, track_if_index, vr_id, priority;
408 0 : u8 is_ipv6 = 0;
409 0 : clib_error_t *ret = 0;
410 0 : vrrp_vr_tracking_if_t *track_intfs = 0, *track_intf;
411 : vrrp_vr_t *vr;
412 : u8 is_add, is_del;
413 : int rv;
414 :
415 : /* defaults */
416 0 : sw_if_index = ~0;
417 0 : vr_id = 0;
418 0 : is_add = is_del = 0;
419 :
420 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
421 : {
422 0 : if (unformat (input, "%U", unformat_vnet_sw_interface, vmp->vnet_main,
423 : &sw_if_index))
424 : ;
425 0 : else if (unformat (input, "sw_if_index %u", &sw_if_index))
426 : ;
427 0 : else if (unformat (input, "add"))
428 0 : is_add = 1;
429 0 : else if (unformat (input, "del"))
430 0 : is_del = 1;
431 0 : else if (unformat (input, "vr_id %u", &vr_id))
432 : ;
433 0 : else if (unformat (input, "ipv6"))
434 0 : is_ipv6 = 1;
435 0 : else if (unformat (input, "track-index %u priority %u", &track_if_index,
436 : &priority))
437 : {
438 0 : vec_add2 (track_intfs, track_intf, 1);;
439 0 : track_intf->sw_if_index = track_if_index;
440 0 : track_intf->priority = priority;
441 : }
442 : else
443 0 : break;
444 : }
445 :
446 0 : if (sw_if_index == ~0)
447 0 : ret = clib_error_return (0, "Please specify an interface");
448 0 : else if (!vr_id || vr_id > 0xff)
449 0 : ret = clib_error_return (0, "VR ID must be between 1 and 255");
450 0 : else if (is_add == is_del)
451 0 : ret = clib_error_return (0, "One of add,delete must be specified");
452 :
453 0 : if (ret)
454 0 : goto done;
455 :
456 0 : vr = vrrp_vr_lookup (sw_if_index, vr_id, is_ipv6);
457 0 : if (!vr)
458 : {
459 0 : ret = clib_error_return (0, "VR not found");
460 0 : goto done;
461 : }
462 :
463 0 : vec_foreach (track_intf, track_intfs)
464 : {
465 0 : if (!vnet_sw_interface_is_valid (vnm, track_intf->sw_if_index))
466 : {
467 0 : ret = clib_error_return (0, "tracked intf sw_if_index %u invalid",
468 : track_intf->sw_if_index);
469 0 : goto done;
470 : }
471 0 : if (!track_intf->priority)
472 : {
473 0 : ret = clib_error_return (0, "tracked intf priority must be > 0");
474 0 : goto done;
475 : }
476 0 : if (track_intf->priority >= vr->config.priority)
477 : {
478 0 : ret = clib_error_return (0, "tracked intf priority must be less "
479 : "than VR priority (%u)",
480 : vr->config.priority);
481 0 : goto done;
482 : }
483 : }
484 :
485 0 : rv = vrrp_vr_tracking_ifs_add_del (vr, track_intfs, is_add);
486 0 : if (rv)
487 0 : ret = clib_error_return (0, "vrrp_vr_tracking_ifs_add_del returned %d",
488 : rv);
489 :
490 0 : done:
491 0 : vec_free (track_intfs);
492 :
493 0 : return ret;
494 : }
495 :
496 : /* *INDENT-OFF* */
497 7839 : VLIB_CLI_COMMAND (vrrp_vr_track_if_command, static) =
498 : {
499 : .path = "vrrp vr track-if",
500 : .short_help =
501 : "vrrp vr track-if (add|del) (<intf_name>|sw_if_index <n>) vr_id <n> [ipv6] track-index <n> priority <n> [ track-index <n> priority <n> ...]",
502 : .function = vrrp_vr_track_if_command_fn,
503 : };
504 : /* *INDENT-ON* */
505 :
506 : /*
507 : * fd.io coding-style-patch-verification: ON
508 : *
509 : * Local Variables:
510 : * eval: (c-set-style "gnu")
511 : * End:
512 : */
|