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