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