1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * BFD daemon CLI implementation.
5 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
11 #include "lib/command.h"
13 #include "lib/northbound_cli.h"
15 #include "bfdd/bfdd_cli_clippy.c"
23 #define PEER_STR "Configure peer\n"
24 #define INTERFACE_NAME_STR "Configure interface name to use\n"
25 #define PEER_IPV4_STR "IPv4 peer address\n"
26 #define PEER_IPV6_STR "IPv6 peer address\n"
27 #define MHOP_STR "Configure multihop\n"
28 #define LOCAL_STR "Configure local address\n"
29 #define LOCAL_IPV4_STR "IPv4 local address\n"
30 #define LOCAL_IPV6_STR "IPv6 local address\n"
31 #define LOCAL_INTF_STR "Configure local interface name to use\n"
32 #define VRF_STR "Configure VRF\n"
33 #define VRF_NAME_STR "Configure VRF name\n"
39 bfd_cli_is_single_hop(struct vty
*vty
)
41 return strstr(VTY_CURR_XPATH
, "/single-hop") != NULL
;
45 bfd_cli_is_profile(struct vty
*vty
)
47 return strstr(VTY_CURR_XPATH
, "/bfd/profile") != NULL
;
54 bfd_enter
, bfd_enter_cmd
,
56 "Configure BFD peers\n")
60 nb_cli_enqueue_change(vty
, "/frr-bfdd:bfdd/bfd", NB_OP_CREATE
, NULL
);
61 ret
= nb_cli_apply_changes(vty
, NULL
);
62 if (ret
== CMD_SUCCESS
)
63 VTY_PUSH_XPATH(BFD_NODE
, "/frr-bfdd:bfdd/bfd");
69 bfd_config_reset
, bfd_config_reset_cmd
,
72 "Configure BFD peers\n")
74 nb_cli_enqueue_change(vty
, "/frr-bfdd:bfdd/bfd", NB_OP_DESTROY
, NULL
);
75 return nb_cli_apply_changes(vty
, NULL
);
78 void bfd_cli_show_header(struct vty
*vty
,
79 const struct lyd_node
*dnode
80 __attribute__((__unused__
)),
81 bool show_defaults
__attribute__((__unused__
)))
83 vty_out(vty
, "!\nbfd\n");
86 void bfd_cli_show_header_end(struct vty
*vty
, const struct lyd_node
*dnode
87 __attribute__((__unused__
)))
89 vty_out(vty
, "exit\n");
94 bfd_peer_enter
, bfd_peer_enter_cmd
,
95 "peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$ifname|vrf NAME}]",
109 char source_str
[INET6_ADDRSTRLEN
+ 32];
110 char xpath
[XPATH_MAXLEN
], xpath_srcaddr
[XPATH_MAXLEN
+ 32];
113 if (!local_address_str
) {
115 "%% local-address is required when using multihop\n");
116 return CMD_WARNING_CONFIG_FAILED
;
120 "%% interface is prohibited when using multihop\n");
121 return CMD_WARNING_CONFIG_FAILED
;
123 snprintf(source_str
, sizeof(source_str
), "[source-addr='%s']",
128 slen
= snprintf(xpath
, sizeof(xpath
),
129 "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
130 multihop
? "multi-hop" : "single-hop", source_str
,
133 slen
+= snprintf(xpath
+ slen
, sizeof(xpath
) - slen
,
134 "[interface='%s']", ifname
);
136 slen
+= snprintf(xpath
+ slen
, sizeof(xpath
) - slen
,
139 snprintf(xpath
+ slen
, sizeof(xpath
) - slen
, "[vrf='%s']", vrf
);
141 snprintf(xpath
+ slen
, sizeof(xpath
) - slen
, "[vrf='%s']",
144 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
145 if (multihop
== NULL
&& local_address_str
!= NULL
) {
146 snprintf(xpath_srcaddr
, sizeof(xpath_srcaddr
),
147 "%s/source-addr", xpath
);
148 nb_cli_enqueue_change(vty
, xpath_srcaddr
, NB_OP_MODIFY
,
152 /* Apply settings immediately. */
153 ret
= nb_cli_apply_changes(vty
, NULL
);
154 if (ret
== CMD_SUCCESS
)
155 VTY_PUSH_XPATH(BFD_PEER_NODE
, xpath
);
161 bfd_no_peer
, bfd_no_peer_cmd
,
162 "no peer <A.B.C.D|X:X::X:X> [{multihop$multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME$ifname|vrf NAME}]",
177 char xpath
[XPATH_MAXLEN
];
178 char source_str
[INET6_ADDRSTRLEN
+ 32];
181 if (!local_address_str
) {
183 "%% local-address is required when using multihop\n");
184 return CMD_WARNING_CONFIG_FAILED
;
188 "%% interface is prohibited when using multihop\n");
189 return CMD_WARNING_CONFIG_FAILED
;
191 snprintf(source_str
, sizeof(source_str
), "[source-addr='%s']",
196 slen
= snprintf(xpath
, sizeof(xpath
),
197 "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
198 multihop
? "multi-hop" : "single-hop", source_str
,
201 slen
+= snprintf(xpath
+ slen
, sizeof(xpath
) - slen
,
202 "[interface='%s']", ifname
);
204 slen
+= snprintf(xpath
+ slen
, sizeof(xpath
) - slen
,
207 snprintf(xpath
+ slen
, sizeof(xpath
) - slen
, "[vrf='%s']", vrf
);
209 snprintf(xpath
+ slen
, sizeof(xpath
) - slen
, "[vrf='%s']",
212 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
214 /* Apply settings immediatly. */
215 return nb_cli_apply_changes(vty
, NULL
);
218 static void _bfd_cli_show_peer(struct vty
*vty
, const struct lyd_node
*dnode
,
219 bool show_defaults
__attribute__((__unused__
)),
222 const char *vrf
= yang_dnode_get_string(dnode
, "./vrf");
224 vty_out(vty
, " peer %s",
225 yang_dnode_get_string(dnode
, "./dest-addr"));
228 vty_out(vty
, " multihop");
230 if (yang_dnode_exists(dnode
, "./source-addr"))
231 vty_out(vty
, " local-address %s",
232 yang_dnode_get_string(dnode
, "./source-addr"));
234 if (strcmp(vrf
, VRF_DEFAULT_NAME
))
235 vty_out(vty
, " vrf %s", vrf
);
239 yang_dnode_get_string(dnode
, "./interface");
240 if (strcmp(ifname
, "*"))
241 vty_out(vty
, " interface %s", ifname
);
247 void bfd_cli_show_single_hop_peer(struct vty
*vty
, const struct lyd_node
*dnode
,
250 _bfd_cli_show_peer(vty
, dnode
, show_defaults
, false);
253 void bfd_cli_show_multi_hop_peer(struct vty
*vty
, const struct lyd_node
*dnode
,
256 _bfd_cli_show_peer(vty
, dnode
, show_defaults
, true);
259 void bfd_cli_show_peer_end(struct vty
*vty
, const struct lyd_node
*dnode
260 __attribute__((__unused__
)))
262 vty_out(vty
, " exit\n");
263 vty_out(vty
, " !\n");
267 bfd_peer_shutdown
, bfd_peer_shutdown_cmd
,
270 "Disable BFD peer\n")
272 nb_cli_enqueue_change(vty
, "./administrative-down", NB_OP_MODIFY
,
273 no
? "false" : "true");
274 return nb_cli_apply_changes(vty
, NULL
);
277 void bfd_cli_show_shutdown(struct vty
*vty
, const struct lyd_node
*dnode
,
280 vty_out(vty
, " %sshutdown\n",
281 yang_dnode_get_bool(dnode
, NULL
) ? "" : "no ");
285 bfd_peer_passive
, bfd_peer_passive_cmd
,
288 "Don't attempt to start sessions\n")
290 nb_cli_enqueue_change(vty
, "./passive-mode", NB_OP_MODIFY
,
291 no
? "false" : "true");
292 return nb_cli_apply_changes(vty
, NULL
);
295 void bfd_cli_show_passive(struct vty
*vty
, const struct lyd_node
*dnode
,
298 vty_out(vty
, " %spassive-mode\n",
299 yang_dnode_get_bool(dnode
, NULL
) ? "" : "no ");
303 bfd_peer_minimum_ttl
, bfd_peer_minimum_ttl_cmd
,
304 "[no] minimum-ttl (1-254)$ttl",
306 "Expect packets with at least this TTL\n"
307 "Minimum TTL expected\n")
309 if (bfd_cli_is_single_hop(vty
)) {
310 vty_out(vty
, "%% Minimum TTL is only available for multi hop sessions.\n");
311 return CMD_WARNING_CONFIG_FAILED
;
315 nb_cli_enqueue_change(vty
, "./minimum-ttl", NB_OP_DESTROY
,
318 nb_cli_enqueue_change(vty
, "./minimum-ttl", NB_OP_MODIFY
,
320 return nb_cli_apply_changes(vty
, NULL
);
324 no_bfd_peer_minimum_ttl
, no_bfd_peer_minimum_ttl_cmd
,
327 "Expect packets with at least this TTL\n")
329 nb_cli_enqueue_change(vty
, "./minimum-ttl", NB_OP_DESTROY
, NULL
);
330 return nb_cli_apply_changes(vty
, NULL
);
333 void bfd_cli_show_minimum_ttl(struct vty
*vty
, const struct lyd_node
*dnode
,
336 vty_out(vty
, " minimum-ttl %s\n", yang_dnode_get_string(dnode
, NULL
));
340 bfd_peer_mult
, bfd_peer_mult_cmd
,
341 "detect-multiplier (2-255)$multiplier",
342 "Configure peer detection multiplier\n"
343 "Configure peer detection multiplier value\n")
345 nb_cli_enqueue_change(vty
, "./detection-multiplier", NB_OP_MODIFY
,
347 return nb_cli_apply_changes(vty
, NULL
);
350 void bfd_cli_show_mult(struct vty
*vty
, const struct lyd_node
*dnode
,
353 vty_out(vty
, " detect-multiplier %s\n",
354 yang_dnode_get_string(dnode
, NULL
));
358 bfd_peer_rx
, bfd_peer_rx_cmd
,
359 "receive-interval (10-60000)$interval",
360 "Configure peer receive interval\n"
361 "Configure peer receive interval value in milliseconds\n")
365 snprintf(value
, sizeof(value
), "%ld", interval
* 1000);
366 nb_cli_enqueue_change(vty
, "./required-receive-interval", NB_OP_MODIFY
,
369 return nb_cli_apply_changes(vty
, NULL
);
372 void bfd_cli_show_rx(struct vty
*vty
, const struct lyd_node
*dnode
,
375 uint32_t value
= yang_dnode_get_uint32(dnode
, NULL
);
377 vty_out(vty
, " receive-interval %u\n", value
/ 1000);
381 bfd_peer_tx
, bfd_peer_tx_cmd
,
382 "transmit-interval (10-60000)$interval",
383 "Configure peer transmit interval\n"
384 "Configure peer transmit interval value in milliseconds\n")
388 snprintf(value
, sizeof(value
), "%ld", interval
* 1000);
389 nb_cli_enqueue_change(vty
, "./desired-transmission-interval",
390 NB_OP_MODIFY
, value
);
392 return nb_cli_apply_changes(vty
, NULL
);
395 void bfd_cli_show_tx(struct vty
*vty
, const struct lyd_node
*dnode
,
398 uint32_t value
= yang_dnode_get_uint32(dnode
, NULL
);
400 vty_out(vty
, " transmit-interval %u\n", value
/ 1000);
404 bfd_peer_echo
, bfd_peer_echo_cmd
,
407 "Configure echo mode\n")
409 if (!bfd_cli_is_profile(vty
) && !bfd_cli_is_single_hop(vty
)) {
411 "%% Echo mode is only available for single hop sessions.\n");
412 return CMD_WARNING_CONFIG_FAILED
;
415 if (!no
&& !bglobal
.bg_use_dplane
) {
418 "%% Echo mode works correctly for IPv4, but only works when the peer is also FRR for IPv6.\n");
421 "%% Current implementation of echo mode works only when the peer is also FRR.\n");
422 #endif /* BFD_LINUX */
425 nb_cli_enqueue_change(vty
, "./echo-mode", NB_OP_MODIFY
,
426 no
? "false" : "true");
427 return nb_cli_apply_changes(vty
, NULL
);
430 void bfd_cli_show_echo(struct vty
*vty
, const struct lyd_node
*dnode
,
433 vty_out(vty
, " %secho-mode\n",
434 yang_dnode_get_bool(dnode
, NULL
) ? "" : "no ");
438 bfd_peer_echo_interval
, bfd_peer_echo_interval_cmd
,
439 "echo-interval (10-60000)$interval",
440 "Configure peer echo intervals\n"
441 "Configure peer echo rx/tx intervals value in milliseconds\n")
445 if (!bfd_cli_is_profile(vty
) && !bfd_cli_is_single_hop(vty
)) {
446 vty_out(vty
, "%% Echo mode is only available for single hop sessions.\n");
447 return CMD_WARNING_CONFIG_FAILED
;
450 snprintf(value
, sizeof(value
), "%ld", interval
* 1000);
451 nb_cli_enqueue_change(vty
, "./desired-echo-transmission-interval",
452 NB_OP_MODIFY
, value
);
453 nb_cli_enqueue_change(vty
, "./required-echo-receive-interval",
454 NB_OP_MODIFY
, value
);
456 return nb_cli_apply_changes(vty
, NULL
);
460 bfd_peer_echo_transmit_interval
, bfd_peer_echo_transmit_interval_cmd
,
461 "echo transmit-interval (10-60000)$interval",
462 "Configure peer echo intervals\n"
463 "Configure desired transmit interval\n"
464 "Configure interval value in milliseconds\n")
468 if (!bfd_cli_is_profile(vty
) && !bfd_cli_is_single_hop(vty
)) {
469 vty_out(vty
, "%% Echo mode is only available for single hop sessions.\n");
470 return CMD_WARNING_CONFIG_FAILED
;
473 snprintf(value
, sizeof(value
), "%ld", interval
* 1000);
474 nb_cli_enqueue_change(vty
, "./desired-echo-transmission-interval",
475 NB_OP_MODIFY
, value
);
477 return nb_cli_apply_changes(vty
, NULL
);
480 void bfd_cli_show_desired_echo_transmission_interval(
481 struct vty
*vty
, const struct lyd_node
*dnode
, bool show_defaults
)
483 uint32_t value
= yang_dnode_get_uint32(dnode
, NULL
);
485 vty_out(vty
, " echo transmit-interval %u\n", value
/ 1000);
489 bfd_peer_echo_receive_interval
, bfd_peer_echo_receive_interval_cmd
,
490 "echo receive-interval <disabled$disabled|(10-60000)$interval>",
491 "Configure peer echo intervals\n"
492 "Configure required receive interval\n"
493 "Disable echo packets receive\n"
494 "Configure interval value in milliseconds\n")
498 if (!bfd_cli_is_profile(vty
) && !bfd_cli_is_single_hop(vty
)) {
499 vty_out(vty
, "%% Echo mode is only available for single hop sessions.\n");
500 return CMD_WARNING_CONFIG_FAILED
;
504 snprintf(value
, sizeof(value
), "0");
506 snprintf(value
, sizeof(value
), "%ld", interval
* 1000);
508 nb_cli_enqueue_change(vty
, "./required-echo-receive-interval",
509 NB_OP_MODIFY
, value
);
511 return nb_cli_apply_changes(vty
, NULL
);
514 void bfd_cli_show_required_echo_receive_interval(struct vty
*vty
,
515 const struct lyd_node
*dnode
,
518 uint32_t value
= yang_dnode_get_uint32(dnode
, NULL
);
521 vty_out(vty
, " echo receive-interval %u\n", value
/ 1000);
523 vty_out(vty
, " echo receive-interval disabled\n");
529 DEFPY_YANG_NOSH(bfd_profile
, bfd_profile_cmd
,
530 "profile BFDPROF$name",
532 BFD_PROFILE_NAME_STR
)
534 char xpath
[XPATH_MAXLEN
];
537 snprintf(xpath
, sizeof(xpath
), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
540 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
542 /* Apply settings immediately. */
543 rv
= nb_cli_apply_changes(vty
, NULL
);
544 if (rv
== CMD_SUCCESS
)
545 VTY_PUSH_XPATH(BFD_PROFILE_NODE
, xpath
);
550 DEFPY_YANG(no_bfd_profile
, no_bfd_profile_cmd
,
551 "no profile BFDPROF$name",
554 BFD_PROFILE_NAME_STR
)
556 char xpath
[XPATH_MAXLEN
];
558 snprintf(xpath
, sizeof(xpath
), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
561 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
563 /* Apply settings immediately. */
564 return nb_cli_apply_changes(vty
, NULL
);
567 void bfd_cli_show_profile(struct vty
*vty
, const struct lyd_node
*dnode
,
570 vty_out(vty
, " profile %s\n", yang_dnode_get_string(dnode
, "./name"));
573 ALIAS_YANG(bfd_peer_mult
, bfd_profile_mult_cmd
,
574 "detect-multiplier (2-255)$multiplier",
575 "Configure peer detection multiplier\n"
576 "Configure peer detection multiplier value\n")
578 ALIAS_YANG(bfd_peer_tx
, bfd_profile_tx_cmd
,
579 "transmit-interval (10-60000)$interval",
580 "Configure peer transmit interval\n"
581 "Configure peer transmit interval value in milliseconds\n")
583 ALIAS_YANG(bfd_peer_rx
, bfd_profile_rx_cmd
,
584 "receive-interval (10-60000)$interval",
585 "Configure peer receive interval\n"
586 "Configure peer receive interval value in milliseconds\n")
588 ALIAS_YANG(bfd_peer_shutdown
, bfd_profile_shutdown_cmd
,
591 "Disable BFD peer\n")
593 ALIAS_YANG(bfd_peer_passive
, bfd_profile_passive_cmd
,
596 "Don't attempt to start sessions\n")
598 ALIAS_YANG(bfd_peer_minimum_ttl
, bfd_profile_minimum_ttl_cmd
,
599 "[no] minimum-ttl (1-254)$ttl",
601 "Expect packets with at least this TTL\n"
602 "Minimum TTL expected\n")
604 ALIAS_YANG(no_bfd_peer_minimum_ttl
, no_bfd_profile_minimum_ttl_cmd
,
607 "Expect packets with at least this TTL\n")
609 ALIAS_YANG(bfd_peer_echo
, bfd_profile_echo_cmd
,
612 "Configure echo mode\n")
614 ALIAS_YANG(bfd_peer_echo_interval
, bfd_profile_echo_interval_cmd
,
615 "echo-interval (10-60000)$interval",
616 "Configure peer echo interval\n"
617 "Configure peer echo interval value in milliseconds\n")
620 bfd_peer_echo_transmit_interval
, bfd_profile_echo_transmit_interval_cmd
,
621 "echo transmit-interval (10-60000)$interval",
622 "Configure peer echo intervals\n"
623 "Configure desired transmit interval\n"
624 "Configure interval value in milliseconds\n")
627 bfd_peer_echo_receive_interval
, bfd_profile_echo_receive_interval_cmd
,
628 "echo receive-interval <disabled$disabled|(10-60000)$interval>",
629 "Configure peer echo intervals\n"
630 "Configure required receive interval\n"
631 "Disable echo packets receive\n"
632 "Configure interval value in milliseconds\n")
634 DEFPY_YANG(bfd_peer_profile
, bfd_peer_profile_cmd
,
635 "[no] profile BFDPROF$pname",
637 "Use BFD profile settings\n"
638 BFD_PROFILE_NAME_STR
)
641 nb_cli_enqueue_change(vty
, "./profile", NB_OP_DESTROY
, NULL
);
643 nb_cli_enqueue_change(vty
, "./profile", NB_OP_MODIFY
, pname
);
645 return nb_cli_apply_changes(vty
, NULL
);
648 void bfd_cli_peer_profile_show(struct vty
*vty
, const struct lyd_node
*dnode
,
651 vty_out(vty
, " profile %s\n", yang_dnode_get_string(dnode
, NULL
));
654 struct cmd_node bfd_profile_node
= {
655 .name
= "bfd profile",
656 .node
= BFD_PROFILE_NODE
,
657 .parent_node
= BFD_NODE
,
658 .prompt
= "%s(config-bfd-profile)# ",
661 static void bfd_profile_var(vector comps
, struct cmd_token
*token
)
663 extern struct bfdproflist bplist
;
664 struct bfd_profile
*bp
;
666 TAILQ_FOREACH (bp
, &bplist
, entry
) {
667 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, bp
->name
));
671 static const struct cmd_variable_handler bfd_vars
[] = {
672 {.tokenname
= "BFDPROF", .completions
= bfd_profile_var
},
673 {.completions
= NULL
}
679 install_element(CONFIG_NODE
, &bfd_enter_cmd
);
680 install_element(CONFIG_NODE
, &bfd_config_reset_cmd
);
682 install_element(BFD_NODE
, &bfd_peer_enter_cmd
);
683 install_element(BFD_NODE
, &bfd_no_peer_cmd
);
685 install_element(BFD_PEER_NODE
, &bfd_peer_shutdown_cmd
);
686 install_element(BFD_PEER_NODE
, &bfd_peer_mult_cmd
);
687 install_element(BFD_PEER_NODE
, &bfd_peer_rx_cmd
);
688 install_element(BFD_PEER_NODE
, &bfd_peer_tx_cmd
);
689 install_element(BFD_PEER_NODE
, &bfd_peer_echo_cmd
);
690 install_element(BFD_PEER_NODE
, &bfd_peer_echo_interval_cmd
);
691 install_element(BFD_PEER_NODE
, &bfd_peer_echo_transmit_interval_cmd
);
692 install_element(BFD_PEER_NODE
, &bfd_peer_echo_receive_interval_cmd
);
693 install_element(BFD_PEER_NODE
, &bfd_peer_profile_cmd
);
694 install_element(BFD_PEER_NODE
, &bfd_peer_passive_cmd
);
695 install_element(BFD_PEER_NODE
, &bfd_peer_minimum_ttl_cmd
);
696 install_element(BFD_PEER_NODE
, &no_bfd_peer_minimum_ttl_cmd
);
698 /* Profile commands. */
699 cmd_variable_handler_register(bfd_vars
);
701 install_node(&bfd_profile_node
);
702 install_default(BFD_PROFILE_NODE
);
704 install_element(BFD_NODE
, &bfd_profile_cmd
);
705 install_element(BFD_NODE
, &no_bfd_profile_cmd
);
707 install_element(BFD_PROFILE_NODE
, &bfd_profile_mult_cmd
);
708 install_element(BFD_PROFILE_NODE
, &bfd_profile_tx_cmd
);
709 install_element(BFD_PROFILE_NODE
, &bfd_profile_rx_cmd
);
710 install_element(BFD_PROFILE_NODE
, &bfd_profile_shutdown_cmd
);
711 install_element(BFD_PROFILE_NODE
, &bfd_profile_echo_cmd
);
712 install_element(BFD_PROFILE_NODE
, &bfd_profile_echo_interval_cmd
);
713 install_element(BFD_PROFILE_NODE
, &bfd_profile_echo_transmit_interval_cmd
);
714 install_element(BFD_PROFILE_NODE
, &bfd_profile_echo_receive_interval_cmd
);
715 install_element(BFD_PROFILE_NODE
, &bfd_profile_passive_cmd
);
716 install_element(BFD_PROFILE_NODE
, &bfd_profile_minimum_ttl_cmd
);
717 install_element(BFD_PROFILE_NODE
, &no_bfd_profile_minimum_ttl_cmd
);