diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 6527ec5f41..a1710ec127 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -11,8 +11,12 @@ #include "lib/command.h" #include "lib/log.h" #include "lib/northbound_cli.h" +#include "lib/termtable.h" +#include "lib/ipaddr.h" +#ifndef VTYSH_EXTRACT_PL #include "bfdd/bfdd_cli_clippy.c" +#endif /* VTYSH_EXTRACT_PL */ #include "bfd.h" #include "bfdd_nb.h" @@ -31,6 +35,10 @@ #define LOCAL_INTF_STR "Configure local interface name to use\n" #define VRF_STR "Configure VRF\n" #define VRF_NAME_STR "Configure VRF name\n" +#define SESSION_NAME_STR "Specify bfd session name\n" +#define SET_SESSION_NAME_STR "bfd session name\n" +#define SESSION_MODE_STR "Specify bfd session mode\n" +#define APPLY_SESSION_MODE_STR "Enable bfd mode\n" /* * Prototypes. @@ -41,6 +49,12 @@ bfd_cli_is_single_hop(struct vty *vty) return strstr(VTY_CURR_XPATH, "/single-hop") != NULL; } +static bool bfd_cli_is_sbfd_echo(struct vty *vty) +{ + return strstr(VTY_CURR_XPATH, "/sbfd-echo") != NULL; +} + + static bool bfd_cli_is_profile(struct vty *vty) { @@ -215,45 +229,486 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults __attribute__((__unused__)), - bool mhop) +DEFPY_YANG_NOSH( + sbfd_echo_peer_enter, sbfd_echo_peer_enter_cmd, + "peer bfd-mode sbfd-echo bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + srv6-source-ipv6 X:X::X:X srv6-encap-data X:X::X:X...", + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-echo mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure source ipv6 address for srv6 encap\n" + LOCAL_IPV6_STR + "Configure sidlist data for srv6 encap\n" + "X:X::X:X IPv6 sid address\n") { - const char *vrf = yang_dnode_get_string(dnode, "vrf"); + int ret, slen, data_idx = 11; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32], xpath_mh[XPATH_MAXLEN + 32]; - vty_out(vty, " peer %s", - yang_dnode_get_string(dnode, "dest-addr")); - - if (mhop) - vty_out(vty, " multihop"); - - if (yang_dnode_exists(dnode, "source-addr")) - vty_out(vty, " local-address %s", - yang_dnode_get_string(dnode, "source-addr")); - - if (strcmp(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, " vrf %s", vrf); - - if (!mhop) { - const char *ifname = - yang_dnode_get_string(dnode, "interface"); - if (strcmp(ifname, "*")) - vty_out(vty, " interface %s", ifname); + if (!bfdname) { + vty_out(vty, "%% ERROR: bfd name is required\n"); + return CMD_WARNING_CONFIG_FAILED; } - vty_out(vty, "\n"); + if (strcmp(peer_str, local_address_str)) { + vty_out(vty, + "%% ERROR: peer and local-address must be the same in sbfd-echo mode\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-echo[source-addr='%s'][bfd-name='%s']", + local_address_str, bfdname); + + if (vrf) { + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + data_idx += 2; + } else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (multihop) { + snprintf(xpath_mh, sizeof(xpath_mh), "%s/multi-hop", xpath); + nb_cli_enqueue_change(vty, xpath_mh, NB_OP_MODIFY, "true"); + data_idx += 1; + } + + for (int i = data_idx; i < argc; i++) { + snprintf(xpath_sl, sizeof(xpath_sl), "%s/srv6-encap-data", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_CREATE, argv[i]->arg); + } + + snprintf(xpath_sl, sizeof(xpath_sl), "%s/srv6-source-ipv6", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, srv6_source_ipv6_str); + + snprintf(xpath_sl, sizeof(xpath_sl), "%s/dest-addr", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, peer_str); + + /* Apply settings immediately. */ + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(BFD_PEER_NODE, xpath); + + return ret; +} + +DEFPY_YANG( + sbfd_echo_no_peer, sbfd_echo_no_peer_cmd, + "no peer bfd-mode sbfd-echo bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + srv6-source-ipv6 X:X::X:X srv6-encap-data X:X::X:X...", + NO_STR + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-echo mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure source ipv6 address for srv6 encap\n" + LOCAL_IPV6_STR + "Configure sidlist data for srv6 encap\n" + "X:X::X:X IPv6 sid address\n") +{ + int slen; + char xpath[XPATH_MAXLEN]; + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-echo[source-addr='%s'][bfd-name='%s']", + local_address_str, bfdname); + + if (vrf) + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + /* Apply settings immediatly. */ + return nb_cli_apply_changes(vty, NULL); +} + + +DEFPY_YANG_NOSH( + sbfd_init_peer_enter, sbfd_init_peer_enter_cmd, + "peer bfd-mode sbfd-init bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + remote-discr (1-4294967295)$discr srv6-source-ipv6 X:X::X:X srv6-encap-data X:X::X:X...", + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-init mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n" + "Configure source ipv6 address for srv6 encap\n" + LOCAL_IPV6_STR + "Configure sidlist data for srv6 encap\n" + "X:X::X:X IPv6 sid address\n") +{ + int ret, slen, data_idx = 13; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32], xpath_rd[XPATH_MAXLEN + 32], + xpath_mh[XPATH_MAXLEN + 32]; + struct ipaddr peer_addr = { 0 }; + struct ipaddr local_addr = { 0 }; + + if (!bfdname) { + vty_out(vty, "%% ERROR: bfd name is required\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + str2ipaddr(peer_str, &peer_addr); + if (peer_addr.ipa_type == AF_UNSPEC) { + vty_out(vty, "%% ERROR: peer is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + str2ipaddr(local_address_str, &local_addr); + if (local_addr.ipa_type == AF_UNSPEC) { + vty_out(vty, "%% ERROR: local_address is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (peer_addr.ipa_type != local_addr.ipa_type) { + vty_out(vty, "%% ERROR: peer and local_address are not the same ip version\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, peer_str, bfdname); + + if (vrf) { + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + data_idx += 2; + } else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (multihop) { + snprintf(xpath_mh, sizeof(xpath_mh), "%s/multi-hop", xpath); + nb_cli_enqueue_change(vty, xpath_mh, NB_OP_MODIFY, "true"); + data_idx += 1; + } + + if (srv6_source_ipv6_str) { + for (int i = data_idx; i < argc; i++) { + snprintf(xpath_sl, sizeof(xpath_sl), "%s/srv6-encap-data", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_CREATE, argv[i]->arg); + } + + snprintf(xpath_sl, sizeof(xpath_sl), "%s/srv6-source-ipv6", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, srv6_source_ipv6_str); + } + + snprintf(xpath_rd, sizeof(xpath_rd), "%s/remote-discr", xpath); + nb_cli_enqueue_change(vty, xpath_rd, NB_OP_MODIFY, discr_str); + + /* Apply settings immediately. */ + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(BFD_PEER_NODE, xpath); + + return ret; +} + +DEFPY_YANG( + sbfd_init_no_peer, sbfd_init_no_peer_cmd, + "no peer bfd-mode sbfd-init bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + remote-discr (0-4294967295)$discr srv6-source-ipv6 X:X::X:X srv6-encap-data X:X::X:X...", + NO_STR + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-init mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n" + "Configure source ipv6 address for srv6 encap\n" + LOCAL_IPV6_STR + "Configure sidlist data for srv6 encap\n" + "X:X::X:X IPv6 sid address\n") +{ + int slen; + char xpath[XPATH_MAXLEN]; + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, peer_str, bfdname); + + if (vrf) + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + /* Apply settings immediatly. */ + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG_NOSH( + sbfd_init_peer_raw_enter, sbfd_init_peer_raw_enter_cmd, + "peer bfd-mode sbfd-init bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + remote-discr (1-4294967295)$discr", + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-init mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n") +{ + int ret, slen; + char xpath[XPATH_MAXLEN], xpath_rd[XPATH_MAXLEN + 32], xpath_mh[XPATH_MAXLEN + 32]; + struct ipaddr peer_addr = { 0 }; + struct ipaddr local_addr = { 0 }; + + if (!bfdname) { + vty_out(vty, "%% ERROR: bfd name is required\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + str2ipaddr(peer_str, &peer_addr); + if (peer_addr.ipa_type == AF_UNSPEC) { + vty_out(vty, "%% ERROR: peer is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + str2ipaddr(local_address_str, &local_addr); + if (local_addr.ipa_type == AF_UNSPEC) { + vty_out(vty, "%% ERROR: local_address is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (peer_addr.ipa_type != local_addr.ipa_type) { + vty_out(vty, "%% ERROR: peer and local_address are not the same ip version\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, peer_str, bfdname); + + if (vrf) + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (multihop) { + snprintf(xpath_mh, sizeof(xpath_mh), "%s/multi-hop", xpath); + nb_cli_enqueue_change(vty, xpath_mh, NB_OP_MODIFY, "true"); + } + + snprintf(xpath_rd, sizeof(xpath_rd), "%s/remote-discr", xpath); + nb_cli_enqueue_change(vty, xpath_rd, NB_OP_MODIFY, discr_str); + + /* Apply settings immediately. */ + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(BFD_PEER_NODE, xpath); + + return ret; +} + +DEFPY_YANG( + sbfd_init_no_peer_raw, sbfd_init_no_peer_raw_cmd, + "no peer bfd-mode sbfd-init bfd-name BFDNAME$bfdname \ + [multihop$multihop] local-address [vrf NAME] \ + remote-discr (0-4294967295)$discr", + NO_STR + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-init mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + VRF_STR + VRF_NAME_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n") +{ + int slen; + char xpath[XPATH_MAXLEN]; + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, peer_str, bfdname); + + if (vrf) + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + /* Apply settings immediatly. */ + return nb_cli_apply_changes(vty, NULL); +} + +static const char *_bfd_cli_bfd_mode_type_to_string(enum bfd_mode_type mode) +{ + switch (mode) { + case BFD_MODE_TYPE_BFD: + return "bfd"; + case BFD_MODE_TYPE_SBFD_ECHO: + return "sbfd-echo"; + case BFD_MODE_TYPE_SBFD_INIT: + return "sbfd-init"; + default: + return "Unknown"; + } +} + +struct sidlist_show_iter { + char buf[INET6_ADDRSTRLEN * SRV6_MAX_SEGS]; +}; + +static int sidlist_show_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct sidlist_show_iter *iter = arg; + const char *addr; + + addr = yang_dnode_get_string(dnode, NULL); + + strlcat(iter->buf, addr, INET6_ADDRSTRLEN * SRV6_MAX_SEGS); + strlcat(iter->buf, " ", INET6_ADDRSTRLEN * SRV6_MAX_SEGS); + + return YANG_ITER_CONTINUE; +} + +static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults __attribute__((__unused__)), bool mhop, + uint32_t bfd_mode) +{ + const char *vrf = yang_dnode_get_string(dnode, "vrf"); + struct sidlist_show_iter iter = { 0 }; + + vty_out(vty, " peer %s", yang_dnode_get_string(dnode, "./dest-addr")); + if (bfd_mode == BFD_MODE_TYPE_BFD) { + if (mhop) + vty_out(vty, " multihop"); + + if (yang_dnode_exists(dnode, "./source-addr")) + vty_out(vty, " local-address %s", + yang_dnode_get_string(dnode, "./source-addr")); + + if (strcmp(vrf, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrf); + + if (!mhop) { + const char *ifname = yang_dnode_get_string(dnode, "./interface"); + + if (strcmp(ifname, "*")) + vty_out(vty, " interface %s", ifname); + } + vty_out(vty, "\n"); + } else if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd_mode == BFD_MODE_TYPE_SBFD_INIT) { + vty_out(vty, " bfd-mode %s", _bfd_cli_bfd_mode_type_to_string(bfd_mode)); + + if (yang_dnode_exists(dnode, "bfd-name")) + vty_out(vty, " bfd-name %s", yang_dnode_get_string(dnode, "bfd-name")); + + if (mhop) + vty_out(vty, " multihop"); + + if (yang_dnode_exists(dnode, "source-addr")) + vty_out(vty, " local-address %s", + yang_dnode_get_string(dnode, "source-addr")); + + if (strcmp(vrf, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrf); + + if (bfd_mode == BFD_MODE_TYPE_SBFD_INIT) { + if (yang_dnode_exists(dnode, "remote-discr")) + vty_out(vty, " remote-discr %u", + yang_dnode_get_uint32(dnode, "remote-discr")); + } + + if (yang_dnode_exists(dnode, "srv6-source-ipv6")) + vty_out(vty, " srv6-source-ipv6 %s", + yang_dnode_get_string(dnode, "srv6-source-ipv6")); + + if (yang_dnode_exists(dnode, "srv6-encap-data")) { + yang_dnode_iterate(sidlist_show_iter_cb, &iter, dnode, "./srv6-encap-data"); + vty_out(vty, " srv6-encap-data %s", iter.buf); + } + + vty_out(vty, "\n"); + } } void bfd_cli_show_single_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - _bfd_cli_show_peer(vty, dnode, show_defaults, false); + _bfd_cli_show_peer(vty, dnode, show_defaults, false, BFD_MODE_TYPE_BFD); } void bfd_cli_show_multi_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - _bfd_cli_show_peer(vty, dnode, show_defaults, true); + _bfd_cli_show_peer(vty, dnode, show_defaults, true, BFD_MODE_TYPE_BFD); +} + +void bfd_cli_show_sbfd_echo_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + _bfd_cli_show_peer(vty, dnode, show_defaults, false, BFD_MODE_TYPE_SBFD_ECHO); +} + +void bfd_cli_show_sbfd_init_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + _bfd_cli_show_peer(vty, dnode, show_defaults, true, BFD_MODE_TYPE_SBFD_INIT); } void bfd_cli_show_peer_end(struct vty *vty, const struct lyd_node *dnode @@ -446,8 +901,9 @@ DEFPY_YANG( { char value[32]; - if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { - vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty) && !bfd_cli_is_sbfd_echo(vty)) { + vty_out(vty, + "%% Echo mode is only available for single hop or sbfd echo sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -470,8 +926,9 @@ DEFPY_YANG( { char value[32]; - if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { - vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty) && !bfd_cli_is_sbfd_echo(vty)) { + vty_out(vty, + "%% Echo mode is only available for single hop or sbfd echo sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -501,11 +958,13 @@ DEFPY_YANG( { char value[32]; - if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { - vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty) && !bfd_cli_is_sbfd_echo(vty)) { + vty_out(vty, + "%% Echo mode is only available for single hop or sbfd echo sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } + if (disabled) snprintf(value, sizeof(value), "0"); else @@ -657,6 +1116,160 @@ DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd, return nb_cli_apply_changes(vty, NULL); } +DEFPY( + sbfd_reflector, sbfd_reflector_cmd, + "sbfd reflector source-address X:X::X:X$srcip discriminator WORD...", + "seamless BFD\n" + "sbfd reflector\n" + "binding source ip address\n" + IPV6_STR + "discriminator\n" + "discriminator value or range (e.g. 100 or 100 200 300 or 100-300)\n") +{ + int idx_discr = 5; + int i; + uint32_t j; + uint32_t discr = 0; + uint32_t discr_from = 0; + uint32_t discr_to = 0; + + for (i = idx_discr; i < argc; i++) { + /* check validity*/ + char *pstr = argv[i]->arg; + + /*single discr*/ + if (strspn(pstr, "0123456789") == strlen(pstr)) { + discr = atol(pstr); + sbfd_reflector_new(discr, &srcip); + } + /*discr segment*/ + else if (strspn(pstr, "0123456789-") == strlen(pstr)) { + char *token = strtok(argv[i]->arg, "-"); + + if (token) + discr_from = atol(token); + + token = strtok(NULL, "-"); + if (token) + discr_to = atol(token); + + if (discr_from >= discr_to) { + vty_out(vty, "input discriminator range %u-%u is illegal\n", + discr_from, discr_to); + } + + for (j = discr_from; j <= discr_to; j++) + sbfd_reflector_new(j, &srcip); + } + /*illegal input*/ + else + vty_out(vty, "input discriminator %s is illegal\n", (char *)argv[i]); + } + + return CMD_SUCCESS; +} + +DEFPY( + no_sbfd_reflector_all, no_sbfd_reflector_all_cmd, + "no sbfd reflector [all]", + NO_STR + "seamless BFD\n" + "sbfd reflector\n" + "all\n") +{ + sbfd_reflector_flush(); + + if (sbfd_discr_get_count()) { + vty_out(vty, "delete all reflector discriminator failed.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFPY( + no_sbfd_reflector, no_sbfd_reflector_cmd, + "no sbfd reflector (0-4294967295)$start_discr [(0-4294967295)$end_discr]", + NO_STR + "seamless BFD\n" + "sbfd reflector\n" + "start discriminator\n" + "end discriminator\n") +{ + struct sbfd_reflector *sr; + int32_t i; + + if (end_discr == 0) { + if (start_discr == 0) { + vty_out(vty, "input reflector discriminator is illegal.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + sr = sbfd_discr_lookup(start_discr); + if (!sr) { + vty_out(vty, "input reflector discriminator does not exist.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + // notify bfdsyncd + //bfd_fpm_sbfd_reflector_sendmsg(sr, false); + sbfd_reflector_free(start_discr); + + } else { + if (end_discr <= start_discr) { + vty_out(vty, "input reflector discriminator is illegal.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + for (i = start_discr; i <= end_discr; i++) { + sr = sbfd_discr_lookup(i); + if (sr) { + // notify bfdsyncd + //bfd_fpm_sbfd_reflector_sendmsg(sr, false); + sbfd_reflector_free(i); + } + } + } + + return CMD_SUCCESS; +} + +static void _sbfd_reflector_show(struct hash_bucket *hb, void *arg) +{ + struct sbfd_reflector *sr = hb->data; + struct ttable *tt; + char buf[INET6_ADDRSTRLEN]; + + tt = (struct ttable *)arg; + + ttable_add_row(tt, "%u|%s|%s|%s", sr->discr, + inet_ntop(AF_INET6, &sr->local, buf, sizeof(buf)), "Active", "Software"); +} + +DEFPY( + sbfd_reflector_show_info, sbfd_reflector_show_info_cmd, + "show sbfd reflector", + "show\n" + "seamless BFD\n" + "sbfd reflector\n") +{ + struct ttable *tt; + char *out; + + vty_out(vty, "sbfd reflector discriminator :\n"); + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "SBFD-Discr|SourceIP|State|CreateType"); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); + + sbfd_discr_iterate(_sbfd_reflector_show, tt); + + out = ttable_dump(tt, "\n"); + vty_out(vty, "%s", out); + XFREE(MTYPE_TMP, out); + ttable_del(tt); + + return CMD_SUCCESS; +} void bfd_cli_peer_profile_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { @@ -694,6 +1307,18 @@ bfdd_cli_init(void) install_element(BFD_NODE, &bfd_peer_enter_cmd); install_element(BFD_NODE, &bfd_no_peer_cmd); + install_element(BFD_NODE, &sbfd_echo_peer_enter_cmd); + install_element(BFD_NODE, &sbfd_echo_no_peer_cmd); + + install_element(BFD_NODE, &sbfd_init_peer_enter_cmd); + install_element(BFD_NODE, &sbfd_init_no_peer_cmd); + install_element(BFD_NODE, &sbfd_init_peer_raw_enter_cmd); + install_element(BFD_NODE, &sbfd_init_no_peer_raw_cmd); + + install_element(BFD_NODE, &sbfd_reflector_cmd); + install_element(BFD_NODE, &no_sbfd_reflector_all_cmd); + install_element(BFD_NODE, &no_sbfd_reflector_cmd); + install_element(VIEW_NODE, &sbfd_reflector_show_info_cmd); install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd); install_element(BFD_PEER_NODE, &bfd_peer_mult_cmd); install_element(BFD_PEER_NODE, &bfd_peer_rx_cmd);