]> git.proxmox.com Git - mirror_frr.git/blob - vrrpd/vrrp_vty.c
Merge pull request #5793 from ton31337/fix/formatting_show_bgp_summary_failed
[mirror_frr.git] / vrrpd / vrrp_vty.c
1 /*
2 * VRRP CLI commands.
3 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
4 * Quentin Young
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 #include <zebra.h>
21
22 #include "lib/command.h"
23 #include "lib/if.h"
24 #include "lib/ipaddr.h"
25 #include "lib/json.h"
26 #include "lib/northbound_cli.h"
27 #include "lib/prefix.h"
28 #include "lib/termtable.h"
29 #include "lib/vty.h"
30 #include "lib/vrf.h"
31
32 #include "vrrp.h"
33 #include "vrrp_debug.h"
34 #include "vrrp_vty.h"
35 #include "vrrp_zebra.h"
36 #ifndef VTYSH_EXTRACT_PL
37 #include "vrrpd/vrrp_vty_clippy.c"
38 #endif
39
40
41 #define VRRP_STR "Virtual Router Redundancy Protocol\n"
42 #define VRRP_VRID_STR "Virtual Router ID\n"
43 #define VRRP_PRIORITY_STR "Virtual Router Priority\n"
44 #define VRRP_ADVINT_STR "Virtual Router Advertisement Interval\n"
45 #define VRRP_IP_STR "Virtual Router IP address\n"
46 #define VRRP_VERSION_STR "VRRP protocol version\n"
47
48 #define VRRP_XPATH_ENTRY VRRP_XPATH "[virtual-router-id='%ld']"
49
50 /* clang-format off */
51
52 /*
53 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group
54 */
55 DEFPY(vrrp_vrid,
56 vrrp_vrid_cmd,
57 "[no] vrrp (1-255)$vrid [version (2-3)]",
58 NO_STR
59 VRRP_STR
60 VRRP_VRID_STR
61 VRRP_VERSION_STR
62 VRRP_VERSION_STR)
63 {
64 char valbuf[20];
65
66 snprintf(valbuf, sizeof(valbuf), "%ld", version ? version : vd.version);
67
68 if (no)
69 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
70 else {
71 nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
72 nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, valbuf);
73 }
74
75 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
76 }
77
78 void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
79 {
80 const char *vrid = yang_dnode_get_string(dnode, "./virtual-router-id");
81 const char *ver = yang_dnode_get_string(dnode, "./version");
82
83 vty_out(vty, " vrrp %s", vrid);
84 if (show_defaults || !yang_dnode_is_default(dnode, "./version"))
85 vty_out(vty, " version %s", ver);
86 vty_out(vty, "\n");
87 }
88
89 /*
90 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown
91 */
92 DEFPY(vrrp_shutdown,
93 vrrp_shutdown_cmd,
94 "[no] vrrp (1-255)$vrid shutdown",
95 NO_STR
96 VRRP_STR
97 VRRP_VRID_STR
98 "Force VRRP router into administrative shutdown\n")
99 {
100 nb_cli_enqueue_change(vty, "./shutdown", NB_OP_MODIFY,
101 no ? "false" : "true");
102
103 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
104 }
105
106 void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
107 bool show_defaults)
108 {
109 const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
110 const bool shut = yang_dnode_get_bool(dnode, NULL);
111
112 vty_out(vty, " %svrrp %s shutdown\n", shut ? "" : "no ", vrid);
113 }
114
115 /*
116 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority
117 */
118 DEFPY(vrrp_priority,
119 vrrp_priority_cmd,
120 "vrrp (1-255)$vrid priority (1-254)",
121 VRRP_STR
122 VRRP_VRID_STR
123 VRRP_PRIORITY_STR
124 "Priority value")
125 {
126 nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, priority_str);
127
128 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
129 }
130
131 /*
132 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority
133 */
134 DEFPY(no_vrrp_priority,
135 no_vrrp_priority_cmd,
136 "no vrrp (1-255)$vrid priority [(1-254)]",
137 NO_STR
138 VRRP_STR
139 VRRP_VRID_STR
140 VRRP_PRIORITY_STR
141 "Priority value")
142 {
143 nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, NULL);
144
145 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
146 }
147
148 void cli_show_priority(struct vty *vty, struct lyd_node *dnode,
149 bool show_defaults)
150 {
151 const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
152 const char *prio = yang_dnode_get_string(dnode, NULL);
153
154 vty_out(vty, " vrrp %s priority %s\n", vrid, prio);
155 }
156
157 /*
158 * XPath:
159 * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval
160 */
161 DEFPY(vrrp_advertisement_interval,
162 vrrp_advertisement_interval_cmd,
163 "vrrp (1-255)$vrid advertisement-interval (10-40950)",
164 VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
165 "Advertisement interval in milliseconds; must be multiple of 10")
166 {
167 char val[20];
168
169 /* all internal computations are in centiseconds */
170 advertisement_interval /= CS2MS;
171 snprintf(val, sizeof(val), "%ld", advertisement_interval);
172 nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY,
173 val);
174
175 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
176 }
177
178 /*
179 * XPath:
180 * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval
181 */
182 DEFPY(no_vrrp_advertisement_interval,
183 no_vrrp_advertisement_interval_cmd,
184 "no vrrp (1-255)$vrid advertisement-interval [(10-40950)]",
185 NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
186 "Advertisement interval in milliseconds; must be multiple of 10")
187 {
188 nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY,
189 NULL);
190
191 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
192 }
193
194 void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode,
195 bool show_defaults)
196 {
197 const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
198 uint16_t advint = yang_dnode_get_uint16(dnode, NULL);
199
200 vty_out(vty, " vrrp %s advertisement-interval %u\n", vrid,
201 advint * CS2MS);
202 }
203
204 /*
205 * XPath:
206 * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address
207 */
208 DEFPY(vrrp_ip,
209 vrrp_ip_cmd,
210 "[no] vrrp (1-255)$vrid ip A.B.C.D",
211 NO_STR
212 VRRP_STR
213 VRRP_VRID_STR
214 "Add IPv4 address\n"
215 VRRP_IP_STR)
216 {
217 int op = no ? NB_OP_DESTROY : NB_OP_CREATE;
218 nb_cli_enqueue_change(vty, "./v4/virtual-address", op, ip_str);
219
220 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
221 }
222
223 void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
224 {
225 const char *vrid =
226 yang_dnode_get_string(dnode, "../../virtual-router-id");
227 const char *ipv4 = yang_dnode_get_string(dnode, NULL);
228
229 vty_out(vty, " vrrp %s ip %s\n", vrid, ipv4);
230 }
231
232 /*
233 * XPath:
234 * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address
235 */
236 DEFPY(vrrp_ip6,
237 vrrp_ip6_cmd,
238 "[no] vrrp (1-255)$vrid ipv6 X:X::X:X",
239 NO_STR
240 VRRP_STR
241 VRRP_VRID_STR
242 "Add IPv6 address\n"
243 VRRP_IP_STR)
244 {
245 int op = no ? NB_OP_DESTROY : NB_OP_CREATE;
246 nb_cli_enqueue_change(vty, "./v6/virtual-address", op, ipv6_str);
247
248 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
249 }
250
251 void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
252 {
253 const char *vrid =
254 yang_dnode_get_string(dnode, "../../virtual-router-id");
255 const char *ipv6 = yang_dnode_get_string(dnode, NULL);
256
257 vty_out(vty, " vrrp %s ipv6 %s\n", vrid, ipv6);
258 }
259
260 /*
261 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt
262 */
263 DEFPY(vrrp_preempt,
264 vrrp_preempt_cmd,
265 "[no] vrrp (1-255)$vrid preempt",
266 NO_STR
267 VRRP_STR
268 VRRP_VRID_STR
269 "Preempt mode\n")
270 {
271 nb_cli_enqueue_change(vty, "./preempt", NB_OP_MODIFY,
272 no ? "false" : "true");
273
274 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
275 }
276
277 void cli_show_preempt(struct vty *vty, struct lyd_node *dnode,
278 bool show_defaults)
279 {
280 const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
281 const bool pre = yang_dnode_get_bool(dnode, NULL);
282
283 vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid);
284 }
285
286 /* XXX: yang conversion */
287 DEFPY(vrrp_autoconfigure,
288 vrrp_autoconfigure_cmd,
289 "[no] vrrp autoconfigure [version (2-3)]",
290 NO_STR
291 VRRP_STR
292 "Automatically set up VRRP instances on VRRP-compatible interfaces\n"
293 "Version for automatically configured instances\n"
294 VRRP_VERSION_STR)
295 {
296 version = version ? version : 3;
297
298 if (!no)
299 vrrp_autoconfig_on(version);
300 else
301 vrrp_autoconfig_off();
302
303 return CMD_SUCCESS;
304 }
305
306 /* XXX: yang conversion */
307 DEFPY(vrrp_default,
308 vrrp_default_cmd,
309 "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
310 NO_STR
311 VRRP_STR
312 "Configure defaults for new VRRP instances\n"
313 VRRP_ADVINT_STR
314 "Advertisement interval in milliseconds\n"
315 "Preempt mode\n"
316 VRRP_PRIORITY_STR
317 "Priority value\n"
318 "Force VRRP router into administrative shutdown\n")
319 {
320 if (adv) {
321 if (advint % CS2MS != 0) {
322 vty_out(vty, "%% Value must be a multiple of %u\n",
323 (unsigned int)CS2MS);
324 return CMD_WARNING_CONFIG_FAILED;
325 }
326 /* all internal computations are in centiseconds */
327 advint /= CS2MS;
328 vd.advertisement_interval = no ? VRRP_DEFAULT_ADVINT : advint;
329 }
330 if (p)
331 vd.preempt_mode = !no;
332 if (prio)
333 vd.priority = no ? VRRP_DEFAULT_PRIORITY : prioval;
334 if (s)
335 vd.shutdown = !no;
336
337 return CMD_SUCCESS;
338 }
339
340 /* clang-format on */
341
342 /*
343 * Build JSON representation of VRRP instance.
344 *
345 * vr
346 * VRRP router to build json object from
347 *
348 * Returns:
349 * JSON representation of VRRP instance. Must be freed by caller.
350 */
351 static struct json_object *vrrp_build_json(struct vrrp_vrouter *vr)
352 {
353 char ethstr4[ETHER_ADDR_STRLEN];
354 char ethstr6[ETHER_ADDR_STRLEN];
355 char ipstr[INET6_ADDRSTRLEN];
356 const char *stastr4 = vrrp_state_names[vr->v4->fsm.state];
357 const char *stastr6 = vrrp_state_names[vr->v6->fsm.state];
358 char sipstr4[INET6_ADDRSTRLEN] = {};
359 char sipstr6[INET6_ADDRSTRLEN] = {};
360 struct listnode *ln;
361 struct ipaddr *ip;
362 struct json_object *j = json_object_new_object();
363 struct json_object *v4 = json_object_new_object();
364 struct json_object *v4_stats = json_object_new_object();
365 struct json_object *v4_addrs = json_object_new_array();
366 struct json_object *v6 = json_object_new_object();
367 struct json_object *v6_stats = json_object_new_object();
368 struct json_object *v6_addrs = json_object_new_array();
369
370 prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
371 prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
372
373 json_object_int_add(j, "vrid", vr->vrid);
374 json_object_int_add(j, "version", vr->version);
375 json_object_boolean_add(j, "autoconfigured", vr->autoconf);
376 json_object_boolean_add(j, "shutdown", vr->shutdown);
377 json_object_boolean_add(j, "preemptMode", vr->preempt_mode);
378 json_object_boolean_add(j, "acceptMode", vr->accept_mode);
379 json_object_string_add(j, "interface", vr->ifp->name);
380 json_object_int_add(j, "advertisementInterval",
381 vr->advertisement_interval * CS2MS);
382 /* v4 */
383 json_object_string_add(v4, "interface",
384 vr->v4->mvl_ifp ? vr->v4->mvl_ifp->name : "");
385 json_object_string_add(v4, "vmac", ethstr4);
386 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
387 json_object_string_add(v4, "primaryAddress", sipstr4);
388 json_object_string_add(v4, "status", stastr4);
389 json_object_int_add(v4, "effectivePriority", vr->v4->priority);
390 json_object_int_add(v4, "masterAdverInterval",
391 vr->v4->master_adver_interval * CS2MS);
392 json_object_int_add(v4, "skewTime", vr->v4->skew_time * CS2MS);
393 json_object_int_add(v4, "masterDownInterval",
394 vr->v4->master_down_interval * CS2MS);
395 /* v4 stats */
396 json_object_int_add(v4_stats, "adverTx", vr->v4->stats.adver_tx_cnt);
397 json_object_int_add(v4_stats, "adverRx", vr->v4->stats.adver_rx_cnt);
398 json_object_int_add(v4_stats, "garpTx", vr->v4->stats.garp_tx_cnt);
399 json_object_int_add(v4_stats, "transitions", vr->v4->stats.trans_cnt);
400 json_object_object_add(v4, "stats", v4_stats);
401 /* v4 addrs */
402 if (vr->v4->addrs->count) {
403 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ln, ip)) {
404 inet_ntop(vr->v4->family, &ip->ipaddr_v4, ipstr,
405 sizeof(ipstr));
406 json_object_array_add(v4_addrs,
407 json_object_new_string(ipstr));
408 }
409 }
410 json_object_object_add(v4, "addresses", v4_addrs);
411 json_object_object_add(j, "v4", v4);
412
413 /* v6 */
414 json_object_string_add(v6, "interface",
415 vr->v6->mvl_ifp ? vr->v6->mvl_ifp->name : "");
416 json_object_string_add(v6, "vmac", ethstr6);
417 ipaddr2str(&vr->v6->src, sipstr6, sizeof(sipstr6));
418 if (strlen(sipstr6) == 0 && vr->v6->src.ip.addr == 0x00)
419 strlcat(sipstr6, "::", sizeof(sipstr6));
420 json_object_string_add(v6, "primaryAddress", sipstr6);
421 json_object_string_add(v6, "status", stastr6);
422 json_object_int_add(v6, "effectivePriority", vr->v6->priority);
423 json_object_int_add(v6, "masterAdverInterval",
424 vr->v6->master_adver_interval * CS2MS);
425 json_object_int_add(v6, "skewTime", vr->v6->skew_time * CS2MS);
426 json_object_int_add(v6, "masterDownInterval",
427 vr->v6->master_down_interval * CS2MS);
428 /* v6 stats */
429 json_object_int_add(v6_stats, "adverTx", vr->v6->stats.adver_tx_cnt);
430 json_object_int_add(v6_stats, "adverRx", vr->v6->stats.adver_rx_cnt);
431 json_object_int_add(v6_stats, "neighborAdverTx",
432 vr->v6->stats.una_tx_cnt);
433 json_object_int_add(v6_stats, "transitions", vr->v6->stats.trans_cnt);
434 json_object_object_add(v6, "stats", v6_stats);
435 /* v6 addrs */
436 if (vr->v6->addrs->count) {
437 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ln, ip)) {
438 inet_ntop(vr->v6->family, &ip->ipaddr_v6, ipstr,
439 sizeof(ipstr));
440 json_object_array_add(v6_addrs,
441 json_object_new_string(ipstr));
442 }
443 }
444 json_object_object_add(v6, "addresses", v6_addrs);
445 json_object_object_add(j, "v6", v6);
446
447 return j;
448 }
449
450 /*
451 * Dump VRRP instance status to VTY.
452 *
453 * vty
454 * vty to dump to
455 *
456 * vr
457 * VRRP router to dump
458 */
459 static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
460 {
461 char ethstr4[ETHER_ADDR_STRLEN];
462 char ethstr6[ETHER_ADDR_STRLEN];
463 char ipstr[INET6_ADDRSTRLEN];
464 const char *stastr4 = vrrp_state_names[vr->v4->fsm.state];
465 const char *stastr6 = vrrp_state_names[vr->v6->fsm.state];
466 char sipstr4[INET6_ADDRSTRLEN] = {};
467 char sipstr6[INET6_ADDRSTRLEN] = {};
468 struct listnode *ln;
469 struct ipaddr *ip;
470
471 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
472
473 ttable_add_row(tt, "%s|%" PRIu32, "Virtual Router ID", vr->vrid);
474 ttable_add_row(tt, "%s|%" PRIu8, "Protocol Version", vr->version);
475 ttable_add_row(tt, "%s|%s", "Autoconfigured",
476 vr->autoconf ? "Yes" : "No");
477 ttable_add_row(tt, "%s|%s", "Shutdown", vr->shutdown ? "Yes" : "No");
478 ttable_add_row(tt, "%s|%s", "Interface", vr->ifp->name);
479 prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
480 prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
481 ttable_add_row(tt, "%s|%s", "VRRP interface (v4)",
482 vr->v4->mvl_ifp ? vr->v4->mvl_ifp->name : "None");
483 ttable_add_row(tt, "%s|%s", "VRRP interface (v6)",
484 vr->v6->mvl_ifp ? vr->v6->mvl_ifp->name : "None");
485 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
486 ipaddr2str(&vr->v6->src, sipstr6, sizeof(sipstr6));
487 if (strlen(sipstr6) == 0 && vr->v6->src.ip.addr == 0x00)
488 strlcat(sipstr6, "::", sizeof(sipstr6));
489 ttable_add_row(tt, "%s|%s", "Primary IP (v4)", sipstr4);
490 ttable_add_row(tt, "%s|%s", "Primary IP (v6)", sipstr6);
491 ttable_add_row(tt, "%s|%s", "Virtual MAC (v4)", ethstr4);
492 ttable_add_row(tt, "%s|%s", "Virtual MAC (v6)", ethstr6);
493 ttable_add_row(tt, "%s|%s", "Status (v4)", stastr4);
494 ttable_add_row(tt, "%s|%s", "Status (v6)", stastr6);
495 ttable_add_row(tt, "%s|%" PRIu8, "Priority", vr->priority);
496 ttable_add_row(tt, "%s|%" PRIu8, "Effective Priority (v4)",
497 vr->v4->priority);
498 ttable_add_row(tt, "%s|%" PRIu8, "Effective Priority (v6)",
499 vr->v6->priority);
500 ttable_add_row(tt, "%s|%s", "Preempt Mode",
501 vr->preempt_mode ? "Yes" : "No");
502 ttable_add_row(tt, "%s|%s", "Accept Mode",
503 vr->accept_mode ? "Yes" : "No");
504 ttable_add_row(tt, "%s|%d ms", "Advertisement Interval",
505 vr->advertisement_interval * CS2MS);
506 ttable_add_row(tt, "%s|%d ms",
507 "Master Advertisement Interval (v4)",
508 vr->v4->master_adver_interval * CS2MS);
509 ttable_add_row(tt, "%s|%d ms",
510 "Master Advertisement Interval (v6)",
511 vr->v6->master_adver_interval * CS2MS);
512 ttable_add_row(tt, "%s|%" PRIu32, "Advertisements Tx (v4)",
513 vr->v4->stats.adver_tx_cnt);
514 ttable_add_row(tt, "%s|%" PRIu32, "Advertisements Tx (v6)",
515 vr->v6->stats.adver_tx_cnt);
516 ttable_add_row(tt, "%s|%" PRIu32, "Advertisements Rx (v4)",
517 vr->v4->stats.adver_rx_cnt);
518 ttable_add_row(tt, "%s|%" PRIu32, "Advertisements Rx (v6)",
519 vr->v6->stats.adver_rx_cnt);
520 ttable_add_row(tt, "%s|%" PRIu32, "Gratuitous ARP Tx (v4)",
521 vr->v4->stats.garp_tx_cnt);
522 ttable_add_row(tt, "%s|%" PRIu32, "Neigh. Adverts Tx (v6)",
523 vr->v6->stats.una_tx_cnt);
524 ttable_add_row(tt, "%s|%" PRIu32, "State transitions (v4)",
525 vr->v4->stats.trans_cnt);
526 ttable_add_row(tt, "%s|%" PRIu32, "State transitions (v6)",
527 vr->v6->stats.trans_cnt);
528 ttable_add_row(tt, "%s|%d ms", "Skew Time (v4)",
529 vr->v4->skew_time * CS2MS);
530 ttable_add_row(tt, "%s|%d ms", "Skew Time (v6)",
531 vr->v6->skew_time * CS2MS);
532 ttable_add_row(tt, "%s|%d ms", "Master Down Interval (v4)",
533 vr->v4->master_down_interval * CS2MS);
534 ttable_add_row(tt, "%s|%d ms", "Master Down Interval (v6)",
535 vr->v6->master_down_interval * CS2MS);
536 ttable_add_row(tt, "%s|%u", "IPv4 Addresses", vr->v4->addrs->count);
537
538 char fill[35];
539
540 memset(fill, '.', sizeof(fill));
541 fill[sizeof(fill) - 1] = 0x00;
542 if (vr->v4->addrs->count) {
543 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ln, ip)) {
544 inet_ntop(vr->v4->family, &ip->ipaddr_v4, ipstr,
545 sizeof(ipstr));
546 ttable_add_row(tt, "%s|%s", fill, ipstr);
547 }
548 }
549
550 ttable_add_row(tt, "%s|%u", "IPv6 Addresses", vr->v6->addrs->count);
551
552 if (vr->v6->addrs->count) {
553 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ln, ip)) {
554 inet_ntop(vr->v6->family, &ip->ipaddr_v6, ipstr,
555 sizeof(ipstr));
556 ttable_add_row(tt, "%s|%s", fill, ipstr);
557 }
558 }
559
560 char *table = ttable_dump(tt, "\n");
561
562 vty_out(vty, "\n%s\n", table);
563 XFREE(MTYPE_TMP, table);
564 ttable_del(tt);
565 }
566
567 /*
568 * Sort comparator, used when sorting VRRP instances for display purposes.
569 *
570 * Sorts by interface name first, then by VRID ascending.
571 */
572 static int vrrp_instance_display_sort_cmp(const void **d1, const void **d2)
573 {
574 const struct vrrp_vrouter *vr1 = *d1;
575 const struct vrrp_vrouter *vr2 = *d2;
576 int result;
577
578 result = strcmp(vr1->ifp->name, vr2->ifp->name);
579 result += !result * (vr1->vrid - vr2->vrid);
580
581 return result;
582 }
583
584 /* clang-format off */
585
586 DEFPY(vrrp_vrid_show,
587 vrrp_vrid_show_cmd,
588 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] [json$json]",
589 SHOW_STR
590 VRRP_STR
591 INTERFACE_STR
592 "Only show VRRP instances on this interface\n"
593 VRRP_VRID_STR
594 JSON_STR)
595 {
596 struct vrrp_vrouter *vr;
597 struct listnode *ln;
598 struct list *ll = hash_to_list(vrrp_vrouters_hash);
599 struct json_object *j = json_object_new_array();
600
601 list_sort(ll, vrrp_instance_display_sort_cmp);
602
603 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr)) {
604 if (ifn && !strmatch(ifn, vr->ifp->name))
605 continue;
606 if (vrid && ((uint8_t) vrid) != vr->vrid)
607 continue;
608
609 if (!json)
610 vrrp_show(vty, vr);
611 else
612 json_object_array_add(j, vrrp_build_json(vr));
613 }
614
615 if (json)
616 vty_out(vty, "%s\n",
617 json_object_to_json_string_ext(
618 j, JSON_C_TO_STRING_PRETTY));
619
620 json_object_free(j);
621
622 list_delete(&ll);
623
624 return CMD_SUCCESS;
625 }
626
627 DEFPY(vrrp_vrid_show_summary,
628 vrrp_vrid_show_summary_cmd,
629 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] summary",
630 SHOW_STR
631 VRRP_STR
632 INTERFACE_STR
633 "Only show VRRP instances on this interface\n"
634 VRRP_VRID_STR
635 "Summarize all VRRP instances\n")
636 {
637 struct vrrp_vrouter *vr;
638 struct listnode *ln;
639 struct list *ll = hash_to_list(vrrp_vrouters_hash);
640
641 list_sort(ll, vrrp_instance_display_sort_cmp);
642
643 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
644
645 ttable_add_row(
646 tt, "Interface|VRID|Priority|IPv4|IPv6|State (v4)|State (v6)");
647 ttable_rowseps(tt, 0, BOTTOM, true, '-');
648
649 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr)) {
650 if (ifn && !strmatch(ifn, vr->ifp->name))
651 continue;
652 if (vrid && ((uint8_t)vrid) != vr->vrid)
653 continue;
654
655 ttable_add_row(
656 tt, "%s|%" PRIu8 "|%" PRIu8 "|%d|%d|%s|%s",
657 vr->ifp->name, vr->vrid, vr->priority,
658 vr->v4->addrs->count, vr->v6->addrs->count,
659 vr->v4->fsm.state == VRRP_STATE_MASTER ? "Master"
660 : "Backup",
661 vr->v6->fsm.state == VRRP_STATE_MASTER ? "Master"
662 : "Backup");
663 }
664
665 char *table = ttable_dump(tt, "\n");
666
667 vty_out(vty, "\n%s\n", table);
668 XFREE(MTYPE_TMP, table);
669 ttable_del(tt);
670
671 list_delete(&ll);
672
673 return CMD_SUCCESS;
674 }
675
676
677 DEFPY(debug_vrrp,
678 debug_vrrp_cmd,
679 "[no] debug vrrp [{protocol$proto|autoconfigure$ac|packets$pkt|sockets$sock|ndisc$ndisc|arp$arp|zebra$zebra}]",
680 NO_STR
681 DEBUG_STR
682 VRRP_STR
683 "Debug protocol state\n"
684 "Debug autoconfiguration\n"
685 "Debug sent and received packets\n"
686 "Debug socket creation and configuration\n"
687 "Debug Neighbor Discovery\n"
688 "Debug ARP\n"
689 "Debug Zebra events\n")
690 {
691 /* If no specific are given on/off them all */
692 if (strmatch(argv[argc - 1]->text, "vrrp"))
693 vrrp_debug_set(NULL, 0, vty->node, !no, true, true, true, true,
694 true, true, true);
695 else
696 vrrp_debug_set(NULL, 0, vty->node, !no, !!proto, !!ac, !!pkt,
697 !!sock, !!ndisc, !!arp, !!zebra);
698
699 return CMD_SUCCESS;
700 }
701
702 DEFUN_NOSH (show_debugging_vrrp,
703 show_debugging_vrrp_cmd,
704 "show debugging [vrrp]",
705 SHOW_STR
706 DEBUG_STR
707 "VRRP information\n")
708 {
709 vty_out(vty, "VRRP debugging status:\n");
710
711 vrrp_debug_status_write(vty);
712
713 return CMD_SUCCESS;
714 }
715
716 /* clang-format on */
717
718 /*
719 * Write per interface VRRP config.
720 */
721 static int vrrp_config_write_interface(struct vty *vty)
722 {
723 struct vrf *vrf;
724 int write = 0;
725
726 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
727 struct interface *ifp;
728
729 FOR_ALL_INTERFACES (vrf, ifp) {
730 struct lyd_node *dnode;
731
732 dnode = yang_dnode_get(
733 running_config->dnode,
734 "/frr-interface:lib/interface[name='%s'][vrf='%s']",
735 ifp->name, vrf->name);
736 if (dnode == NULL)
737 continue;
738
739 write = 1;
740 nb_cli_show_dnode_cmds(vty, dnode, false);
741 }
742 }
743
744 return write;
745 }
746
747 static struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1};
748 static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
749 static struct cmd_node vrrp_node = {VRRP_NODE, "", 1};
750
751 void vrrp_vty_init(void)
752 {
753 install_node(&debug_node, vrrp_config_write_debug);
754 install_node(&interface_node, vrrp_config_write_interface);
755 install_node(&vrrp_node, vrrp_config_write_global);
756 if_cmd_init();
757
758 install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
759 install_element(VIEW_NODE, &vrrp_vrid_show_summary_cmd);
760 install_element(VIEW_NODE, &show_debugging_vrrp_cmd);
761 install_element(VIEW_NODE, &debug_vrrp_cmd);
762 install_element(CONFIG_NODE, &debug_vrrp_cmd);
763 install_element(CONFIG_NODE, &vrrp_autoconfigure_cmd);
764 install_element(CONFIG_NODE, &vrrp_default_cmd);
765 install_element(INTERFACE_NODE, &vrrp_vrid_cmd);
766 install_element(INTERFACE_NODE, &vrrp_shutdown_cmd);
767 install_element(INTERFACE_NODE, &vrrp_priority_cmd);
768 install_element(INTERFACE_NODE, &no_vrrp_priority_cmd);
769 install_element(INTERFACE_NODE, &vrrp_advertisement_interval_cmd);
770 install_element(INTERFACE_NODE, &no_vrrp_advertisement_interval_cmd);
771 install_element(INTERFACE_NODE, &vrrp_ip_cmd);
772 install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
773 install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
774 }