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