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