]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp_vty.c
lib, zebra: Allow for interface deletion when kernel event happens
[mirror_frr.git] / vrrpd / vrrp_vty.c
CommitLineData
5435a2bf 1/*
63d4bd12
QY
2 * VRRP CLI commands.
3 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
4 * Quentin Young
5435a2bf
QY
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
862f2f37
QY
22#include "lib/command.h"
23#include "lib/if.h"
24#include "lib/ipaddr.h"
6e21b5ae 25#include "lib/json.h"
862f2f37
QY
26#include "lib/prefix.h"
27#include "lib/termtable.h"
28#include "lib/vty.h"
5435a2bf
QY
29
30#include "vrrp.h"
78fb3dbe 31#include "vrrp_debug.h"
78fb3dbe 32#include "vrrp_vty.h"
c23edd74
QY
33#ifndef VTYSH_EXTRACT_PL
34#include "vrrpd/vrrp_vty_clippy.c"
35#endif
5435a2bf
QY
36
37
38#define VRRP_STR "Virtual Router Redundancy Protocol\n"
39#define VRRP_VRID_STR "Virtual Router ID\n"
c23edd74 40#define VRRP_PRIORITY_STR "Virtual Router Priority\n"
6287cefe 41#define VRRP_ADVINT_STR "Virtual Router Advertisement Interval\n"
c23edd74 42#define VRRP_IP_STR "Virtual Router IPv4 address\n"
99966840 43#define VRRP_VERSION_STR "VRRP protocol version\n"
c23edd74 44
4f0b6b45 45#define VROUTER_GET_VTY(_vty, _ifp, _vrid, _vr) \
c23edd74 46 do { \
4f0b6b45 47 _vr = vrrp_lookup(_ifp, _vrid); \
c23edd74
QY
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 } \
2fff50ec 54 } while (0)
5435a2bf 55
b637bcd4
QY
56/* clang-format off */
57
c23edd74 58DEFPY(vrrp_vrid,
5435a2bf 59 vrrp_vrid_cmd,
99966840 60 "[no] vrrp (1-255)$vrid [version (2-3)]",
5435a2bf
QY
61 NO_STR
62 VRRP_STR
99966840
QY
63 VRRP_VRID_STR
64 VRRP_VERSION_STR
65 VRRP_VERSION_STR)
5435a2bf
QY
66{
67 VTY_DECLVAR_CONTEXT(interface, ifp);
5435a2bf 68
4f0b6b45 69 struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid);
6287cefe 70
99966840
QY
71 if (version == 0)
72 version = 3;
73
6287cefe
QY
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)
99966840 80 vrrp_vrouter_create(ifp, vrid, version);
6287cefe
QY
81 else if (vr)
82 vty_out(vty, "%% VRRP instance %ld already exists on %s\n",
83 vrid, ifp->name);
5435a2bf
QY
84
85 return CMD_SUCCESS;
86}
87
f96a183b
QY
88DEFPY(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
c23edd74
QY
116DEFPY(vrrp_priority,
117 vrrp_priority_cmd,
d7cfcdc0 118 "[no] vrrp (1-255)$vrid priority (1-254)",
c23edd74
QY
119 NO_STR
120 VRRP_STR
121 VRRP_VRID_STR
122 VRRP_PRIORITY_STR
bac08ded 123 "Priority value")
c23edd74 124{
4f0b6b45
QY
125 VTY_DECLVAR_CONTEXT(interface, ifp);
126
c23edd74 127 struct vrrp_vrouter *vr;
8cd1d277 128 uint8_t newprio = no ? vd.priority : priority;
c23edd74 129
4f0b6b45 130 VROUTER_GET_VTY(vty, ifp, vrid, vr);
1d21789e 131
6287cefe 132 vrrp_set_priority(vr, newprio);
1d21789e 133
1d21789e
QY
134 return CMD_SUCCESS;
135}
136
137DEFPY(vrrp_advertisement_interval,
138 vrrp_advertisement_interval_cmd,
cb44d476 139 "[no] vrrp (1-255)$vrid advertisement-interval (10-40950)",
6287cefe 140 NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
cb44d476 141 "Advertisement interval in milliseconds; must be multiple of 10")
1d21789e 142{
4f0b6b45
QY
143 VTY_DECLVAR_CONTEXT(interface, ifp);
144
1d21789e 145 struct vrrp_vrouter *vr;
19c38250
QY
146 uint16_t newadvint =
147 no ? vd.advertisement_interval * 10 : advertisement_interval;
1d21789e 148
cb44d476
QY
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
4f0b6b45 157 VROUTER_GET_VTY(vty, ifp, vrid, vr);
6287cefe 158 vrrp_set_advertisement_interval(vr, newadvint);
c23edd74
QY
159
160 return CMD_SUCCESS;
161}
162
163DEFPY(vrrp_ip,
164 vrrp_ip_cmd,
862f2f37 165 "[no] vrrp (1-255)$vrid ip A.B.C.D",
c23edd74
QY
166 NO_STR
167 VRRP_STR
168 VRRP_VRID_STR
862f2f37 169 "Add IPv4 address\n"
c23edd74
QY
170 VRRP_IP_STR)
171{
4f0b6b45
QY
172 VTY_DECLVAR_CONTEXT(interface, ifp);
173
c23edd74 174 struct vrrp_vrouter *vr;
2cd90902
QY
175 bool deactivated = false;
176 bool activated = false;
177 bool failed = false;
178 int ret = CMD_SUCCESS;
2fff50ec 179 int oldstate;
c23edd74 180
4f0b6b45 181 VROUTER_GET_VTY(vty, ifp, vrid, vr);
c23edd74 182
2cd90902 183 bool will_activate = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE);
862f2f37 184
2cd90902 185 if (no) {
2fff50ec 186 oldstate = vr->v4->fsm.state;
6e93585e
QY
187 failed = vrrp_del_ipv4(vr, ip);
188 vrrp_check_start(vr);
2cd90902
QY
189 deactivated = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE
190 && oldstate != VRRP_STATE_INITIALIZE);
862f2f37 191 } else {
2fff50ec 192 oldstate = vr->v4->fsm.state;
6e93585e
QY
193 failed = vrrp_add_ipv4(vr, ip);
194 vrrp_check_start(vr);
2cd90902
QY
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) {
1af0eb1f 204 vty_out(vty, "%% Failed to %s virtual IP\n",
2cd90902
QY
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 }
862f2f37
QY
212 }
213
214 return ret;
215}
216
217DEFPY(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{
4f0b6b45
QY
226 VTY_DECLVAR_CONTEXT(interface, ifp);
227
862f2f37 228 struct vrrp_vrouter *vr;
2cd90902
QY
229 bool deactivated = false;
230 bool activated = false;
231 bool failed = false;
232 int ret = CMD_SUCCESS;
2fff50ec 233 int oldstate;
862f2f37 234
4f0b6b45 235 VROUTER_GET_VTY(vty, ifp, vrid, vr);
862f2f37 236
99966840
QY
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
2cd90902 243 bool will_activate = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE);
1d21789e 244
2cd90902 245 if (no) {
2fff50ec 246 oldstate = vr->v6->fsm.state;
6e93585e 247 failed = vrrp_del_ipv6(vr, ipv6);
29ef66fa 248 vrrp_check_start(vr);
2cd90902
QY
249 deactivated = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE
250 && oldstate != VRRP_STATE_INITIALIZE);
1d21789e 251 } else {
2fff50ec 252 oldstate = vr->v6->fsm.state;
6e93585e 253 failed = vrrp_add_ipv6(vr, ipv6);
29ef66fa 254 vrrp_check_start(vr);
2cd90902
QY
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) {
d5a6ff43 264 vty_out(vty, "%% Failed to %s virtual IP\n",
2cd90902
QY
265 no ? "remove" : "add");
266 ret = CMD_WARNING_CONFIG_FAILED;
267 if (will_activate && !activated) {
268 vty_out(vty,
d5a6ff43 269 "%% Failed to activate IPv6 Virtual Router %ld\n",
2cd90902
QY
270 vrid);
271 }
1d21789e
QY
272 }
273
274 return ret;
c23edd74
QY
275}
276
8ec51216
QY
277DEFPY(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
27fd8827
QY
296DEFPY(vrrp_autoconfigure,
297 vrrp_autoconfigure_cmd,
298 "[no] vrrp autoconfigure [version (2-3)]",
53e60e5c
QY
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{
53e60e5c
QY
305 version = version ? version : 3;
306
27fd8827
QY
307 if (!no)
308 vrrp_autoconfig_on(version);
309 else
310 vrrp_autoconfig_off();
53e60e5c
QY
311
312 return CMD_SUCCESS;
313}
314
8cd1d277
QY
315DEFPY(vrrp_default,
316 vrrp_default_cmd,
33b010a9 317 "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
8cd1d277
QY
318 NO_STR
319 VRRP_STR
320 "Configure defaults for new VRRP instances\n"
321 VRRP_ADVINT_STR
33b010a9 322 "Advertisement interval in milliseconds\n"
8cd1d277
QY
323 "Preempt mode\n"
324 VRRP_PRIORITY_STR
325 "Priority value\n"
326 "Force VRRP router into administrative shutdown\n")
327{
33b010a9
QY
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;
8cd1d277 335 vd.advertisement_interval = no ? VRRP_DEFAULT_ADVINT : advint;
33b010a9 336 }
8cd1d277
QY
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
6332c77f
QY
347/* clang-format on */
348
6e21b5ae
QY
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 */
358static 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];
23804b4f
QY
365 char sipstr4[INET6_ADDRSTRLEN] = {};
366 char sipstr6[INET6_ADDRSTRLEN] = {};
6e21b5ae
QY
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();
6332c77f 371 struct json_object *v4_stats = json_object_new_object();
6e21b5ae
QY
372 struct json_object *v4_addrs = json_object_new_array();
373 struct json_object *v6 = json_object_new_object();
6332c77f 374 struct json_object *v6_stats = json_object_new_object();
6e21b5ae
QY
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);
b1d7f513
QY
384 json_object_boolean_add(j, "preemptMode", vr->preempt_mode);
385 json_object_boolean_add(j, "acceptMode", vr->accept_mode);
6e21b5ae 386 json_object_string_add(j, "interface", vr->ifp->name);
0a7b203e
QY
387 json_object_int_add(j, "advertisementInterval",
388 vr->advertisement_interval * CS2MS);
6e21b5ae
QY
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);
23804b4f
QY
393 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
394 json_object_string_add(v4, "primaryAddress", sipstr4);
6e21b5ae 395 json_object_string_add(v4, "status", stastr4);
b1d7f513
QY
396 json_object_int_add(v4, "effectivePriority", vr->v4->priority);
397 json_object_int_add(v4, "masterAdverInterval",
cb44d476
QY
398 vr->v4->master_adver_interval * CS2MS);
399 json_object_int_add(v4, "skewTime", vr->v4->skew_time * CS2MS);
b1d7f513 400 json_object_int_add(v4, "masterDownInterval",
cb44d476 401 vr->v4->master_down_interval * CS2MS);
6332c77f
QY
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 */
6e21b5ae
QY
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);
23804b4f
QY
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);
6e21b5ae 428 json_object_string_add(v6, "status", stastr6);
b1d7f513
QY
429 json_object_int_add(v6, "effectivePriority", vr->v6->priority);
430 json_object_int_add(v6, "masterAdverInterval",
cb44d476
QY
431 vr->v6->master_adver_interval * CS2MS);
432 json_object_int_add(v6, "skewTime", vr->v6->skew_time * CS2MS);
b1d7f513 433 json_object_int_add(v6, "masterDownInterval",
cb44d476 434 vr->v6->master_down_interval * CS2MS);
6332c77f
QY
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 */
6e21b5ae
QY
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
789ce3af
QY
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 */
1d21789e 466static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
c23edd74 467{
862f2f37
QY
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];
23804b4f
QY
473 char sipstr4[INET6_ADDRSTRLEN] = {};
474 char sipstr6[INET6_ADDRSTRLEN] = {};
862f2f37
QY
475 struct listnode *ln;
476 struct ipaddr *ip;
c23edd74
QY
477
478 struct ttable *tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
479
480 ttable_add_row(tt, "%s|%" PRIu32, "Virtual Router ID", vr->vrid);
99966840 481 ttable_add_row(tt, "%s|%" PRIu8, "Protocol Version", vr->version);
27fd8827
QY
482 ttable_add_row(tt, "%s|%s", "Autoconfigured",
483 vr->autoconf ? "Yes" : "No");
f96a183b 484 ttable_add_row(tt, "%s|%s", "Shutdown", vr->shutdown ? "Yes" : "No");
5302f67b 485 ttable_add_row(tt, "%s|%s", "Interface", vr->ifp->name);
862f2f37
QY
486 prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
487 prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
5302f67b
QY
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");
c7e65c4f
QY
492 ipaddr2str(&vr->v4->src, sipstr4, sizeof(sipstr4));
493 ipaddr2str(&vr->v6->src, sipstr6, sizeof(sipstr6));
23804b4f
QY
494 if (strlen(sipstr6) == 0 && vr->v6->src.ip.addr == 0x00)
495 strlcat(sipstr6, "::", sizeof(sipstr6));
c7e65c4f
QY
496 ttable_add_row(tt, "%s|%s", "Primary IP (v4)", sipstr4);
497 ttable_add_row(tt, "%s|%s", "Primary IP (v6)", sipstr6);
862f2f37
QY
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);
c23edd74 502 ttable_add_row(tt, "%s|%" PRIu8, "Priority", vr->priority);
862f2f37
QY
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);
c23edd74
QY
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");
cb44d476
QY
511 ttable_add_row(tt, "%s|%d ms", "Advertisement Interval",
512 vr->advertisement_interval * CS2MS);
513 ttable_add_row(tt, "%s|%d ms",
789ce3af 514 "Master Advertisement Interval (v4)",
cb44d476
QY
515 vr->v4->master_adver_interval * CS2MS);
516 ttable_add_row(tt, "%s|%d ms",
789ce3af 517 "Master Advertisement Interval (v6)",
cb44d476 518 vr->v6->master_adver_interval * CS2MS);
6332c77f
QY
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);
cb44d476
QY
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);
862f2f37 543 ttable_add_row(tt, "%s|%u", "IPv4 Addresses", vr->v4->addrs->count);
c23edd74 544
92c399a4 545 char fill[35];
2fff50ec 546
5302f67b
QY
547 memset(fill, '.', sizeof(fill));
548 fill[sizeof(fill) - 1] = 0x00;
862f2f37 549 if (vr->v4->addrs->count) {
862f2f37
QY
550 for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ln, ip)) {
551 inet_ntop(vr->v4->family, &ip->ipaddr_v4, ipstr,
552 sizeof(ipstr));
5302f67b 553 ttable_add_row(tt, "%s|%s", fill, ipstr);
862f2f37 554 }
862f2f37
QY
555 }
556
5302f67b
QY
557 ttable_add_row(tt, "%s|%u", "IPv6 Addresses", vr->v6->addrs->count);
558
862f2f37 559 if (vr->v6->addrs->count) {
862f2f37
QY
560 for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ln, ip)) {
561 inet_ntop(vr->v6->family, &ip->ipaddr_v6, ipstr,
562 sizeof(ipstr));
5302f67b 563 ttable_add_row(tt, "%s|%s", fill, ipstr);
c23edd74 564 }
c23edd74 565 }
5302f67b
QY
566
567 char *table = ttable_dump(tt, "\n");
2fff50ec 568
5302f67b
QY
569 vty_out(vty, "\n%s\n", table);
570 XFREE(MTYPE_TMP, table);
571 ttable_del(tt);
1d21789e
QY
572}
573
30a1595d
QY
574/*
575 * Sort comparator, used when sorting VRRP instances for display purposes.
576 *
577 * Sorts by interface name first, then by VRID ascending.
578 */
579static 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
6332c77f
QY
591/* clang-format off */
592
1d21789e
QY
593DEFPY(vrrp_vrid_show,
594 vrrp_vrid_show_cmd,
6e21b5ae 595 "show vrrp [interface INTERFACE$ifn] [(1-255)$vrid] [json$json]",
1d21789e
QY
596 SHOW_STR
597 VRRP_STR
4f0b6b45
QY
598 INTERFACE_STR
599 "Only show VRRP instances on this interface\n"
6e21b5ae
QY
600 VRRP_VRID_STR
601 JSON_STR)
1d21789e
QY
602{
603 struct vrrp_vrouter *vr;
4f0b6b45
QY
604 struct listnode *ln;
605 struct list *ll = hash_to_list(vrrp_vrouters_hash);
6e21b5ae 606 struct json_object *j = json_object_new_array();
1d21789e 607
30a1595d
QY
608 list_sort(ll, vrrp_instance_display_sort_cmp);
609
4f0b6b45
QY
610 for (ALL_LIST_ELEMENTS_RO(ll, ln, vr)) {
611 if (ifn && !strmatch(ifn, vr->ifp->name))
612 continue;
48cd8f13 613 if (vrid && ((uint8_t) vrid) != vr->vrid)
4f0b6b45 614 continue;
5302f67b 615
6e21b5ae
QY
616 if (!json)
617 vrrp_show(vty, vr);
618 else
619 json_object_array_add(j, vrrp_build_json(vr));
1d21789e 620 }
c23edd74 621
6e21b5ae
QY
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
4f0b6b45
QY
629 list_delete(&ll);
630
c23edd74
QY
631 return CMD_SUCCESS;
632}
633
30a1595d
QY
634DEFPY(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
78fb3dbe
QY
683
684DEFPY(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
709DEFUN_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
b637bcd4
QY
723/* clang-format on */
724
f828842a 725static struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1};
78fb3dbe 726static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
f828842a 727static struct cmd_node vrrp_node = {VRRP_NODE, "", 1};
78fb3dbe 728
5435a2bf
QY
729void vrrp_vty_init(void)
730{
f828842a
QY
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);
5435a2bf 734 if_cmd_init();
78fb3dbe 735
c23edd74 736 install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
30a1595d 737 install_element(VIEW_NODE, &vrrp_vrid_show_summary_cmd);
78fb3dbe
QY
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);
27fd8827 741 install_element(CONFIG_NODE, &vrrp_autoconfigure_cmd);
8cd1d277 742 install_element(CONFIG_NODE, &vrrp_default_cmd);
5435a2bf 743 install_element(INTERFACE_NODE, &vrrp_vrid_cmd);
f96a183b 744 install_element(INTERFACE_NODE, &vrrp_shutdown_cmd);
c23edd74 745 install_element(INTERFACE_NODE, &vrrp_priority_cmd);
1d21789e 746 install_element(INTERFACE_NODE, &vrrp_advertisement_interval_cmd);
c23edd74 747 install_element(INTERFACE_NODE, &vrrp_ip_cmd);
862f2f37 748 install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
8ec51216 749 install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
5435a2bf 750}