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