]> git.proxmox.com Git - mirror_frr.git/blob - vrrpd/vrrp_vty.c
Merge pull request #12191 from manojvn/463777
[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 /*
285 * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/checksum-with-
286 * ipv4-pseudoheader
287 */
288 DEFPY_YANG(vrrp_checksum_with_ipv4_pseudoheader,
289 vrrp_checksum_with_ipv4_pseudoheader_cmd,
290 "[no] vrrp (1-255)$vrid checksum-with-ipv4-pseudoheader",
291 NO_STR
292 VRRP_STR
293 VRRP_VRID_STR
294 "Checksum mode in VRRPv3\n")
295 {
296 nb_cli_enqueue_change(vty, "./checksum-with-ipv4-pseudoheader",
297 NB_OP_MODIFY, no ? "false" : "true");
298
299 return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
300 }
301
302 void cli_show_checksum_with_ipv4_pseudoheader(struct vty *vty,
303 const struct lyd_node *dnode,
304 bool show_defaults)
305 {
306 const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
307 const bool pre = yang_dnode_get_bool(dnode, NULL);
308
309 vty_out(vty, " %svrrp %s checksum-with-ipv4-pseudoheader\n",
310 pre ? "" : "no ", vrid);
311 }
312
313 /* XXX: yang conversion */
314 DEFPY_YANG(vrrp_autoconfigure,
315 vrrp_autoconfigure_cmd,
316 "[no] vrrp autoconfigure [version (2-3)]",
317 NO_STR
318 VRRP_STR
319 "Automatically set up VRRP instances on VRRP-compatible interfaces\n"
320 "Version for automatically configured instances\n"
321 VRRP_VERSION_STR)
322 {
323 version = version ? version : 3;
324
325 if (!no)
326 vrrp_autoconfig_on(version);
327 else
328 vrrp_autoconfig_off();
329
330 return CMD_SUCCESS;
331 }
332
333 /* XXX: yang conversion */
334 DEFPY_YANG(vrrp_default,
335 vrrp_default_cmd,
336 "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|checksum-with-ipv4-pseudoheader$ipv4ph|shutdown$s>",
337 NO_STR
338 VRRP_STR
339 "Configure defaults for new VRRP instances\n"
340 VRRP_ADVINT_STR
341 "Advertisement interval in milliseconds\n"
342 "Preempt mode\n"
343 VRRP_PRIORITY_STR
344 "Priority value\n"
345 "Checksum mode in VRRPv3\n"
346 "Force VRRP router into administrative shutdown\n")
347 {
348 if (adv) {
349 if (advint % CS2MS != 0) {
350 vty_out(vty, "%% Value must be a multiple of %u\n",
351 (unsigned int)CS2MS);
352 return CMD_WARNING_CONFIG_FAILED;
353 }
354 /* all internal computations are in centiseconds */
355 advint /= CS2MS;
356 vd.advertisement_interval = no ? VRRP_DEFAULT_ADVINT : advint;
357 }
358 if (p)
359 vd.preempt_mode = !no;
360 if (prio)
361 vd.priority = no ? VRRP_DEFAULT_PRIORITY : prioval;
362 if (ipv4ph)
363 vd.checksum_with_ipv4_pseudoheader = !no;
364 if (s)
365 vd.shutdown = !no;
366
367 return CMD_SUCCESS;
368 }
369
370 /* clang-format on */
371
372 /*
373 * Build JSON representation of VRRP instance.
374 *
375 * vr
376 * VRRP router to build json object from
377 *
378 * Returns:
379 * JSON representation of VRRP instance. Must be freed by caller.
380 */
381 static struct json_object *vrrp_build_json(struct vrrp_vrouter *vr)
382 {
383 char ethstr4[ETHER_ADDR_STRLEN];
384 char ethstr6[ETHER_ADDR_STRLEN];
385 char ipstr[INET6_ADDRSTRLEN];
386 const char *stastr4 = vrrp_state_names[vr->v4->fsm.state];
387 const char *stastr6 = vrrp_state_names[vr->v6->fsm.state];
388 char sipstr4[INET6_ADDRSTRLEN] = {};
389 char sipstr6[INET6_ADDRSTRLEN] = {};
390 struct listnode *ln;
391 struct ipaddr *ip;
392 struct json_object *j = json_object_new_object();
393 struct json_object *v4 = json_object_new_object();
394 struct json_object *v4_stats = json_object_new_object();
395 struct json_object *v4_addrs = json_object_new_array();
396 struct json_object *v6 = json_object_new_object();
397 struct json_object *v6_stats = json_object_new_object();
398 struct json_object *v6_addrs = json_object_new_array();
399
400 prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
401 prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
402
403 json_object_int_add(j, "vrid", vr->vrid);
404 json_object_int_add(j, "version", vr->version);
405 json_object_boolean_add(j, "autoconfigured", vr->autoconf);
406 json_object_boolean_add(j, "shutdown", vr->shutdown);
407 json_object_boolean_add(j, "preemptMode", vr->preempt_mode);
408 json_object_boolean_add(j, "acceptMode", vr->accept_mode);
409 json_object_boolean_add(j, "checksumWithIpv4Pseudoheader",
410 vr->checksum_with_ipv4_pseudoheader);
411 json_object_string_add(j, "interface", vr->ifp->name);
412 json_object_int_add(j, "advertisementInterval",
413 vr->advertisement_interval * CS2MS);
414 /* v4 */
415 json_object_string_add(v4, "interface",
416 vr->v4->mvl_ifp ? vr->v4->mvl_ifp->name : "");
417 json_object_string_add(v4, "vmac", ethstr4);
418 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
419 json_object_string_add(v4, "primaryAddress", sipstr4);
420 json_object_string_add(v4, "status", stastr4);
421 json_object_int_add(v4, "effectivePriority", vr->v4->priority);
422 json_object_int_add(v4, "masterAdverInterval",
423 vr->v4->master_adver_interval * CS2MS);
424 json_object_int_add(v4, "skewTime", vr->v4->skew_time * CS2MS);
425 json_object_int_add(v4, "masterDownInterval",
426 vr->v4->master_down_interval * CS2MS);
427 /* v4 stats */
428 json_object_int_add(v4_stats, "adverTx", vr->v4->stats.adver_tx_cnt);
429 json_object_int_add(v4_stats, "adverRx", vr->v4->stats.adver_rx_cnt);
430 json_object_int_add(v4_stats, "garpTx", vr->v4->stats.garp_tx_cnt);
431 json_object_int_add(v4_stats, "transitions", vr->v4->stats.trans_cnt);
432 json_object_object_add(v4, "stats", v4_stats);
433 /* v4 addrs */
434 if (vr->v4->addrs->count) {
435 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ln, ip)) {
436 inet_ntop(vr->v4->family, &ip->ipaddr_v4, ipstr,
437 sizeof(ipstr));
438 json_object_array_add(v4_addrs,
439 json_object_new_string(ipstr));
440 }
441 }
442 json_object_object_add(v4, "addresses", v4_addrs);
443 json_object_object_add(j, "v4", v4);
444
445 /* v6 */
446 json_object_string_add(v6, "interface",
447 vr->v6->mvl_ifp ? vr->v6->mvl_ifp->name : "");
448 json_object_string_add(v6, "vmac", ethstr6);
449 ipaddr2str(&vr->v6->src, sipstr6, sizeof(sipstr6));
450 if (strlen(sipstr6) == 0 && vr->v6->src.ip.addr == 0x00)
451 strlcat(sipstr6, "::", sizeof(sipstr6));
452 json_object_string_add(v6, "primaryAddress", sipstr6);
453 json_object_string_add(v6, "status", stastr6);
454 json_object_int_add(v6, "effectivePriority", vr->v6->priority);
455 json_object_int_add(v6, "masterAdverInterval",
456 vr->v6->master_adver_interval * CS2MS);
457 json_object_int_add(v6, "skewTime", vr->v6->skew_time * CS2MS);
458 json_object_int_add(v6, "masterDownInterval",
459 vr->v6->master_down_interval * CS2MS);
460 /* v6 stats */
461 json_object_int_add(v6_stats, "adverTx", vr->v6->stats.adver_tx_cnt);
462 json_object_int_add(v6_stats, "adverRx", vr->v6->stats.adver_rx_cnt);
463 json_object_int_add(v6_stats, "neighborAdverTx",
464 vr->v6->stats.una_tx_cnt);
465 json_object_int_add(v6_stats, "transitions", vr->v6->stats.trans_cnt);
466 json_object_object_add(v6, "stats", v6_stats);
467 /* v6 addrs */
468 if (vr->v6->addrs->count) {
469 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ln, ip)) {
470 inet_ntop(vr->v6->family, &ip->ipaddr_v6, ipstr,
471 sizeof(ipstr));
472 json_object_array_add(v6_addrs,
473 json_object_new_string(ipstr));
474 }
475 }
476 json_object_object_add(v6, "addresses", v6_addrs);
477 json_object_object_add(j, "v6", v6);
478
479 return j;
480 }
481
482 /*
483 * Dump VRRP instance status to VTY.
484 *
485 * vty
486 * vty to dump to
487 *
488 * vr
489 * VRRP router to dump
490 */
491 static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
492 {
493 char ethstr4[ETHER_ADDR_STRLEN];
494 char ethstr6[ETHER_ADDR_STRLEN];
495 char ipstr[INET6_ADDRSTRLEN];
496 const char *stastr4 = vrrp_state_names[vr->v4->fsm.state];
497 const char *stastr6 = vrrp_state_names[vr->v6->fsm.state];
498 char sipstr4[INET6_ADDRSTRLEN] = {};
499 char sipstr6[INET6_ADDRSTRLEN] = {};
500 struct listnode *ln;
501 struct ipaddr *ip;
502
503 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
504
505 ttable_add_row(tt, "%s|%u", "Virtual Router ID", vr->vrid);
506 ttable_add_row(tt, "%s|%hhu", "Protocol Version", vr->version);
507 ttable_add_row(tt, "%s|%s", "Autoconfigured",
508 vr->autoconf ? "Yes" : "No");
509 ttable_add_row(tt, "%s|%s", "Shutdown", vr->shutdown ? "Yes" : "No");
510 ttable_add_row(tt, "%s|%s", "Interface", vr->ifp->name);
511 prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
512 prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
513 ttable_add_row(tt, "%s|%s", "VRRP interface (v4)",
514 vr->v4->mvl_ifp ? vr->v4->mvl_ifp->name : "None");
515 ttable_add_row(tt, "%s|%s", "VRRP interface (v6)",
516 vr->v6->mvl_ifp ? vr->v6->mvl_ifp->name : "None");
517 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
518 ipaddr2str(&vr->v6->src, sipstr6, sizeof(sipstr6));
519 if (strlen(sipstr6) == 0 && vr->v6->src.ip.addr == 0x00)
520 strlcat(sipstr6, "::", sizeof(sipstr6));
521 ttable_add_row(tt, "%s|%s", "Primary IP (v4)", sipstr4);
522 ttable_add_row(tt, "%s|%s", "Primary IP (v6)", sipstr6);
523 ttable_add_row(tt, "%s|%s", "Virtual MAC (v4)", ethstr4);
524 ttable_add_row(tt, "%s|%s", "Virtual MAC (v6)", ethstr6);
525 ttable_add_row(tt, "%s|%s", "Status (v4)", stastr4);
526 ttable_add_row(tt, "%s|%s", "Status (v6)", stastr6);
527 ttable_add_row(tt, "%s|%hhu", "Priority", vr->priority);
528 ttable_add_row(tt, "%s|%hhu", "Effective Priority (v4)",
529 vr->v4->priority);
530 ttable_add_row(tt, "%s|%hhu", "Effective Priority (v6)",
531 vr->v6->priority);
532 ttable_add_row(tt, "%s|%s", "Preempt Mode",
533 vr->preempt_mode ? "Yes" : "No");
534 ttable_add_row(tt, "%s|%s", "Accept Mode",
535 vr->accept_mode ? "Yes" : "No");
536 ttable_add_row(tt, "%s|%s", "Checksum with IPv4 Pseudoheader",
537 vr->checksum_with_ipv4_pseudoheader ? "Yes" : "No");
538 ttable_add_row(tt, "%s|%d ms", "Advertisement Interval",
539 vr->advertisement_interval * CS2MS);
540 ttable_add_row(tt, "%s|%d ms (stale)",
541 "Master Advertisement Interval (v4) Rx",
542 vr->v4->master_adver_interval * CS2MS);
543 ttable_add_row(tt, "%s|%d ms (stale)",
544 "Master Advertisement Interval (v6) Rx",
545 vr->v6->master_adver_interval * CS2MS);
546 ttable_add_row(tt, "%s|%u", "Advertisements Tx (v4)",
547 vr->v4->stats.adver_tx_cnt);
548 ttable_add_row(tt, "%s|%u", "Advertisements Tx (v6)",
549 vr->v6->stats.adver_tx_cnt);
550 ttable_add_row(tt, "%s|%u", "Advertisements Rx (v4)",
551 vr->v4->stats.adver_rx_cnt);
552 ttable_add_row(tt, "%s|%u", "Advertisements Rx (v6)",
553 vr->v6->stats.adver_rx_cnt);
554 ttable_add_row(tt, "%s|%u", "Gratuitous ARP Tx (v4)",
555 vr->v4->stats.garp_tx_cnt);
556 ttable_add_row(tt, "%s|%u", "Neigh. Adverts Tx (v6)",
557 vr->v6->stats.una_tx_cnt);
558 ttable_add_row(tt, "%s|%u", "State transitions (v4)",
559 vr->v4->stats.trans_cnt);
560 ttable_add_row(tt, "%s|%u", "State transitions (v6)",
561 vr->v6->stats.trans_cnt);
562 ttable_add_row(tt, "%s|%d ms", "Skew Time (v4)",
563 vr->v4->skew_time * CS2MS);
564 ttable_add_row(tt, "%s|%d ms", "Skew Time (v6)",
565 vr->v6->skew_time * CS2MS);
566 ttable_add_row(tt, "%s|%d ms", "Master Down Interval (v4)",
567 vr->v4->master_down_interval * CS2MS);
568 ttable_add_row(tt, "%s|%d ms", "Master Down Interval (v6)",
569 vr->v6->master_down_interval * CS2MS);
570 ttable_add_row(tt, "%s|%u", "IPv4 Addresses", vr->v4->addrs->count);
571
572 char fill[35];
573
574 memset(fill, '.', sizeof(fill));
575 fill[sizeof(fill) - 1] = 0x00;
576 if (vr->v4->addrs->count) {
577 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ln, ip)) {
578 inet_ntop(vr->v4->family, &ip->ipaddr_v4, ipstr,
579 sizeof(ipstr));
580 ttable_add_row(tt, "%s|%s", fill, ipstr);
581 }
582 }
583
584 ttable_add_row(tt, "%s|%u", "IPv6 Addresses", vr->v6->addrs->count);
585
586 if (vr->v6->addrs->count) {
587 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ln, ip)) {
588 inet_ntop(vr->v6->family, &ip->ipaddr_v6, ipstr,
589 sizeof(ipstr));
590 ttable_add_row(tt, "%s|%s", fill, ipstr);
591 }
592 }
593
594 char *table = ttable_dump(tt, "\n");
595
596 vty_out(vty, "\n%s\n", table);
597 XFREE(MTYPE_TMP, table);
598 ttable_del(tt);
599 }
600
601 /*
602 * Sort comparator, used when sorting VRRP instances for display purposes.
603 *
604 * Sorts by interface name first, then by VRID ascending.
605 */
606 static int vrrp_instance_display_sort_cmp(const void **d1, const void **d2)
607 {
608 const struct vrrp_vrouter *vr1 = *d1;
609 const struct vrrp_vrouter *vr2 = *d2;
610 int result;
611
612 result = strcmp(vr1->ifp->name, vr2->ifp->name);
613 result += !result * (vr1->vrid - vr2->vrid);
614
615 return result;
616 }
617
618 /* clang-format off */
619
620 DEFPY_YANG(vrrp_vrid_show,
621 vrrp_vrid_show_cmd,
622 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] [json$json]",
623 SHOW_STR
624 VRRP_STR
625 INTERFACE_STR
626 "Only show VRRP instances on this interface\n"
627 VRRP_VRID_STR
628 JSON_STR)
629 {
630 struct vrrp_vrouter *vr;
631 struct listnode *ln;
632 struct list *ll = hash_to_list(vrrp_vrouters_hash);
633 struct json_object *j = json_object_new_array();
634
635 list_sort(ll, vrrp_instance_display_sort_cmp);
636
637 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr)) {
638 if (ifn && !strmatch(ifn, vr->ifp->name))
639 continue;
640 if (vrid && ((uint8_t) vrid) != vr->vrid)
641 continue;
642
643 if (!json)
644 vrrp_show(vty, vr);
645 else
646 json_object_array_add(j, vrrp_build_json(vr));
647 }
648
649 if (json)
650 vty_out(vty, "%s\n",
651 json_object_to_json_string_ext(
652 j, JSON_C_TO_STRING_PRETTY));
653
654 json_object_free(j);
655
656 list_delete(&ll);
657
658 return CMD_SUCCESS;
659 }
660
661 DEFPY_YANG(vrrp_vrid_show_summary,
662 vrrp_vrid_show_summary_cmd,
663 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] summary",
664 SHOW_STR
665 VRRP_STR
666 INTERFACE_STR
667 "Only show VRRP instances on this interface\n"
668 VRRP_VRID_STR
669 "Summarize all VRRP instances\n")
670 {
671 struct vrrp_vrouter *vr;
672 struct listnode *ln;
673 struct list *ll = hash_to_list(vrrp_vrouters_hash);
674
675 list_sort(ll, vrrp_instance_display_sort_cmp);
676
677 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
678
679 ttable_add_row(
680 tt, "Interface|VRID|Priority|IPv4|IPv6|State (v4)|State (v6)");
681 ttable_rowseps(tt, 0, BOTTOM, true, '-');
682
683 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr)) {
684 if (ifn && !strmatch(ifn, vr->ifp->name))
685 continue;
686 if (vrid && ((uint8_t)vrid) != vr->vrid)
687 continue;
688
689 ttable_add_row(
690 tt, "%s|%u|%hhu|%d|%d|%s|%s",
691 vr->ifp->name, vr->vrid, vr->priority,
692 vr->v4->addrs->count, vr->v6->addrs->count,
693 vr->v4->fsm.state == VRRP_STATE_MASTER ? "Master"
694 : "Backup",
695 vr->v6->fsm.state == VRRP_STATE_MASTER ? "Master"
696 : "Backup");
697 }
698
699 char *table = ttable_dump(tt, "\n");
700
701 vty_out(vty, "\n%s\n", table);
702 XFREE(MTYPE_TMP, table);
703 ttable_del(tt);
704
705 list_delete(&ll);
706
707 return CMD_SUCCESS;
708 }
709
710
711 DEFPY_YANG(debug_vrrp,
712 debug_vrrp_cmd,
713 "[no] debug vrrp [{protocol$proto|autoconfigure$ac|packets$pkt|sockets$sock|ndisc$ndisc|arp$arp|zebra$zebra}]",
714 NO_STR
715 DEBUG_STR
716 VRRP_STR
717 "Debug protocol state\n"
718 "Debug autoconfiguration\n"
719 "Debug sent and received packets\n"
720 "Debug socket creation and configuration\n"
721 "Debug Neighbor Discovery\n"
722 "Debug ARP\n"
723 "Debug Zebra events\n")
724 {
725 /* If no specific are given on/off them all */
726 if (strmatch(argv[argc - 1]->text, "vrrp"))
727 vrrp_debug_set(NULL, 0, vty->node, !no, true, true, true, true,
728 true, true, true);
729 else
730 vrrp_debug_set(NULL, 0, vty->node, !no, !!proto, !!ac, !!pkt,
731 !!sock, !!ndisc, !!arp, !!zebra);
732
733 return CMD_SUCCESS;
734 }
735
736 DEFUN_NOSH (show_debugging_vrrp,
737 show_debugging_vrrp_cmd,
738 "show debugging [vrrp]",
739 SHOW_STR
740 DEBUG_STR
741 "VRRP information\n")
742 {
743 vty_out(vty, "VRRP debugging status:\n");
744
745 vrrp_debug_status_write(vty);
746
747 cmd_show_lib_debugs(vty);
748
749 return CMD_SUCCESS;
750 }
751
752 /* clang-format on */
753
754 static struct cmd_node debug_node = {
755 .name = "debug",
756 .node = DEBUG_NODE,
757 .prompt = "",
758 .config_write = vrrp_config_write_debug,
759 };
760
761 static struct cmd_node vrrp_node = {
762 .name = "vrrp",
763 .node = VRRP_NODE,
764 .prompt = "",
765 .config_write = vrrp_config_write_global,
766 };
767
768 void vrrp_vty_init(void)
769 {
770 install_node(&debug_node);
771 install_node(&vrrp_node);
772 vrf_cmd_init(NULL);
773 if_cmd_init_default();
774
775 install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
776 install_element(VIEW_NODE, &vrrp_vrid_show_summary_cmd);
777 install_element(ENABLE_NODE, &show_debugging_vrrp_cmd);
778 install_element(ENABLE_NODE, &debug_vrrp_cmd);
779 install_element(CONFIG_NODE, &debug_vrrp_cmd);
780 install_element(CONFIG_NODE, &vrrp_autoconfigure_cmd);
781 install_element(CONFIG_NODE, &vrrp_default_cmd);
782 install_element(INTERFACE_NODE, &vrrp_vrid_cmd);
783 install_element(INTERFACE_NODE, &vrrp_shutdown_cmd);
784 install_element(INTERFACE_NODE, &vrrp_priority_cmd);
785 install_element(INTERFACE_NODE, &no_vrrp_priority_cmd);
786 install_element(INTERFACE_NODE, &vrrp_advertisement_interval_cmd);
787 install_element(INTERFACE_NODE, &no_vrrp_advertisement_interval_cmd);
788 install_element(INTERFACE_NODE, &vrrp_ip_cmd);
789 install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
790 install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
791 install_element(INTERFACE_NODE,
792 &vrrp_checksum_with_ipv4_pseudoheader_cmd);
793 }