3 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
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)
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
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
22 #include "lib/command.h"
24 #include "lib/ipaddr.h"
26 #include "lib/prefix.h"
27 #include "lib/termtable.h"
31 #include "vrrp_debug.h"
32 #include "vrrp_memory.h"
34 #ifndef VTYSH_EXTRACT_PL
35 #include "vrrpd/vrrp_vty_clippy.c"
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"
46 #define VROUTER_GET_VTY(_vty, _ifp, _vrid, _vr) \
48 _vr = vrrp_lookup(_ifp, _vrid); \
51 "%% Please configure VRRP instance %u\n", \
52 (unsigned int)_vrid); \
53 return CMD_WARNING_CONFIG_FAILED; \
57 /* clang-format off */
61 "[no] vrrp (1-255)$vrid [version (2-3)]",
68 VTY_DECLVAR_CONTEXT(interface
, ifp
);
70 struct vrrp_vrouter
*vr
= vrrp_lookup(ifp
, vrid
);
76 vrrp_vrouter_destroy(vr
);
78 vty_out(vty
, "%% VRRP instance %ld does not exist on %s\n",
81 vrrp_vrouter_create(ifp
, vrid
, version
);
83 vty_out(vty
, "%% VRRP instance %ld already exists on %s\n",
91 "[no] vrrp (1-255)$vrid shutdown",
95 "Force VRRP router into administrative shutdown\n")
97 VTY_DECLVAR_CONTEXT(interface
, ifp
);
99 struct vrrp_vrouter
*vr
;
101 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
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
);
110 vr
->shutdown
= false;
111 vrrp_check_start(vr
);
119 "[no] vrrp (1-255)$vrid priority (1-254)",
126 VTY_DECLVAR_CONTEXT(interface
, ifp
);
128 struct vrrp_vrouter
*vr
;
129 uint8_t newprio
= no
? vd
.priority
: priority
;
131 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
133 vrrp_set_priority(vr
, newprio
);
138 DEFPY(vrrp_advertisement_interval
,
139 vrrp_advertisement_interval_cmd
,
140 "[no] vrrp (1-255)$vrid advertisement-interval (1-4096)",
141 NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
142 "Advertisement interval in centiseconds")
144 VTY_DECLVAR_CONTEXT(interface
, ifp
);
146 struct vrrp_vrouter
*vr
;
147 uint16_t newadvint
= no
? vd
.advertisement_interval
:
148 advertisement_interval
;
150 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
151 vrrp_set_advertisement_interval(vr
, newadvint
);
158 "[no] vrrp (1-255)$vrid ip A.B.C.D",
165 VTY_DECLVAR_CONTEXT(interface
, ifp
);
167 struct vrrp_vrouter
*vr
;
168 bool deactivated
= false;
169 bool activated
= false;
171 int ret
= CMD_SUCCESS
;
173 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
175 bool will_activate
= (vr
->v4
->fsm
.state
== VRRP_STATE_INITIALIZE
);
178 int oldstate
= vr
->v4
->fsm
.state
;
179 failed
= vrrp_del_ipv4(vr
, ip
);
180 vrrp_check_start(vr
);
181 deactivated
= (vr
->v4
->fsm
.state
== VRRP_STATE_INITIALIZE
182 && oldstate
!= VRRP_STATE_INITIALIZE
);
184 int oldstate
= vr
->v4
->fsm
.state
;
185 failed
= vrrp_add_ipv4(vr
, ip
);
186 vrrp_check_start(vr
);
187 activated
= (vr
->v4
->fsm
.state
!= VRRP_STATE_INITIALIZE
188 && oldstate
== VRRP_STATE_INITIALIZE
);
192 vty_out(vty
, "%% Activated IPv4 Virtual Router %ld\n", vrid
);
194 vty_out(vty
, "%% Deactivated IPv4 Virtual Router %ld\n", vrid
);
196 vty_out(vty
, "%% Failed to %s virtual IP\n",
197 no
? "remove" : "add");
198 ret
= CMD_WARNING_CONFIG_FAILED
;
199 if (will_activate
&& !activated
) {
201 "%% Failed to activate IPv4 Virtual Router %ld\n",
211 "[no] vrrp (1-255)$vrid ipv6 X:X::X:X",
218 VTY_DECLVAR_CONTEXT(interface
, ifp
);
220 struct vrrp_vrouter
*vr
;
221 bool deactivated
= false;
222 bool activated
= false;
224 int ret
= CMD_SUCCESS
;
226 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
228 if (vr
->version
!= 3) {
230 "%% Cannot add IPv6 address to VRRPv2 virtual router\n");
231 return CMD_WARNING_CONFIG_FAILED
;
234 bool will_activate
= (vr
->v6
->fsm
.state
== VRRP_STATE_INITIALIZE
);
237 int oldstate
= vr
->v6
->fsm
.state
;
238 failed
= vrrp_del_ipv6(vr
, ipv6
);
239 vrrp_check_start(vr
);
240 deactivated
= (vr
->v6
->fsm
.state
== VRRP_STATE_INITIALIZE
241 && oldstate
!= VRRP_STATE_INITIALIZE
);
243 int oldstate
= vr
->v6
->fsm
.state
;
244 failed
= vrrp_add_ipv6(vr
, ipv6
);
245 vrrp_check_start(vr
);
246 activated
= (vr
->v6
->fsm
.state
!= VRRP_STATE_INITIALIZE
247 && oldstate
== VRRP_STATE_INITIALIZE
);
251 vty_out(vty
, "%% Activated IPv6 Virtual Router %ld\n", vrid
);
253 vty_out(vty
, "%% Deactivated IPv6 Virtual Router %ld\n", vrid
);
255 vty_out(vty
, "%% Failed to %s virtual IP\n",
256 no
? "remove" : "add");
257 ret
= CMD_WARNING_CONFIG_FAILED
;
258 if (will_activate
&& !activated
) {
260 "%% Failed to activate IPv6 Virtual Router %ld\n",
270 "[no] vrrp (1-255)$vrid preempt",
276 VTY_DECLVAR_CONTEXT(interface
, ifp
);
278 struct vrrp_vrouter
*vr
;
280 VROUTER_GET_VTY(vty
, ifp
, vrid
, vr
);
282 vr
->preempt_mode
= !no
;
287 DEFPY(vrrp_autoconfigure
,
288 vrrp_autoconfigure_cmd
,
289 "[no] vrrp autoconfigure [version (2-3)]",
292 "Automatically set up VRRP instances on VRRP-compatible interfaces\n"
293 "Version for automatically configured instances\n"
296 version
= version
? version
: 3;
299 vrrp_autoconfig_on(version
);
301 vrrp_autoconfig_off();
308 "[no] vrrp default <advertisement-interval$adv (1-4096)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
311 "Configure defaults for new VRRP instances\n"
313 "Advertisement interval in centiseconds\n"
317 "Force VRRP router into administrative shutdown\n")
320 vd
.advertisement_interval
= no
? VRRP_DEFAULT_ADVINT
: advint
;
322 vd
.preempt_mode
= !no
;
324 vd
.priority
= no
? VRRP_DEFAULT_PRIORITY
: prioval
;
331 /* clang-format on */
334 * Build JSON representation of VRRP instance.
337 * VRRP router to build json object from
340 * JSON representation of VRRP instance. Must be freed by caller.
342 static struct json_object
*vrrp_build_json(struct vrrp_vrouter
*vr
)
344 char ethstr4
[ETHER_ADDR_STRLEN
];
345 char ethstr6
[ETHER_ADDR_STRLEN
];
346 char ipstr
[INET6_ADDRSTRLEN
];
347 const char *stastr4
= vrrp_state_names
[vr
->v4
->fsm
.state
];
348 const char *stastr6
= vrrp_state_names
[vr
->v6
->fsm
.state
];
351 struct json_object
*j
= json_object_new_object();
352 struct json_object
*v4
= json_object_new_object();
353 struct json_object
*v4_stats
= json_object_new_object();
354 struct json_object
*v4_addrs
= json_object_new_array();
355 struct json_object
*v6
= json_object_new_object();
356 struct json_object
*v6_stats
= json_object_new_object();
357 struct json_object
*v6_addrs
= json_object_new_array();
359 prefix_mac2str(&vr
->v4
->vmac
, ethstr4
, sizeof(ethstr4
));
360 prefix_mac2str(&vr
->v6
->vmac
, ethstr6
, sizeof(ethstr6
));
362 json_object_int_add(j
, "vrid", vr
->vrid
);
363 json_object_int_add(j
, "version", vr
->version
);
364 json_object_boolean_add(j
, "autoconfigured", vr
->autoconf
);
365 json_object_boolean_add(j
, "shutdown", vr
->shutdown
);
366 json_object_boolean_add(j
, "preemptMode", vr
->preempt_mode
);
367 json_object_boolean_add(j
, "acceptMode", vr
->accept_mode
);
368 json_object_string_add(j
, "interface", vr
->ifp
->name
);
370 json_object_string_add(v4
, "interface",
371 vr
->v4
->mvl_ifp
? vr
->v4
->mvl_ifp
->name
: "");
372 json_object_string_add(v4
, "vmac", ethstr4
);
373 json_object_string_add(v4
, "status", stastr4
);
374 json_object_int_add(v4
, "effectivePriority", vr
->v4
->priority
);
375 json_object_int_add(v4
, "masterAdverInterval",
376 vr
->v4
->master_adver_interval
);
377 json_object_int_add(v4
, "skewTime", vr
->v4
->skew_time
);
378 json_object_int_add(v4
, "masterDownInterval",
379 vr
->v4
->master_down_interval
);
381 json_object_int_add(v4_stats
, "adverTx", vr
->v4
->stats
.adver_tx_cnt
);
382 json_object_int_add(v4_stats
, "adverRx", vr
->v4
->stats
.adver_rx_cnt
);
383 json_object_int_add(v4_stats
, "garpTx", vr
->v4
->stats
.garp_tx_cnt
);
384 json_object_int_add(v4_stats
, "transitions", vr
->v4
->stats
.trans_cnt
);
385 json_object_object_add(v4
, "stats", v4_stats
);
387 if (vr
->v4
->addrs
->count
) {
388 for (ALL_LIST_ELEMENTS_RO(vr
->v4
->addrs
, ln
, ip
)) {
389 inet_ntop(vr
->v4
->family
, &ip
->ipaddr_v4
, ipstr
,
391 json_object_array_add(v4_addrs
,
392 json_object_new_string(ipstr
));
395 json_object_object_add(v4
, "addresses", v4_addrs
);
396 json_object_object_add(j
, "v4", v4
);
399 json_object_string_add(v6
, "interface",
400 vr
->v6
->mvl_ifp
? vr
->v6
->mvl_ifp
->name
: "");
401 json_object_string_add(v6
, "vmac", ethstr6
);
402 json_object_string_add(v6
, "status", stastr6
);
403 json_object_int_add(v6
, "effectivePriority", vr
->v6
->priority
);
404 json_object_int_add(v6
, "masterAdverInterval",
405 vr
->v6
->master_adver_interval
);
406 json_object_int_add(v6
, "skewTime", vr
->v6
->skew_time
);
407 json_object_int_add(v6
, "masterDownInterval",
408 vr
->v6
->master_down_interval
);
410 json_object_int_add(v6_stats
, "adverTx", vr
->v6
->stats
.adver_tx_cnt
);
411 json_object_int_add(v6_stats
, "adverRx", vr
->v6
->stats
.adver_rx_cnt
);
412 json_object_int_add(v6_stats
, "neighborAdverTx",
413 vr
->v6
->stats
.una_tx_cnt
);
414 json_object_int_add(v6_stats
, "transitions", vr
->v6
->stats
.trans_cnt
);
415 json_object_object_add(v6
, "stats", v6_stats
);
417 if (vr
->v6
->addrs
->count
) {
418 for (ALL_LIST_ELEMENTS_RO(vr
->v6
->addrs
, ln
, ip
)) {
419 inet_ntop(vr
->v6
->family
, &ip
->ipaddr_v6
, ipstr
,
421 json_object_array_add(v6_addrs
,
422 json_object_new_string(ipstr
));
425 json_object_object_add(v6
, "addresses", v6_addrs
);
426 json_object_object_add(j
, "v6", v6
);
432 * Dump VRRP instance status to VTY.
438 * VRRP router to dump
440 static void vrrp_show(struct vty
*vty
, struct vrrp_vrouter
*vr
)
442 char ethstr4
[ETHER_ADDR_STRLEN
];
443 char ethstr6
[ETHER_ADDR_STRLEN
];
444 char ipstr
[INET6_ADDRSTRLEN
];
445 const char *stastr4
= vrrp_state_names
[vr
->v4
->fsm
.state
];
446 const char *stastr6
= vrrp_state_names
[vr
->v6
->fsm
.state
];
450 struct ttable
*tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
452 ttable_add_row(tt
, "%s|%" PRIu32
, "Virtual Router ID", vr
->vrid
);
453 ttable_add_row(tt
, "%s|%" PRIu8
, "Protocol Version", vr
->version
);
454 ttable_add_row(tt
, "%s|%s", "Autoconfigured",
455 vr
->autoconf
? "Yes" : "No");
456 ttable_add_row(tt
, "%s|%s", "Shutdown", vr
->shutdown
? "Yes" : "No");
457 ttable_add_row(tt
, "%s|%s", "Interface", vr
->ifp
->name
);
458 prefix_mac2str(&vr
->v4
->vmac
, ethstr4
, sizeof(ethstr4
));
459 prefix_mac2str(&vr
->v6
->vmac
, ethstr6
, sizeof(ethstr6
));
460 ttable_add_row(tt
, "%s|%s", "VRRP interface (v4)",
461 vr
->v4
->mvl_ifp
? vr
->v4
->mvl_ifp
->name
: "None");
462 ttable_add_row(tt
, "%s|%s", "VRRP interface (v6)",
463 vr
->v6
->mvl_ifp
? vr
->v6
->mvl_ifp
->name
: "None");
464 ttable_add_row(tt
, "%s|%s", "Virtual MAC (v4)", ethstr4
);
465 ttable_add_row(tt
, "%s|%s", "Virtual MAC (v6)", ethstr6
);
466 ttable_add_row(tt
, "%s|%s", "Status (v4)", stastr4
);
467 ttable_add_row(tt
, "%s|%s", "Status (v6)", stastr6
);
468 ttable_add_row(tt
, "%s|%" PRIu8
, "Priority", vr
->priority
);
469 ttable_add_row(tt
, "%s|%" PRIu8
, "Effective Priority (v4)",
471 ttable_add_row(tt
, "%s|%" PRIu8
, "Effective Priority (v6)",
473 ttable_add_row(tt
, "%s|%s", "Preempt Mode",
474 vr
->preempt_mode
? "Yes" : "No");
475 ttable_add_row(tt
, "%s|%s", "Accept Mode",
476 vr
->accept_mode
? "Yes" : "No");
477 ttable_add_row(tt
, "%s|%" PRIu16
" cs", "Advertisement Interval",
478 vr
->advertisement_interval
);
479 ttable_add_row(tt
, "%s|%" PRIu16
" cs",
480 "Master Advertisement Interval (v4)",
481 vr
->v4
->master_adver_interval
);
482 ttable_add_row(tt
, "%s|%" PRIu16
" cs",
483 "Master Advertisement Interval (v6)",
484 vr
->v6
->master_adver_interval
);
485 ttable_add_row(tt
, "%s|%" PRIu32
, "Advertisements Tx (v4)",
486 vr
->v4
->stats
.adver_tx_cnt
);
487 ttable_add_row(tt
, "%s|%" PRIu32
, "Advertisements Tx (v6)",
488 vr
->v6
->stats
.adver_tx_cnt
);
489 ttable_add_row(tt
, "%s|%" PRIu32
, "Advertisements Rx (v4)",
490 vr
->v4
->stats
.adver_rx_cnt
);
491 ttable_add_row(tt
, "%s|%" PRIu32
, "Advertisements Rx (v6)",
492 vr
->v6
->stats
.adver_rx_cnt
);
493 ttable_add_row(tt
, "%s|%" PRIu32
, "Gratuitous ARP Tx (v4)",
494 vr
->v4
->stats
.garp_tx_cnt
);
495 ttable_add_row(tt
, "%s|%" PRIu32
, "Neigh. Adverts Tx (v6)",
496 vr
->v6
->stats
.una_tx_cnt
);
497 ttable_add_row(tt
, "%s|%" PRIu32
, "State transitions (v4)",
498 vr
->v4
->stats
.trans_cnt
);
499 ttable_add_row(tt
, "%s|%" PRIu32
, "State transitions (v6)",
500 vr
->v6
->stats
.trans_cnt
);
501 ttable_add_row(tt
, "%s|%" PRIu16
" cs", "Skew Time (v4)",
503 ttable_add_row(tt
, "%s|%" PRIu16
" cs", "Skew Time (v6)",
505 ttable_add_row(tt
, "%s|%" PRIu16
" cs", "Master Down Interval (v4)",
506 vr
->v4
->master_down_interval
);
507 ttable_add_row(tt
, "%s|%" PRIu16
" cs", "Master Down Interval (v6)",
508 vr
->v6
->master_down_interval
);
509 ttable_add_row(tt
, "%s|%u", "IPv4 Addresses", vr
->v4
->addrs
->count
);
512 memset(fill
, '.', sizeof(fill
));
513 fill
[sizeof(fill
) - 1] = 0x00;
514 if (vr
->v4
->addrs
->count
) {
515 for (ALL_LIST_ELEMENTS_RO(vr
->v4
->addrs
, ln
, ip
)) {
516 inet_ntop(vr
->v4
->family
, &ip
->ipaddr_v4
, ipstr
,
518 ttable_add_row(tt
, "%s|%s", fill
, ipstr
);
522 ttable_add_row(tt
, "%s|%u", "IPv6 Addresses", vr
->v6
->addrs
->count
);
524 if (vr
->v6
->addrs
->count
) {
525 for (ALL_LIST_ELEMENTS_RO(vr
->v6
->addrs
, ln
, ip
)) {
526 inet_ntop(vr
->v6
->family
, &ip
->ipaddr_v6
, ipstr
,
528 ttable_add_row(tt
, "%s|%s", fill
, ipstr
);
532 char *table
= ttable_dump(tt
, "\n");
533 vty_out(vty
, "\n%s\n", table
);
534 XFREE(MTYPE_TMP
, table
);
538 /* clang-format off */
540 DEFPY(vrrp_vrid_show
,
542 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] [json$json]",
546 "Only show VRRP instances on this interface\n"
550 struct vrrp_vrouter
*vr
;
552 struct list
*ll
= hash_to_list(vrrp_vrouters_hash
);
553 struct json_object
*j
= json_object_new_array();
555 for (ALL_LIST_ELEMENTS_RO(ll
, ln
, vr
)) {
556 if (ifn
&& !strmatch(ifn
, vr
->ifp
->name
))
558 if (vrid
&& vrid
!= vr
->vrid
)
564 json_object_array_add(j
, vrrp_build_json(vr
));
569 json_object_to_json_string_ext(
570 j
, JSON_C_TO_STRING_PRETTY
));
582 "[no] debug vrrp [{protocol$proto|autoconfigure$ac|packets$pkt|sockets$sock|ndisc$ndisc|arp$arp|zebra$zebra}]",
586 "Debug protocol state\n"
587 "Debug autoconfiguration\n"
588 "Debug sent and received packets\n"
589 "Debug socket creation and configuration\n"
590 "Debug Neighbor Discovery\n"
592 "Debug Zebra events\n")
594 /* If no specific are given on/off them all */
595 if (strmatch(argv
[argc
- 1]->text
, "vrrp"))
596 vrrp_debug_set(NULL
, 0, vty
->node
, !no
, true, true, true, true,
599 vrrp_debug_set(NULL
, 0, vty
->node
, !no
, !!proto
, !!ac
, !!pkt
,
600 !!sock
, !!ndisc
, !!arp
, !!zebra
);
605 DEFUN_NOSH (show_debugging_vrrp
,
606 show_debugging_vrrp_cmd
,
607 "show debugging [vrrp]",
610 "VRRP information\n")
612 vty_out(vty
, "VRRP debugging status:\n");
614 vrrp_debug_status_write(vty
);
619 /* clang-format on */
621 static struct cmd_node interface_node
= {INTERFACE_NODE
, "%s(config-if)# ", 1};
622 static struct cmd_node debug_node
= {DEBUG_NODE
, "", 1};
623 static struct cmd_node vrrp_node
= {VRRP_NODE
, "", 1};
625 void vrrp_vty_init(void)
627 install_node(&debug_node
, vrrp_config_write_debug
);
628 install_node(&interface_node
, vrrp_config_write_interface
);
629 install_node(&vrrp_node
, vrrp_config_write_global
);
632 install_element(VIEW_NODE
, &vrrp_vrid_show_cmd
);
633 install_element(VIEW_NODE
, &show_debugging_vrrp_cmd
);
634 install_element(VIEW_NODE
, &debug_vrrp_cmd
);
635 install_element(CONFIG_NODE
, &debug_vrrp_cmd
);
636 install_element(CONFIG_NODE
, &vrrp_autoconfigure_cmd
);
637 install_element(CONFIG_NODE
, &vrrp_default_cmd
);
638 install_element(INTERFACE_NODE
, &vrrp_vrid_cmd
);
639 install_element(INTERFACE_NODE
, &vrrp_shutdown_cmd
);
640 install_element(INTERFACE_NODE
, &vrrp_priority_cmd
);
641 install_element(INTERFACE_NODE
, &vrrp_advertisement_interval_cmd
);
642 install_element(INTERFACE_NODE
, &vrrp_ip_cmd
);
643 install_element(INTERFACE_NODE
, &vrrp_ip6_cmd
);
644 install_element(INTERFACE_NODE
, &vrrp_preempt_cmd
);