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