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