From 32705fe7206438fb9cd23c0a866992fcc13788e0 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 09:01:18 +0000 Subject: [PATCH 01/21] bfdd: add enum bfd_mode_type for different bfd types Signed-off-by: wumu.zsl --- bfdd/bfd.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index d4d14ffce675..75204062f1ae 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -235,6 +235,12 @@ enum bfd_session_flags { BFD_SESS_FLAG_MAC_SET = 1 << 11, /* MAC of peer known */ }; +enum bfd_mode_type { + BFD_MODE_TYPE_BFD = 0, + BFD_MODE_TYPE_SBFD_ECHO = 1, + BFD_MODE_TYPE_SBFD_INIT = 2, +}; + /* * BFD session hash key. * From 6648243ee7371c24d965709db71ed106d8d540ba Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 09:09:45 +0000 Subject: [PATCH 02/21] bfdd: add bfdname in bfd_key sbfd will use bfdname for key hash Signed-off-by: wumu.zsl --- bfdd/bfd.c | 28 +++++++++++++++++++++++----- bfdd/bfd.h | 3 ++- bfdd/bfdd_nb_config.c | 39 ++++++++++++++++++++++++++++++++++++++- bfdd/bfdd_nb_state.c | 4 ++-- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index f32bc2598bdc..f46fd4a0b42f 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -224,8 +224,9 @@ void bfd_profile_remove(struct bfd_session *bs) void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local, bool mhop, const char *ifname, - const char *vrfname) + const char *vrfname, const char *bfdname) { + struct vrf *vrf = NULL; memset(key, 0, sizeof(*key)); switch (peer->sa_sin.sin_family) { @@ -248,10 +249,27 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, key->mhop = mhop; if (ifname && ifname[0]) strlcpy(key->ifname, ifname, sizeof(key->ifname)); - if (vrfname && vrfname[0]) - strlcpy(key->vrfname, vrfname, sizeof(key->vrfname)); + if (vrfname && vrfname[0] && strcmp(vrfname, VRF_DEFAULT_NAME) != 0) + { + vrf = vrf_lookup_by_name(vrfname); + if (vrf) + { + strlcpy(key->vrfname, vrf->name, sizeof(key->vrfname)); + } + else + { + strlcpy(key->vrfname, vrfname, sizeof(key->vrfname)); + } + } else + { strlcpy(key->vrfname, VRF_DEFAULT_NAME, sizeof(key->vrfname)); + } + + if (bfdname && bfdname[0]) + { + strlcpy(key->bfdname, bfdname, sizeof(key->bfdname)); + } } struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) @@ -260,7 +278,7 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, - bpc->bpc_localif, bpc->bpc_vrfname); + bpc->bpc_localif, bpc->bpc_vrfname, bpc->bfd_name); return bfd_key_lookup(key); } @@ -599,7 +617,7 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, vrf = vrf_lookup_by_id(vrfid); gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL, - vrf ? vrf->name : VRF_DEFAULT_NAME); + vrf ? vrf->name : VRF_DEFAULT_NAME, NULL); /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */ return bfd_key_lookup(key); diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 75204062f1ae..9994fa7427e9 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -260,6 +260,7 @@ struct bfd_key { struct in6_addr local; char ifname[IFNAMSIZ]; char vrfname[VRF_NAMSIZ]; + char bfdname[MAXNAMELEN]; } __attribute__((packed)); struct bfd_session_stats { @@ -606,7 +607,7 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc); void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local, bool mhop, const char *ifname, - const char *vrfname); + const char *vrfname, const char *bfdname); struct bfd_session *bfd_session_new(void); struct bfd_session *bs_registrate(struct bfd_session *bs); void bfd_session_free(struct bfd_session *bs); diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 48fbe7139c27..2f1ff0439786 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -13,14 +13,46 @@ #include "bfd.h" #include "bfdd_nb.h" +#include /* * Helpers. */ +static void get_ip_by_interface(const char *ifname, char *ifip) { + struct ifaddrs *ifaddr, *ifa; + int family; + char intfip[INET6_ADDRSTRLEN]; + + if (getifaddrs(&ifaddr) == -1) { + zlog_err("getifaddrs failed, ifname: %s", ifname); + return; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) continue; + family = ifa->ifa_addr->sa_family; + + if (family == AF_INET || family == AF_INET6) { + if (strcmp(ifa->ifa_name, ifname) == 0) { + getnameinfo(ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + intfip, sizeof(intfip), + NULL, 0, NI_NUMERICHOST); + strlcpy(ifip,intfip,INET6_ADDRSTRLEN - 1); + break; + } + } + } + + freeifaddrs(ifaddr); +} + static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, struct bfd_key *bk) { const char *ifname = NULL, *vrfname = NULL; + char ifip[INET6_ADDRSTRLEN]; struct sockaddr_any psa, lsa; /* Required destination parameter. */ @@ -37,10 +69,15 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, ifname = yang_dnode_get_string(dnode, "interface"); if (strcmp(ifname, "*") == 0) ifname = NULL; + if (ifname != NULL && !yang_dnode_exists(dnode, "source-addr")) + { + get_ip_by_interface(ifname,ifip); + strtosa(ifip, &lsa); + } } /* Generate the corresponding key. */ - gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname); + gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname, NULL); } struct session_iter { diff --git a/bfdd/bfdd_nb_state.c b/bfdd/bfdd_nb_state.c index 12acda8fd8a6..0523d9b266fe 100644 --- a/bfdd/bfdd_nb_state.c +++ b/bfdd/bfdd_nb_state.c @@ -50,7 +50,7 @@ bfdd_bfd_sessions_single_hop_lookup_entry(struct nb_cb_lookup_entry_args *args) strtosa(dest_addr, &psa); memset(&lsa, 0, sizeof(lsa)); - gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf); + gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf, NULL); return bfd_key_lookup(bk); } @@ -354,7 +354,7 @@ bfdd_bfd_sessions_multi_hop_lookup_entry(struct nb_cb_lookup_entry_args *args) strtosa(dest_addr, &psa); strtosa(source_addr, &lsa); - gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf); + gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf, NULL); return bfd_key_lookup(bk); } From 37967411d6800ab411a5b90ceff81c7d37616012 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 09:38:00 +0000 Subject: [PATCH 03/21] bfdd: modify frr-bfdd.yang for sbfd echo and sbfd init Signed-off-by: wumu.zsl --- yang/frr-bfdd.yang | 116 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index c5c824f7927f..e4d569cfe590 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -503,6 +503,122 @@ module frr-bfdd { config false; } } + + list srte-sbfd-echo { + key "source-addr bfd-name vrf"; + description "List of srte sbfd echo sessions"; + + leaf source-addr { + type inet:ip-address; + description "Local IP address"; + } + + leaf dest-addr { + type inet:ip-address; + description "IP address of the peer"; + } + + leaf bfd-name { + type string; + default ""; + description "Bfd session name."; + } + + leaf vrf { + type frr-vrf:vrf-ref; + description "Virtual Routing Domain name"; + } + + leaf profile { + type profile-ref; + description "Override defaults with profile."; + } + + leaf segment-list { + type inet:ip-address; + description "segment list address of sbfd session packet"; + } + + leaf source-ipv6 { + type inet:ip-address; + description "source ipv6 address of sbfd session packet"; + } + + leaf bfd-mode { + type uint32; + description "Bfd session mode."; + } + + uses session-common; + uses session-multi-hop; + uses session-echo; + + container stats { + uses session-states; + config false; + } + } + + list srte-sbfd-init { + key "source-addr dest-addr bfd-name vrf"; + description "List of srte sbfd echo sessions"; + + leaf source-addr { + type inet:ip-address; + description "Local IP address"; + } + + leaf dest-addr { + type inet:ip-address; + description "IP address of the peer"; + } + + leaf bfd-name { + type string; + default ""; + description "Bfd session name."; + } + + leaf vrf { + type frr-vrf:vrf-ref; + description "Virtual Routing Domain name"; + } + + leaf profile { + type profile-ref; + description "Override defaults with profile."; + } + + leaf segment-list { + type inet:ip-address; + description "segment list address of sbfd session packet"; + } + + leaf source-ipv6 { + type inet:ip-address; + description "source ipv6 address of sbfd session packet"; + } + + leaf remote-discr { + type uint32; + default 0; + description + "sbfd-init remote discriminator."; + } + + leaf bfd-mode { + type uint32; + description "Bfd session mode."; + } + + uses session-common; + uses session-multi-hop; + + container stats { + uses session-states; + config false; + } + } } } } From b4d2550ff9cdf7e6354bd115d2269dd59d300c8a Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 09:38:53 +0000 Subject: [PATCH 04/21] bfdd: add vtysh cmd for sbfd Signed-off-by: wumu.zsl --- vtysh/vtysh.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c460dea70cda..b3cc1e73b2b5 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2385,6 +2385,58 @@ DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BFDD, sbfd_echo_peer_enter, sbfd_echo_peer_enter_cmd, + "peer bfd-mode sbfd-echo bfd-name BFDNAME local-address source-ipv6 X:X::X:X [{vrf NAME}]", + "Configure peer\n" + "IPv4 peer address\n" + "IPv6 peer address\n" + "Specify bfd session mode\n" + "Enable sbfd-echo mode\n" + "Specify bfd session name\n" + "bfd session name\n" + "Configure local\n" + "IPv4 local address\n" + "IPv6 local address\n" + "Configure bfd session encap type\n" + "Apply Srv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + "Configure VRF\n" + "Configure VRF name\n") +{ + vty->node = BFD_PEER_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_BFDD, sbfd_init_peer_enter, sbfd_init_peer_enter_cmd, + "peer bfd-mode sbfd-init bfd-name BFDNAME local-address remote-discr (1-4294967295) [{encap-type SRv6 encap-data X:X::X:X source-ipv6 X:X::X:X|vrf NAME}]", + "Configure peer\n" + "IPv4 peer address\n" + "IPv6 peer address\n" + "Specify bfd session mode\n" + "Enable sbfd-init mode\n" + "Specify bfd session name\n" + "bfd session name\n" + "Configure local\n" + "IPv4 local address\n" + "IPv6 local address\n" + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n" + "Configure bfd session encap type\n" + "Apply Srv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + "Configure VRF\n" + "Configure VRF name\n") +{ + vty->node = BFD_PEER_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, "profile BFDPROF", BFD_PROFILE_STR @@ -5272,6 +5324,8 @@ void vtysh_init_vty(void) install_element(BFD_NODE, &vtysh_end_all_cmd); install_element(BFD_NODE, &bfd_peer_enter_cmd); + install_element(BFD_NODE, &sbfd_init_peer_enter_cmd); + install_element(BFD_NODE, &sbfd_echo_peer_enter_cmd); install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); From 14cebb42c162716e9a48175898845a09f29e0926 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 11:05:49 +0000 Subject: [PATCH 05/21] bfdd: implement sbfd Xpath callbacks Signed-off-by: wumu.zsl --- bfdd/bfdd_nb.c | 466 ++++++++++++++++++++++++++++++++++++++++++ bfdd/bfdd_nb.h | 34 +++ bfdd/bfdd_nb_config.c | 161 +++++++++++++++ bfdd/bfdd_nb_state.c | 88 +++++++- 4 files changed, 747 insertions(+), 2 deletions(-) diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c index 114fbc2bdd87..fa06db607386 100644 --- a/bfdd/bfdd_nb.c +++ b/bfdd/bfdd_nb.c @@ -13,6 +13,16 @@ #include "bfdd_nb.h" +static int dummy_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +static int dummy_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + /* clang-format off */ const struct frr_yang_module_info frr_bfdd_info = { .name = "frr-bfdd", @@ -483,6 +493,462 @@ const struct frr_yang_module_info frr_bfdd_info = { .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem, } }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo", + .cbs = { + .create = bfdd_bfd_sessions_srte_sbfd_echo_create, + .destroy = bfdd_bfd_sessions_srte_sbfd_echo_destroy, + .get_next = bfdd_bfd_sessions_srte_sbfd_echo_get_next, + .get_keys = bfdd_bfd_sessions_srte_sbfd_echo_get_keys, + .lookup_entry = bfdd_bfd_sessions_srte_sbfd_echo_lookup_entry, + .cli_show = bfd_cli_show_sbfd_echo_peer, /* TODO */ + .cli_show_end = bfd_cli_show_peer_end, /* TODO */ + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/dest-addr", + .cbs = { + .modify = bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_modify, + .destroy = bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/source-ipv6", + .cbs = { + .modify = bfdd_bfd_sessions_srte_sbfd_source_ipv6_modify, + .destroy = bfdd_bfd_sessions_srte_sbfd_source_ipv6_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/profile", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_profile_modify, + .destroy = bfdd_bfd_sessions_single_hop_profile_destroy, + .cli_show = bfd_cli_peer_profile_show, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/detection-multiplier", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify, + .cli_show = bfd_cli_show_mult, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/desired-transmission-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify, + .cli_show = bfd_cli_show_tx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/required-receive-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify, + .cli_show = bfd_cli_show_rx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/echo-mode", + .cbs = { + .modify = bfdd_bfd_sessions_srte_sbfd_echo_mode_modify, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/desired-echo-transmission-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify, + .cli_show = bfd_cli_show_desired_echo_transmission_interval, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/required-echo-receive-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify, + .cli_show = bfd_cli_show_required_echo_receive_interval, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/administrative-down", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify, + .cli_show = bfd_cli_show_shutdown, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/passive-mode", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_passive_mode_modify, + .cli_show = bfd_cli_show_passive, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/bfd-name", + .cbs = { + .modify = dummy_modify, + .destroy = dummy_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/bfd-mode", + .cbs = { + .modify = bfdd_bfd_sessions_bfd_mode_modify, + .destroy = bfdd_bfd_sessions_bfd_mode_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/segment-list", + .cbs = { + .modify = bfdd_bfd_sessions_segment_list_modify, + .destroy = bfdd_bfd_sessions_segment_list_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/minimum-ttl", + .cbs = { + .modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify, + .destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy, + .cli_show = bfd_cli_show_minimum_ttl, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/local-discriminator", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/local-state", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/local-diagnostic", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/local-multiplier", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/remote-discriminator", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/remote-state", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/remote-diagnostic", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/remote-multiplier", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/negotiated-transmission-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/negotiated-receive-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/detection-mode", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/last-down-time", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/last-up-time", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/session-down-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/session-up-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/control-packet-input-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/control-packet-output-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/negotiated-echo-transmission-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/echo-packet-input-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/stats/echo-packet-output-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init", + .cbs = { + .create = bfdd_bfd_sessions_srte_sbfd_init_create, + .destroy = bfdd_bfd_sessions_srte_sbfd_init_destroy, + .get_next = bfdd_bfd_sessions_srte_sbfd_init_get_next, + .get_keys = bfdd_bfd_sessions_srte_sbfd_init_get_keys, + .lookup_entry = bfdd_bfd_sessions_srte_sbfd_init_lookup_entry, + .cli_show = bfd_cli_show_sbfd_init_peer, /* TODO */ + .cli_show_end = bfd_cli_show_peer_end, /* TODO */ + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/source-ipv6", + .cbs = { + .modify = bfdd_bfd_sessions_srte_sbfd_source_ipv6_modify, + .destroy = bfdd_bfd_sessions_srte_sbfd_source_ipv6_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/remote-discr", + .cbs = { + .modify = bfdd_bfd_sessions_srte_sbfd_init_remote_discr_modify, + .destroy = bfdd_bfd_sessions_srte_sbfd_init_remote_discr_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/profile", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_profile_modify, + .destroy = bfdd_bfd_sessions_single_hop_profile_destroy, + .cli_show = bfd_cli_peer_profile_show, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/detection-multiplier", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify, + .cli_show = bfd_cli_show_mult, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/desired-transmission-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify, + .cli_show = bfd_cli_show_tx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/required-receive-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify, + .cli_show = bfd_cli_show_rx, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/administrative-down", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify, + .cli_show = bfd_cli_show_shutdown, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/passive-mode", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_passive_mode_modify, + .cli_show = bfd_cli_show_passive, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/bfd-name", + .cbs = { + .modify = dummy_modify, + .destroy = dummy_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/bfd-mode", + .cbs = { + .modify = bfdd_bfd_sessions_bfd_mode_modify, + .destroy = bfdd_bfd_sessions_bfd_mode_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/segment-list", + .cbs = { + .modify = bfdd_bfd_sessions_segment_list_modify, + .destroy = bfdd_bfd_sessions_segment_list_destroy, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/minimum-ttl", + .cbs = { + .modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify, + .destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy, + .cli_show = bfd_cli_show_minimum_ttl, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/local-discriminator", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/local-state", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/local-diagnostic", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/local-multiplier", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/remote-discriminator", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/remote-state", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/remote-diagnostic", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/remote-multiplier", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/negotiated-transmission-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/negotiated-receive-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/detection-mode", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/last-down-time", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/last-up-time", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/session-down-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/session-up-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/control-packet-input-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/control-packet-output-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/negotiated-echo-transmission-interval", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/echo-packet-input-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/stats/echo-packet-output-count", + .cbs = { + .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem, + } + }, { .xpath = NULL, }, diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index b5b00b57e4b0..4f624c4fd971 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -112,6 +112,29 @@ bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem( struct nb_cb_get_elem_args *args); int bfdd_bfd_sessions_multi_hop_create(struct nb_cb_create_args *args); int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_create(struct nb_cb_create_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_mode_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_sessions_srte_sbfd_source_ipv6_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_srte_sbfd_source_ipv6_destroy(struct nb_cb_destroy_args *args); +int bfdd_bfd_sessions_srte_sbfd_init_remote_discr_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_srte_sbfd_init_remote_discr_destroy(struct nb_cb_destroy_args *args); + +int bfdd_bfd_sessions_srte_sbfd_init_create(struct nb_cb_create_args *args); +int bfdd_bfd_sessions_srte_sbfd_init_destroy(struct nb_cb_destroy_args *args); +const void * +bfdd_bfd_sessions_srte_sbfd_echo_get_next(struct nb_cb_get_next_args *args); +int bfdd_bfd_sessions_srte_sbfd_echo_get_keys(struct nb_cb_get_keys_args *args); +const void * +bfdd_bfd_sessions_srte_sbfd_echo_lookup_entry(struct nb_cb_lookup_entry_args *args); +const void * +bfdd_bfd_sessions_srte_sbfd_init_get_next(struct nb_cb_get_next_args *args); +int bfdd_bfd_sessions_srte_sbfd_init_get_keys(struct nb_cb_get_keys_args *args); +const void * +bfdd_bfd_sessions_srte_sbfd_init_lookup_entry(struct nb_cb_lookup_entry_args *args); + const void * bfdd_bfd_sessions_multi_hop_get_next(struct nb_cb_get_next_args *args); int bfdd_bfd_sessions_multi_hop_get_keys(struct nb_cb_get_keys_args *args); @@ -185,6 +208,10 @@ void bfd_cli_show_single_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_multi_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_sbfd_echo_peer(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +void bfd_cli_show_sbfd_init_peer(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); void bfd_cli_show_peer_end(struct vty *vty, const struct lyd_node *dnode); void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); @@ -210,4 +237,11 @@ void bfd_cli_show_passive(struct vty *vty, const struct lyd_node *dnode, void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +int bfdd_bfd_sessions_bfd_mode_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_bfd_mode_destroy(struct nb_cb_destroy_args *args); + +int bfdd_bfd_sessions_segment_list_modify(struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_segment_list_destroy(struct nb_cb_destroy_args *args); + +int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy(struct nb_cb_destroy_args *args); #endif /* _FRR_BFDD_NB_H_ */ diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 2f1ff0439786..3ad141c5a2dc 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -751,6 +751,48 @@ int bfdd_bfd_sessions_single_hop_passive_mode_modify( return NB_OK; } +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/bfd-mode + * /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/bfd-mode + */ +int bfdd_bfd_sessions_bfd_mode_modify( + struct nb_cb_modify_args *args) +{ + uint32_t bfd_mode; + bfd_mode = yang_dnode_get_uint32(args->dnode, NULL); + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + if ((bfd_mode != BFD_MODE_TYPE_BFD) && (bfd_mode != BFD_MODE_TYPE_SBFD_ECHO) && (bfd_mode != BFD_MODE_TYPE_SBFD_INIT)) + { + snprintf(args->errmsg, args->errmsg_len,"bfd mode is invalid."); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + return NB_OK; + + case NB_EV_APPLY: + break; + + case NB_EV_ABORT: + return NB_OK; + } + + bs = nb_running_get_entry(args->dnode, NULL, true); + bs->bfd_mode = bfd_mode; + bfd_session_apply(bs); + + return NB_OK; +} + +int bfdd_bfd_sessions_bfd_mode_destroy( + struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + /* * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode */ @@ -882,3 +924,122 @@ int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify( return NB_OK; } + +int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy( + struct nb_cb_destroy_args *args) +{ + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + return NB_OK; + + case NB_EV_APPLY: + break; + + case NB_EV_ABORT: + return NB_OK; + } + + bs = nb_running_get_entry(args->dnode, NULL, true); + bs->peer_profile.minimum_ttl = BFD_DEF_MHOP_TTL; + bfd_session_apply(bs); + + return NB_OK; +} + + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo + */ +int bfdd_bfd_sessions_srte_sbfd_echo_create(struct nb_cb_create_args *args) +{ + return bfd_session_create(args, false, BFD_MODE_TYPE_SBFD_ECHO); +} + +int bfdd_bfd_sessions_srte_sbfd_echo_destroy(struct nb_cb_destroy_args *args) +{ + return bfd_session_destroy(args->event, args->dnode, false, BFD_MODE_TYPE_SBFD_ECHO); +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/segment-list + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/segment-list + */ +int bfdd_bfd_sessions_segment_list_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_segment_list_destroy( + struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/dest-addr + */ +int bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_srte_sbfd_echo_dest_addr_destroy( + struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/echo-mode + */ +int bfdd_bfd_sessions_srte_sbfd_echo_mode_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo/source-ipv6 + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/source-ipv6 + */ +int bfdd_bfd_sessions_srte_sbfd_source_ipv6_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int bfdd_bfd_sessions_srte_sbfd_source_ipv6_destroy( + struct nb_cb_destroy_args *args) +{ + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init + */ +int bfdd_bfd_sessions_srte_sbfd_init_create(struct nb_cb_create_args *args) +{ + return bfd_session_create(args, false, BFD_MODE_TYPE_SBFD_INIT); +} + +int bfdd_bfd_sessions_srte_sbfd_init_destroy(struct nb_cb_destroy_args *args) +{ + return bfd_session_destroy(args->event, args->dnode, false, BFD_MODE_TYPE_SBFD_INIT); +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init/remote-discr + */ +int bfdd_bfd_sessions_srte_sbfd_init_remote_discr_modify(struct nb_cb_modify_args *args) +{ + return NB_OK; +} +int bfdd_bfd_sessions_srte_sbfd_init_remote_discr_destroy(struct nb_cb_destroy_args *args) +{ + return NB_OK; +} diff --git a/bfdd/bfdd_nb_state.c b/bfdd/bfdd_nb_state.c index 0523d9b266fe..3d3fc05c4e0d 100644 --- a/bfdd/bfdd_nb_state.c +++ b/bfdd/bfdd_nb_state.c @@ -20,7 +20,7 @@ const void * bfdd_bfd_sessions_single_hop_get_next(struct nb_cb_get_next_args *args) { - return bfd_session_next(args->list_entry, false); + return bfd_session_next(args->list_entry, false, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_single_hop_get_keys(struct nb_cb_get_keys_args *args) @@ -323,7 +323,7 @@ bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem( const void * bfdd_bfd_sessions_multi_hop_get_next(struct nb_cb_get_next_args *args) { - return bfd_session_next(args->list_entry, true); + return bfd_session_next(args->list_entry, true, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_multi_hop_get_keys(struct nb_cb_get_keys_args *args) @@ -358,3 +358,87 @@ bfdd_bfd_sessions_multi_hop_lookup_entry(struct nb_cb_lookup_entry_args *args) return bfd_key_lookup(bk); } + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo + */ +const void * +bfdd_bfd_sessions_srte_sbfd_echo_get_next(struct nb_cb_get_next_args *args) +{ + return bfd_session_next(args->list_entry, true, BFD_MODE_TYPE_SBFD_ECHO); +} + +int bfdd_bfd_sessions_srte_sbfd_echo_get_keys(struct nb_cb_get_keys_args *args) +{ + const struct bfd_session *bs = args->list_entry; + char srcbuf[INET6_ADDRSTRLEN]; + + inet_ntop(bs->key.family, &bs->key.local, srcbuf, sizeof(srcbuf)); + + args->keys->num = 3; + strlcpy(args->keys->key[0], srcbuf, sizeof(args->keys->key[0])); + strlcpy(args->keys->key[1], bs->key.bfdname, sizeof(args->keys->key[1])); + strlcpy(args->keys->key[2], bs->key.vrfname, sizeof(args->keys->key[2])); + + return NB_OK; +} + +const void * +bfdd_bfd_sessions_srte_sbfd_echo_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + const char *source_addr = args->keys->key[0]; + const char *bfdname = args->keys->key[1]; + const char *vrf = args->keys->key[2]; + struct sockaddr_any psa, lsa; + struct bfd_key bk; + + strtosa(source_addr, &lsa); + memset(&psa, 0, sizeof(psa)); + gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf, bfdname); + + return bfd_key_lookup(bk); +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init + */ +const void * +bfdd_bfd_sessions_srte_sbfd_init_get_next(struct nb_cb_get_next_args *args) +{ + return bfd_session_next(args->list_entry, true, BFD_MODE_TYPE_SBFD_INIT); +} + +int bfdd_bfd_sessions_srte_sbfd_init_get_keys(struct nb_cb_get_keys_args *args) +{ + const struct bfd_session *bs = args->list_entry; + char srcbuf[INET6_ADDRSTRLEN]; + char dstbuf[INET6_ADDRSTRLEN]; + + inet_ntop(bs->key.family, &bs->key.local, srcbuf, sizeof(srcbuf)); + inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf)); + + args->keys->num = 4; + strlcpy(args->keys->key[0], srcbuf, sizeof(args->keys->key[0])); + strlcpy(args->keys->key[1], dstbuf, sizeof(args->keys->key[1])); + strlcpy(args->keys->key[2], bs->key.bfdname, sizeof(args->keys->key[2])); + strlcpy(args->keys->key[3], bs->key.vrfname, sizeof(args->keys->key[3])); + + return NB_OK; +} + +const void * +bfdd_bfd_sessions_srte_sbfd_init_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + const char *source_addr = args->keys->key[0]; + const char *dest_addr = args->keys->key[1]; + const char *bfdname = args->keys->key[2]; + const char *vrf = args->keys->key[3]; + struct sockaddr_any psa, lsa; + struct bfd_key bk; + + strtosa(source_addr, &lsa); + strtosa(dest_addr, &psa); + gen_bfd_key(&bk, &psa, &lsa, true, NULL, vrf, bfdname); + + return bfd_key_lookup(bk); +} \ No newline at end of file From 7d063172f30fd47ef6553b20d9be37cf0d260aad Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 11:18:13 +0000 Subject: [PATCH 06/21] bfdd: refactor bfd_session_create bfd_session_create support both BFD and SBFD, add some validation check for existing bfd Xpath callbacks Signed-off-by: wumu.zsl --- bfdd/bfdd_nb_config.c | 295 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 254 insertions(+), 41 deletions(-) diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 3ad141c5a2dc..b41523fe895b 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -80,6 +80,27 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname, NULL); } +static void sbfd_session_get_key(bool mhop, const struct lyd_node *dnode, + struct bfd_key *bk) +{ + const char *ifname = NULL, *vrfname = NULL, *bfdname = NULL; + struct sockaddr_any psa, lsa; + + /* Required source parameter. */ + strtosa(yang_dnode_get_string(dnode, "source-addr"), &lsa); + + strtosa(yang_dnode_get_string(dnode, "dest-addr"), &psa); + + if (yang_dnode_exists(dnode, "bfd-name")) + bfdname = yang_dnode_get_string(dnode, "bfd-name"); + + if (yang_dnode_exists(dnode, "vrf")) + vrfname = yang_dnode_get_string(dnode, "vrf"); + + /* Generate the corresponding key. */ + gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname, bfdname); +} + struct session_iter { int count; bool wildcard; @@ -100,7 +121,7 @@ static int session_iter_cb(const struct lyd_node *dnode, void *arg) return YANG_ITER_CONTINUE; } -static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) +static int bfd_session_create(struct nb_cb_create_args *args, bool mhop, uint32_t bfd_mode) { const struct lyd_node *sess_dnode; struct session_iter iter; @@ -110,10 +131,23 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) const char *vrfname; struct bfd_key bk; struct prefix p; + const char * bfd_name = NULL; + uint8_t segnum = 1; + struct sockaddr_any slist, out_sip6; switch (args->event) { case NB_EV_VALIDATE: - yang_dnode_get_prefix(&p, args->dnode, "dest-addr"); + if ((bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) || (bfd_mode == BFD_MODE_TYPE_SBFD_INIT)) { + if(bfd_session_get_by_name(yang_dnode_get_string(args->dnode, "bfd-name"))) { + snprintf( + args->errmsg, args->errmsg_len, + "bfd name already exist."); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + + yang_dnode_get_prefix(&p, args->dnode, "./dest-addr"); if (mhop) { /* @@ -165,34 +199,132 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) break; case NB_EV_PREPARE: - bfd_session_get_key(mhop, args->dnode, &bk); - bs = bfd_key_lookup(bk); + if (bfd_mode == BFD_MODE_TYPE_BFD) + { + bfd_session_get_key(mhop, args->dnode, &bk); + bs = bfd_key_lookup(bk); + + /* This session was already configured by another daemon. */ + if (bs != NULL) { + /* Now it is configured also by CLI. */ + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + bs->refcount++; + + args->resource->ptr = bs; + break; + } + + bs = bfd_session_new(BFD_MODE_TYPE_BFD, 0); - /* This session was already configured by another daemon. */ - if (bs != NULL) { - /* Now it is configured also by CLI. */ + /* Fill the session key. */ + bfd_session_get_key(mhop, args->dnode, &bs->key); + /* Set configuration flags. */ + bs->refcount = 1; SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); - bs->refcount++; + if (mhop) + SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (bs->key.family == AF_INET6) + SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); args->resource->ptr = bs; break; } + else if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + sbfd_session_get_key(mhop, args->dnode, &bk); + bs = bfd_key_lookup(bk); + + /* This session was already configured by another daemon. */ + if (bs != NULL) { + /* Now it is configured also by CLI. */ + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + bs->refcount++; + + args->resource->ptr = bs; + break; + } - bs = bfd_session_new(); + //todo: set segnum according to segment-list + segnum = yang_dnode_exists(args->dnode, "segment-list")?1: 0; + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO && !yang_dnode_exists(args->dnode, "segment-list")){ + //currenty segment-list should not be null + snprintf( + args->errmsg, args->errmsg_len, + "segment-list should not be null"); + return NB_ERR_RESOURCE; + } - /* Fill the session key. */ - bfd_session_get_key(mhop, args->dnode, &bs->key); + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO && !yang_dnode_exists(args->dnode, "source-ipv6")){ + snprintf( + args->errmsg, args->errmsg_len, + "source_ipv6 should not be null"); + return NB_ERR_RESOURCE; + } - /* Set configuration flags. */ - bs->refcount = 1; - SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); - if (mhop) - SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); - if (bs->key.family == AF_INET6) - SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); + if (bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + if (!yang_dnode_exists(args->dnode, "remote-discr")){ + snprintf( + args->errmsg, args->errmsg_len, + "remote-discr should not be null"); + return NB_ERR_RESOURCE; + } + } - args->resource->ptr = bs; - break; + bfd_name = yang_dnode_get_string(args->dnode, "bfd-name"); + + bs = bfd_session_new(bfd_mode, segnum); + if (bs == NULL) { + snprintf( + args->errmsg, args->errmsg_len, + "session-new: allocation failed"); + return NB_ERR_RESOURCE; + } + /* Fill the session key. */ + sbfd_session_get_key(mhop, args->dnode, &bs->key); + strlcpy(bs->bfd_name, bfd_name, BFD_NAME_SIZE); + + if(segnum) + { + strtosa(yang_dnode_get_string(args->dnode, "./segment-list"), &slist); + memcpy(&bs->seg_list[0], &slist.sa_sin6.sin6_addr, sizeof(struct in6_addr)); + + strtosa(yang_dnode_get_string(args->dnode, "./source-ipv6"), &out_sip6); + memcpy(&bs->out_sip6, &out_sip6.sa_sin6.sin6_addr, sizeof(struct in6_addr)); + } + + if (bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + bs->discrs.remote_discr = yang_dnode_get_uint32(args->dnode, "./remote-discr"); + } + + /* Set configuration flags. */ + bs->refcount = 1; + SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); + // if (mhop) + // SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (bs->key.family == AF_INET6) + SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); + + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + memcpy(&bs->key.peer, &bs->key.local, sizeof(struct in6_addr)); + } + else + { + bs->xmt_TO = bs->timers.desired_min_tx; + bs->detect_TO = bs->detect_mult * bs->xmt_TO; + } + + args->resource->ptr = bs; + break; + + } + else + { + snprintf(args->errmsg, args->errmsg_len,"bfd mode must be bfd or sbfd."); + return NB_ERR_VALIDATION; + } case NB_EV_APPLY: bs = args->resource->ptr; @@ -215,14 +347,19 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) } static int bfd_session_destroy(enum nb_event event, - const struct lyd_node *dnode, bool mhop) + const struct lyd_node *dnode, bool mhop, uint32_t bfd_mode) { struct bfd_session *bs; struct bfd_key bk; switch (event) { case NB_EV_VALIDATE: - bfd_session_get_key(mhop, dnode, &bk); + if(bfd_mode == BFD_MODE_TYPE_BFD){ + bfd_session_get_key(mhop, dnode, &bk); + }else{ + sbfd_session_get_key(mhop, dnode, &bk); + } + if (bfd_key_lookup(bk) == NULL) return NB_ERR_INCONSISTENCY; break; @@ -243,6 +380,13 @@ static int bfd_session_destroy(enum nb_event event, if (bs->refcount > 0) break; + if (bglobal.debug_peer_event) + zlog_info("bfd_session_destroy: %s", bs_to_string(bs)); + + if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd_mode == BFD_MODE_TYPE_SBFD_INIT){ + ptm_bfd_notify(bs, PTM_BFD_DEL); + } + bfd_session_free(bs); break; @@ -356,9 +500,13 @@ int bfdd_bfd_profile_desired_transmission_interval_modify( struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint32_t min_tx; switch (args->event) { case NB_EV_VALIDATE: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_tx < 10000 || min_tx > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -366,8 +514,12 @@ int bfdd_bfd_profile_desired_transmission_interval_modify( break; case NB_EV_APPLY: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->min_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (bp->min_tx == min_tx) + return NB_OK; + + bp->min_tx = min_tx; bfd_profile_update(bp); break; @@ -386,9 +538,11 @@ int bfdd_bfd_profile_required_receive_interval_modify( struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint32_t min_rx; switch (args->event) { case NB_EV_VALIDATE: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); break; case NB_EV_PREPARE: @@ -396,8 +550,12 @@ int bfdd_bfd_profile_required_receive_interval_modify( break; case NB_EV_APPLY: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->min_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (bp->min_rx == min_rx) + return NB_OK; + + bp->min_rx = min_rx; bfd_profile_update(bp); break; @@ -415,12 +573,17 @@ int bfdd_bfd_profile_required_receive_interval_modify( int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args) { struct bfd_profile *bp; + bool shutdown; if (args->event != NB_EV_APPLY) return NB_OK; + shutdown = yang_dnode_get_bool(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->admin_shutdown = yang_dnode_get_bool(args->dnode, NULL); + if (bp->admin_shutdown == shutdown) + return NB_OK; + + bp->admin_shutdown = shutdown; bfd_profile_update(bp); return NB_OK; @@ -432,12 +595,17 @@ int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args) int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args) { struct bfd_profile *bp; + bool passive; if (args->event != NB_EV_APPLY) return NB_OK; + passive = yang_dnode_get_bool(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->passive = yang_dnode_get_bool(args->dnode, NULL); + if (bp->passive == passive) + return NB_OK; + + bp->passive = passive; bfd_profile_update(bp); return NB_OK; @@ -449,12 +617,17 @@ int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args) int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint8_t minimum_ttl; if (args->event != NB_EV_APPLY) return NB_OK; + minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL); + if (bp->minimum_ttl == minimum_ttl) + return NB_OK; + + bp->minimum_ttl = minimum_ttl; bfd_profile_update(bp); return NB_OK; @@ -489,9 +662,13 @@ int bfdd_bfd_profile_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint32_t min_tx; switch (args->event) { case NB_EV_VALIDATE: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_tx < 10000 || min_tx > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -499,8 +676,12 @@ int bfdd_bfd_profile_desired_echo_transmission_interval_modify( break; case NB_EV_APPLY: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->min_echo_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (bp->min_echo_tx == min_tx) + return NB_OK; + + bp->min_echo_tx = min_tx; bfd_profile_update(bp); break; @@ -519,9 +700,15 @@ int bfdd_bfd_profile_required_echo_receive_interval_modify( struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint32_t min_rx; switch (args->event) { case NB_EV_VALIDATE: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_rx == 0) + return NB_OK; + if (min_rx < 10000 || min_rx > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -529,8 +716,12 @@ int bfdd_bfd_profile_required_echo_receive_interval_modify( break; case NB_EV_APPLY: + min_rx = yang_dnode_get_uint32(args->dnode, NULL); bp = nb_running_get_entry(args->dnode, NULL, true); - bp->min_echo_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (bp->min_echo_rx == min_rx) + return NB_OK; + + bp->min_echo_rx = min_rx; bfd_profile_update(bp); break; @@ -547,12 +738,12 @@ int bfdd_bfd_profile_required_echo_receive_interval_modify( */ int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args, false); + return bfd_session_create(args, false, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args) { - return bfd_session_destroy(args->event, args->dnode, false); + return bfd_session_destroy(args->event, args->dnode, false, BFD_MODE_TYPE_BFD); } /* @@ -637,10 +828,13 @@ int bfdd_bfd_sessions_single_hop_detection_multiplier_modify( int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify( struct nb_cb_modify_args *args) { + uint32_t tx_interval = yang_dnode_get_uint32(args->dnode, NULL); struct bfd_session *bs; switch (args->event) { case NB_EV_VALIDATE: + if (tx_interval < 10000 || tx_interval > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -649,8 +843,10 @@ int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); - bs->peer_profile.min_tx = - yang_dnode_get_uint32(args->dnode, NULL); + if (tx_interval == bs->timers.desired_min_tx) + return NB_OK; + + bs->peer_profile.min_tx = tx_interval; bfd_session_apply(bs); break; @@ -668,10 +864,13 @@ int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify( int bfdd_bfd_sessions_single_hop_required_receive_interval_modify( struct nb_cb_modify_args *args) { + uint32_t rx_interval = yang_dnode_get_uint32(args->dnode, NULL); struct bfd_session *bs; switch (args->event) { case NB_EV_VALIDATE: + if (rx_interval < 10000 || rx_interval > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -680,8 +879,10 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); - bs->peer_profile.min_rx = - yang_dnode_get_uint32(args->dnode, NULL); + if (rx_interval == bs->timers.required_min_rx) + return NB_OK; + + bs->peer_profile.min_rx = rx_interval; bfd_session_apply(bs); break; @@ -828,10 +1029,13 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify( int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args) { + uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL); struct bfd_session *bs; switch (args->event) { case NB_EV_VALIDATE: + if (echo_interval < 10000 || echo_interval > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -840,8 +1044,10 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); - bs->peer_profile.min_echo_tx = - yang_dnode_get_uint32(args->dnode, NULL); + if (echo_interval == bs->timers.desired_min_echo_tx) + return NB_OK; + + bs->peer_profile.min_echo_tx = echo_interval; bfd_session_apply(bs); break; @@ -860,10 +1066,15 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( struct nb_cb_modify_args *args) { + uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL); struct bfd_session *bs; switch (args->event) { case NB_EV_VALIDATE: + if (echo_interval == 0) + return NB_OK; + if (echo_interval < 10000 || echo_interval > 60000000) + return NB_ERR_VALIDATION; break; case NB_EV_PREPARE: @@ -872,8 +1083,10 @@ int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); - bs->peer_profile.min_echo_rx = - yang_dnode_get_uint32(args->dnode, NULL); + if (echo_interval == bs->timers.required_min_echo_rx) + return NB_OK; + + bs->peer_profile.min_echo_rx = echo_interval; bfd_session_apply(bs); break; @@ -890,12 +1103,12 @@ int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( */ int bfdd_bfd_sessions_multi_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args, true); + return bfd_session_create(args, true, BFD_MODE_TYPE_BFD); } int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args) { - return bfd_session_destroy(args->event, args->dnode, true); + return bfd_session_destroy(args->event, args->dnode, true, BFD_MODE_TYPE_BFD); } /* From f7e761ca5f9e23400de0bbfbe2a321a4ade8c3eb Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 11:21:03 +0000 Subject: [PATCH 07/21] bfdd: add sbfd cmds to bfdd cli Signed-off-by: wumu.zsl --- bfdd/bfdd_cli.c | 595 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 568 insertions(+), 27 deletions(-) diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 6527ec5f41a3..1a03ed45bda1 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -11,8 +11,11 @@ #include "lib/command.h" #include "lib/log.h" #include "lib/northbound_cli.h" +#include "lib/termtable.h" +#ifndef VTYSH_EXTRACT_PL #include "bfdd/bfdd_cli_clippy.c" +#endif /* VTYSH_EXTRACT_PL */ #include "bfd.h" #include "bfdd_nb.h" @@ -31,6 +34,14 @@ #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" + +#define IPV4_ADDRESS 4 +#define IPV6_ADDRESS 6 +#define INVALID_IP 0 /* * Prototypes. @@ -41,12 +52,31 @@ 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, "/srte-sbfd-echo") != NULL; +} + + static bool bfd_cli_is_profile(struct vty *vty) { return strstr(VTY_CURR_XPATH, "/bfd/profile") != NULL; } +static int determine_ip_version(const char *ip) +{ + struct in_addr inaddr4; + struct in6_addr inaddr6; + + if (inet_pton(AF_INET, ip, &inaddr4) == 1) + return IPV4_ADDRESS; + if (inet_pton(AF_INET6, ip, &inaddr6) == 1) + return IPV6_ADDRESS; + + return INVALID_IP; +} /* * Functions. */ @@ -215,45 +245,369 @@ 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 \ + local-address \ + source-ipv6 X:X::X:X [{vrf NAME}]", + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-echo mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + "Configure bfd session encap type\n" + "Apply Srv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + VRF_STR + VRF_NAME_STR) { - const char *vrf = yang_dnode_get_string(dnode, "vrf"); + int ret, slen; + char value[32]; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32],xpath_bfdmode[XPATH_MAXLEN + 32]; + + if (!bfdname) { + vty_out(vty,"%% ERROR: bfd name is required\n"); + return CMD_WARNING_CONFIG_FAILED; + } - vty_out(vty, " peer %s", - yang_dnode_get_string(dnode, "dest-addr")); + 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/srte-sbfd-echo[source-addr='%s'][bfd-name='%s']", + local_address_str, + bfdname); + + if (vrf) + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", + VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (strcmp(encap_type, "SRv6") == 0) + { + snprintf(xpath_sl, sizeof(xpath_sl), "%s/segment-list", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, encap_data_str); + } + else + { + vty_out(vty,"%% ERROR: encap_type is invalid\n"); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(xpath_sl, sizeof(xpath_sl), "%s/source-ipv6", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, 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); + + snprintf(xpath_bfdmode, sizeof(xpath_bfdmode), "%s/bfd-mode", xpath); + snprintf(value, sizeof(value), "%d", BFD_MODE_TYPE_SBFD_ECHO); + nb_cli_enqueue_change(vty, xpath_bfdmode, NB_OP_MODIFY, value); + + /* 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 \ + local-address \ + source-ipv6 X:X::X:X [{vrf NAME}]", + 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 + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + "Configure bfd session encap type\n" + "Apply Srv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + VRF_STR + VRF_NAME_STR) +{ + int slen; + char xpath[XPATH_MAXLEN]; + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-echo[source-addr='%s'][bfd-name='%s']", + local_address_str, + bfdname); + + if (vrf) + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + slen += 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 \ + local-address \ + remote-discr (1-4294967295)$discr [{encap-type ENCAP_TYPE$encap_type encap-data X:X::X:X source-ipv6 X:X::X:X|vrf NAME}]", + PEER_STR + PEER_IPV4_STR + PEER_IPV6_STR + SESSION_MODE_STR + "Enable sbfd-echo mode\n" + SESSION_NAME_STR + SET_SESSION_NAME_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n" + "Configure bfd session encap type\n" + "Apply SRv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + VRF_STR + VRF_NAME_STR) +{ + int ret, slen, peer_ver, local_ver; + char value[32]; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32],xpath_bfdmode[XPATH_MAXLEN + 32],xpath_rd[XPATH_MAXLEN + 32]; + + if (!bfdname) { + vty_out(vty,"%% ERROR: bfd name is required\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + peer_ver = determine_ip_version(peer_str); + if (peer_ver == INVALID_IP) + { + vty_out(vty,"%% ERROR: peer is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (mhop) - vty_out(vty, " multihop"); + local_ver = determine_ip_version(local_address_str); + if (local_ver == INVALID_IP) + { + vty_out(vty,"%% ERROR: local_address is invalid address\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (yang_dnode_exists(dnode, "source-addr")) - vty_out(vty, " local-address %s", - yang_dnode_get_string(dnode, "source-addr")); + if (peer_ver != local_ver) + { + 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/srte-sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, + peer_str, + bfdname); - if (strcmp(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, " vrf %s", vrf); + if (vrf) + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", + VRF_DEFAULT_NAME); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (encap_type && strcmp(encap_type, "SRv6") == 0) + { + snprintf(xpath_sl, sizeof(xpath_sl), "%s/segment-list", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, encap_data_str); - if (!mhop) { - const char *ifname = - yang_dnode_get_string(dnode, "interface"); - if (strcmp(ifname, "*")) - vty_out(vty, " interface %s", ifname); + snprintf(xpath_sl, sizeof(xpath_sl), "%s/source-ipv6", xpath); + nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, source_ipv6_str); } - vty_out(vty, "\n"); + snprintf(xpath_bfdmode, sizeof(xpath_bfdmode), "%s/bfd-mode", xpath); + snprintf(value, sizeof(value), "%d", BFD_MODE_TYPE_SBFD_INIT); + nb_cli_enqueue_change(vty, xpath_bfdmode, NB_OP_MODIFY, value); + + 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 \ + local-address \ + remote-discr (0-4294967295)$discr [{encap-type ENCAP_TYPE$encap_type encap-data X:X::X:X source-ipv6 X:X::X:X|vrf NAME}]", + 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 + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + "Configure bfd session remote discriminator\n" + "Configure remote discriminator\n" + "Configure bfd session encap type\n" + "Apply Srv6 as encap type\n" + "Configure bfd session encap data\n" + "Set bfd session encap data\n" + "Configure bfd session source-ipv6 address\n" + "Configure source-ipv6 address\n" + VRF_STR + VRF_NAME_STR) +{ + int slen; + char xpath[XPATH_MAXLEN]; + + slen = snprintf(xpath, sizeof(xpath), + "/frr-bfdd:bfdd/bfd/sessions/srte-sbfd-init[source-addr='%s'][dest-addr='%s'][bfd-name='%s']", + local_address_str, + peer_str, + bfdname); + + if (vrf) + slen += snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf); + else + slen += 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"; + } +} +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"); + + 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) + { + if (yang_dnode_exists(dnode, "bfd-name")) + vty_out(vty, " bfd-name %s", yang_dnode_get_string(dnode, "bfd-name")); + + if (yang_dnode_exists(dnode, "bfd-mode")) + vty_out(vty, " bfd-mode %s", _bfd_cli_bfd_mode_type_to_string(yang_dnode_get_uint32(dnode, "bfd-mode"))); + + if (yang_dnode_exists(dnode, "source-addr")) + vty_out(vty, " local-address %s", + yang_dnode_get_string(dnode, "source-addr")); + + if (yang_dnode_exists(dnode, "segment-list")) + vty_out(vty, " segment-list %s", + yang_dnode_get_string(dnode, "segment-list")); + + if (yang_dnode_exists(dnode, "source-ipv6")) + vty_out(vty, " source-ipv6 %s", + yang_dnode_get_string(dnode, "source-ipv6")); + + 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 (strcmp(vrf, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrf); + + 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 +800,8 @@ 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 +824,8 @@ 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 +855,12 @@ 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 +1012,182 @@ 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 refector 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; + uint32_t i; + + if (end_discr == 0 ) + { + if (start_discr == 0) + { + vty_out(vty, "input refector discriminator is illegal.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + sr = sbfd_discr_lookup(start_discr); + if (!sr) + { + vty_out(vty, "input refector 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 refector 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 refector 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 +1225,16 @@ 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_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); From 074710b58303aaae2d391a01817f9440b661c964 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 11:24:55 +0000 Subject: [PATCH 08/21] bfdd: add show sbfd commands Signed-off-by: wumu.zsl --- bfdd/bfdd_vty.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 372 insertions(+), 11 deletions(-) diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 26554e1496b8..4a5e2ba34e01 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -58,6 +58,27 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, const char *label, const char *peer_str, const char *local_str, const char *ifname, const char *vrfname); +static void _display_bfd_by_bfdname_json_iter(struct hash_bucket *hb, void *arg); +static void _display_bfd_by_bfdname_iter(struct hash_bucket *hb, void *arg); +static void _display_bfd_by_bfdname(struct vty *vty, const char *vrfname, const char *bfdname, bool use_json); +static void _display_bfd_counters_by_bfdname_iter(struct hash_bucket *hb, void *arg); +static void _display_bfd_counters_json_by_bfdname_iter(struct hash_bucket *hb, void *arg); +static void _display_bfd_counters_by_bfdname(struct vty *vty, const char *vrfname, const char *bfdname, bool use_json); +static void _clear_bfd_counters_by_bfdname(const char *vrfname, const char *bfdname); +static void _clear_peer_counter(struct bfd_session *bs); + +static const char *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"; + } +} /* @@ -74,12 +95,38 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) vty_out(vty, " multihop"); + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + vty_out(vty, " bfd-mode %s", bfd_mode_type_to_string(bs->bfd_mode)); + + if (bs->bfd_name[0]) + { + vty_out(vty, " bfd-name %s", bs->bfd_name); + } + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) vty_out(vty, " local-address %s", inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf))); - if (bs->key.vrfname[0]) + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + vty_out(vty, " remote-discr %u", bs->discrs.remote_discr); + } + if (bs->bfd_name[0] && bs->segnum) + { + vty_out(vty, " encap-type %s", "SRv6"); + vty_out(vty, " encap-data %s", + inet_ntop(AF_INET6, &bs->seg_list[0], addr_buf, + sizeof(addr_buf))); + vty_out(vty, " source-ipv6 %s", + inet_ntop(AF_INET6, &bs->out_sip6, addr_buf, + sizeof(addr_buf))); + } + } + + if (bs->key.vrfname[0]) vty_out(vty, " vrf %s", bs->key.vrfname); if (bs->key.ifname[0]) vty_out(vty, " interface %s", bs->key.ifname); @@ -135,10 +182,21 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag)); vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag)); + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + vty_out(vty, "\t\tPeer Type: sbfd initiator\n"); + } + else if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + vty_out(vty, "\t\tPeer Type: echo\n"); + } + else + { vty_out(vty, "\t\tPeer Type: %s\n", CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) ? "configured" : "dynamic"); _display_rtt(&min, &avg, &max, bs); vty_out(vty, "\t\tRTT min/avg/max: %u/%u/%u usec\n", min, avg, max); + } vty_out(vty, "\t\tLocal timers:\n"); vty_out(vty, "\t\t\tDetect-multiplier: %u\n", @@ -152,12 +210,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) bs->timers.required_min_echo_rx / 1000); else vty_out(vty, "\t\t\tEcho receive interval: disabled\n"); - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO) + || bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) vty_out(vty, "\t\t\tEcho transmission interval: %ums\n", - bs->timers.desired_min_echo_tx / 1000); + bs->timers.desired_min_echo_tx / 1000); else vty_out(vty, "\t\t\tEcho transmission interval: disabled\n"); + + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT + || bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + vty_out(vty, "\t\tRemote timers:\n"); + vty_out(vty, "\t\t\tDetect-multiplier: -\n"); + vty_out(vty, "\t\t\tReceive interval: -\n"); + vty_out(vty, "\t\t\tTransmission interval: -\n"); + vty_out(vty, "\t\t\tEcho receive interval: -\n"); + } + else + { vty_out(vty, "\t\tRemote timers:\n"); vty_out(vty, "\t\t\tDetect-multiplier: %u\n", bs->remote_detect_mult); @@ -170,6 +241,7 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) bs->remote_timers.required_min_echo / 1000); else vty_out(vty, "\t\t\tEcho receive interval: disabled\n"); + } vty_out(vty, "\n"); } @@ -216,6 +288,9 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) json_object_int_add(jo, "minimum-ttl", bs->mh_ttl); + if (bs->bfd_mode != BFD_MODE_TYPE_BFD) + json_object_string_add(jo, "bfd-name", bs->bfd_name); + switch (bs->ses_state) { case PTM_BFD_ADM_DOWN: json_object_string_add(jo, "status", "shutdown"); @@ -253,7 +328,17 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) bs->timers.desired_min_tx / 1000); json_object_int_add(jo, "echo-receive-interval", bs->timers.required_min_echo_rx / 1000); - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT + || bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + json_object_int_add(jo, "configured-echo-transmit-interval", + bs->timers.desired_min_echo_tx / 1000); + json_object_int_add(jo, "current-echo-transmit-interval", + bs->echo_xmt_TO / 1000); + json_object_int_add(jo, "current-detect-echo-receive-interval", + bs->echo_detect_TO / 1000); + } + else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) json_object_int_add(jo, "echo-transmit-interval", bs->timers.desired_min_echo_tx / 1000); else @@ -289,6 +374,7 @@ struct bfd_vrf_tuple { const char *vrfname; struct vty *vty; struct json_object *jo; + const char *bfdname; }; static void _display_peer_iter(struct hash_bucket *hb, void *arg) @@ -309,6 +395,31 @@ static void _display_peer_iter(struct hash_bucket *hb, void *arg) _display_peer(vty, bs); } +static void _display_bfd_by_bfdname_iter(struct hash_bucket *hb, void *arg) +{ + struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg; + struct vty *vty; + struct bfd_session *bs = hb->data; + + if (!bvt) + return; + vty = bvt->vty; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + if (bvt->bfdname) { + if ((!bs->key.bfdname[0] || !strmatch(bs->key.bfdname, bvt->bfdname)) && + (!bs->bfd_name[0] || !strmatch(bs->bfd_name, bvt->bfdname))) + return; + } + + _display_peer(vty, bs); +} + static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) { struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg; @@ -334,6 +445,58 @@ static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) json_object_array_add(jo, jon); } +static void _display_bfd_by_bfdname_json_iter(struct hash_bucket *hb, void *arg) +{ + struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg; + struct json_object *jo, *jon = NULL; + struct bfd_session *bs = hb->data; + + if (!bvt) + return; + jo = bvt->jo; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + if (bvt->bfdname) { + if ((!bs->key.bfdname[0] || !strmatch(bs->key.bfdname, bvt->bfdname)) && + (!bs->bfd_name[0] || !strmatch(bs->bfd_name, bvt->bfdname))) + return; + } + + jon = __display_peer_json(bs); + if (jon == NULL) { + zlog_warn("%s: not enough memory", __func__); + return; + } + + json_object_array_add(jo, jon); +} +static void _display_bfd_by_bfdname(struct vty *vty, const char *vrfname, const char *bfdname, bool use_json) +{ + struct json_object *jo; + struct bfd_vrf_tuple bvt = {0}; + + bvt.vrfname = vrfname; + bvt.bfdname = bfdname; + + if (!use_json) { + bvt.vty = vty; + vty_out(vty, "BFD Peers:\n"); + bfd_id_iterate(_display_bfd_by_bfdname_iter, &bvt); + return; + } + + jo = json_object_new_array(); + bvt.jo = jo; + bfd_id_iterate(_display_bfd_by_bfdname_json_iter, &bvt); + + vty_json(vty, jo); +} + static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json) { struct json_object *jo; @@ -378,6 +541,8 @@ static void _display_peer_counter(struct vty *vty, struct bfd_session *bs) bs->stats.session_down); vty_out(vty, "\t\tZebra notifications: %" PRIu64 "\n", bs->stats.znotification); + vty_out(vty, "\t\tTx fail packet: %" PRIu64 "\n", + bs->stats.tx_fail_pkt); vty_out(vty, "\n"); } @@ -397,6 +562,7 @@ static struct json_object *__display_peer_counters_json(struct bfd_session *bs) json_object_int_add(jo, "session-up", bs->stats.session_up); json_object_int_add(jo, "session-down", bs->stats.session_down); json_object_int_add(jo, "zebra-notifications", bs->stats.znotification); + json_object_int_add(jo, "tx-fail-packet", bs->stats.tx_fail_pkt); return jo; } @@ -472,6 +638,115 @@ static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json vty_json(vty, jo); } +static void _display_bfd_counters_by_bfdname_iter(struct hash_bucket *hb, void *arg) +{ + struct bfd_vrf_tuple *bvt = arg; + struct vty *vty; + struct bfd_session *bs = hb->data; + + if (!bvt) + return; + vty = bvt->vty; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + if (bvt->bfdname){ + if (!bs->key.bfdname[0] || + !strmatch(bs->key.bfdname, bvt->bfdname)) + return; + } + + _display_peer_counter(vty, bs); +} +static void _display_bfd_counters_json_by_bfdname_iter(struct hash_bucket *hb, void *arg) +{ + struct json_object *jo, *jon = NULL; + struct bfd_session *bs = hb->data; + struct bfd_vrf_tuple *bvt = arg; + + if (!bvt) + return; + jo = bvt->jo; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + if (bvt->bfdname){ + if (!bs->key.bfdname[0] || + !strmatch(bs->key.bfdname, bvt->bfdname)) + return; + } + + jon = __display_peer_counters_json(bs); + if (jon == NULL) { + zlog_warn("%s: not enough memory", __func__); + return; + } + + json_object_array_add(jo, jon); +} +static void _display_bfd_counters_by_bfdname(struct vty *vty, const char *vrfname, const char *bfdname, bool use_json) +{ + struct json_object *jo; + struct bfd_vrf_tuple bvt = {0}; + + bvt.vrfname = vrfname; + bvt.bfdname = bfdname; + + if (!use_json) { + bvt.vty = vty; + vty_out(vty, "BFD Peers:\n"); + bfd_id_iterate(_display_bfd_counters_by_bfdname_iter, &bvt); + return; + } + + jo = json_object_new_array(); + bvt.jo = jo; + bfd_id_iterate(_display_bfd_counters_json_by_bfdname_iter, &bvt); + + vty_json(vty, jo); +} +static void _clear_bfd_counters_by_bfdname_iter(struct hash_bucket *hb, void *arg) +{ + struct bfd_vrf_tuple *bvt = arg; + struct bfd_session *bs = hb->data; + + if (!bvt) + return; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + if (bvt->bfdname){ + if (!bs->key.bfdname[0] || + !strmatch(bs->key.bfdname, bvt->bfdname)) + return; + } + + _clear_peer_counter(bs); +} + +static void _clear_bfd_counters_by_bfdname(const char *vrfname, const char *bfdname) +{ + struct bfd_vrf_tuple bvt = {0}; + + bvt.vrfname = vrfname; + bvt.bfdname = bfdname; + + bfd_id_iterate(_clear_bfd_counters_by_bfdname_iter, &bvt); + return; +} + static void _clear_peer_counter(struct bfd_session *bs) { /* Clear only pkt stats, intention is not to loose system @@ -486,12 +761,21 @@ static void _display_peer_brief(struct vty *vty, struct bfd_session *bs) { char addr_buf[INET6_ADDRSTRLEN]; - vty_out(vty, "%-10u", bs->discrs.my_discr); - inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf)); - vty_out(vty, " %-40s", addr_buf); - inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); - vty_out(vty, " %-40s", addr_buf); - vty_out(vty, "%-15s\n", state_list[bs->ses_state].str); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + vty_out(vty, "%-10u", bs->discrs.my_discr); + inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + vty_out(vty, "%-15s\n", state_list[bs->ses_state].str); + } else { + vty_out(vty, "%-10u", bs->discrs.my_discr); + vty_out(vty, " %-40s", satostr(&bs->local_address)); + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + + vty_out(vty, "%-15s\n", state_list[bs->ses_state].str); + } } static void _display_peer_brief_iter(struct hash_bucket *hb, void *arg) @@ -558,6 +842,8 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, struct bfd_peer_cfg bpc; struct sockaddr_any psa, lsa, *lsap; char errormsg[128]; + struct vrf *vrf = NULL; + char *tmpName = NULL; if (peer_str) { strtosa(peer_str, &psa); @@ -570,7 +856,17 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, idx = 0; mhop = argv_find(argv, argc, "multihop", &idx); - if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname, + tmpName = (char *)vrfname; + if (vrfname) { + vrf = vrf_lookup_by_name(vrfname); + if (vrf == NULL) { + vty_out(vty, "%% Vrf is not exist: %s\n", vrfname); + return NULL; + } + tmpName = vrf->name; + } + + if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, tmpName, errormsg, sizeof(errormsg)) != 0) { vty_out(vty, "%% Invalid peer configuration: %s\n", @@ -631,6 +927,50 @@ void _display_rtt(uint32_t *min, uint32_t *avg, uint32_t *max, /* * Show commands. */ +DEFPY(bfd_show_by_bfdname, bfd_show_by_bfdname_cmd, + "show bfd [vrf NAME$vrf_name] bfd-name BFDNAME$bfdname [json]", + SHOW_STR + "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR + "Specify bfd session name\n" + "bfd session name\n" + JSON_STR) +{ + + _display_bfd_by_bfdname(vty, vrf_name, bfdname, use_json(argc, argv)); + + return CMD_SUCCESS; +} + +DEFPY(bfd_show_counters_by_bfdname, bfd_show_counters_by_bfdname_cmd, + "show bfd [vrf NAME$vrf_name] bfd-name BFDNAME$bfdname counters [json]", + SHOW_STR + "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR + "Specify bfd session name\n" + "bfd session name\n" + "Show BFD peer counters information\n" + JSON_STR) +{ + _display_bfd_counters_by_bfdname(vty, vrf_name, bfdname, use_json(argc, argv)); + + return CMD_SUCCESS; +} + +DEFPY(bfd_clear_counters_by_bfdname, bfd_clear_counters_by_bfdname_cmd, + "clear bfd [vrf NAME$vrfname] bfd-name BFDNAME$bfdname counters", + CLEAR_STR + "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR + "Specify bfd session name\n" + "bfd session name\n" + "clear BFD peer counters information\n") +{ + _clear_bfd_counters_by_bfdname(vrfname, bfdname); + + return CMD_SUCCESS; +} + DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf NAME] peers [json]", SHOW_STR "Bidirection Forwarding Detection\n" @@ -971,6 +1311,21 @@ struct cmd_node bfd_peer_node = { .prompt = "%s(config-bfd-peer)# ", }; +static void _sbfd_reflector_write_config(struct hash_bucket *hb, void *arg) +{ + struct sbfd_reflector *sr = hb->data; + char buf[INET6_ADDRSTRLEN]; + struct vty *vty; + vty = (struct vty *) arg; + inet_ntop(AF_INET6, &sr->local, buf, sizeof(buf)); + vty_out(vty, " sbfd reflector source-address %s discriminator %u\n", buf, sr->discr); +} + +static void sbfd_reflector_write_config(struct vty *vty) +{ + sbfd_discr_iterate(_sbfd_reflector_write_config, vty); +} + static int bfdd_write_config(struct vty *vty) { struct lyd_node *dnode; @@ -1002,6 +1357,9 @@ static int bfdd_write_config(struct vty *vty) written = 1; } + /*sbfd config*/ + sbfd_reflector_write_config(vty); + return written; } @@ -1011,6 +1369,9 @@ void bfdd_vty_init(void) install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd); install_element(ENABLE_NODE, &bfd_clear_peer_counters_cmd); install_element(ENABLE_NODE, &bfd_show_peers_cmd); + install_element(ENABLE_NODE, &bfd_show_by_bfdname_cmd); + install_element(ENABLE_NODE, &bfd_show_counters_by_bfdname_cmd); + install_element(ENABLE_NODE, &bfd_clear_counters_by_bfdname_cmd); install_element(ENABLE_NODE, &bfd_show_peer_cmd); install_element(ENABLE_NODE, &bfd_show_peers_brief_cmd); install_element(ENABLE_NODE, &show_bfd_distributed_cmd); From 2bda257d9a1c3933743b7fc6cbea60d227af8727 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 11:36:31 +0000 Subject: [PATCH 09/21] bfdd: implement functions for sending sbfd pkts with SRv6 header Two types of sbfd packets are supported: initiator packet and echo packet Signed-off-by: wumu.zsl --- bfdd/bfd.h | 6 + bfdd/bfd_packet.c | 862 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 868 insertions(+) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 9994fa7427e9..e9efe94a7f94 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -526,6 +526,7 @@ int bp_set_ttl(int sd, uint8_t value); int bp_set_tosv6(int sd, uint8_t value); int bp_set_tos(int sd, uint8_t value); int bp_bind_dev(int sd, const char *dev); +void bp_set_prio(int sd, int value); int bp_udp_shop(const struct vrf *vrf); int bp_udp_mhop(const struct vrf *vrf); @@ -535,10 +536,15 @@ int bp_peer_socket(const struct bfd_session *bs); int bp_peer_socketv6(const struct bfd_session *bs); int bp_echo_socket(const struct vrf *vrf); int bp_echov6_socket(const struct vrf *vrf); +int bp_peer_srh_socketv6(struct bfd_session *bs); +int bp_sbfd_socket(const struct vrf *vrf); +int bp_initv6_socket(const struct vrf *vrf); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); void ptm_bfd_echo_fp_snd(struct bfd_session *bfd); +void ptm_sbfd_echo_snd(struct bfd_session *bfd); +void ptm_sbfd_initiator_snd(struct bfd_session *bfd, int fbit); void bfd_recv_cb(struct event *t); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index f9397fa128db..80ed54777594 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -20,16 +20,21 @@ #ifdef BFD_LINUX #include +#include #endif /* BFD_LINUX */ #include #include +#include +#include #include "lib/sockopt.h" #include "lib/checksum.h" #include "lib/network.h" #include "bfd.h" +#define BUF_SIZ 1024 +#define SOCK_OPT_PRIO_HIGH 6 /* * Prototypes @@ -49,6 +54,18 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, struct sockaddr *to, socklen_t tolen); int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, uint8_t *ttl, uint32_t *my_discr, uint64_t *my_rtt); + +static int ptm_bfd_reflector_process_init_packet(struct bfd_vrf_global *bvrf, int s); +int _ptm_sbfd_init_send(struct bfd_session *bs, const void *data, size_t datalen); +int _ptm_sbfd_echo_send(struct bfd_session *bfd, const void *data, size_t datalen); +int bp_raw_sbfd_send(int sd, uint8_t *data, size_t datalen, struct in6_addr* sip , struct in6_addr* dip, + uint16_t src_port, uint16_t dst_port, + uint8_t seg_num, struct in6_addr* segment_list); +int bp_raw_sbfd_red_send(int sd, uint8_t *data, size_t datalen, + uint16_t family, struct in6_addr* out_sip, struct in6_addr* sip , struct in6_addr* dip, + uint16_t src_port, uint16_t dst_port, + uint8_t seg_num, struct in6_addr* segment_list); + #ifdef BFD_LINUX ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, ifindex_t *ifindex, @@ -1352,6 +1369,15 @@ static void bp_bind_ip(int sd, uint16_t port) zlog_fatal("bind-ip: bind: %s", strerror(errno)); } +void bp_set_prio(int sd, int value) +{ + int priority = value; + + if (setsockopt(sd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) { + zlog_warn("set_prio: setsockopt(SO_PRIORITY, %d): %s", value, strerror(errno)); + } +} + int bp_udp_shop(const struct vrf *vrf) { int sd; @@ -1421,6 +1447,8 @@ int bp_peer_socket(const struct bfd_session *bs) return -1; } + bp_set_prio(sd, SOCK_OPT_PRIO_HIGH); + /* Find an available source port in the proper range */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; @@ -1428,6 +1456,8 @@ int bp_peer_socket(const struct bfd_session *bs) sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr)); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) + sin.sin_addr.s_addr = INADDR_ANY; pcount = 0; do { @@ -1487,6 +1517,8 @@ int bp_peer_socketv6(const struct bfd_session *bs) return -1; } + bp_set_prio(sd, SOCK_OPT_PRIO_HIGH); + /* Find an available source port in the proper range */ memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; @@ -1699,6 +1731,7 @@ int bp_echo_socket(const struct vrf *vrf) bp_set_ipopts(s); bp_bind_ip(s, BFD_DEF_ECHO_PORT); + bp_set_prio(s, SOCK_OPT_PRIO_HIGH); return s; } @@ -1723,6 +1756,7 @@ int bp_echov6_socket(const struct vrf *vrf) bp_set_ipv6opts(s); bp_bind_ipv6(s, BFD_DEF_ECHO_PORT); + bp_set_prio(s, SOCK_OPT_PRIO_HIGH); return s; } @@ -1768,3 +1802,831 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd, } } #endif + +int _ptm_sbfd_init_send(struct bfd_session *bfd, const void *data, size_t datalen) +{ + int sd = -1; + struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd); + + int seg_num; + struct in6_addr* segment_list = NULL; + struct in6_addr peer; + struct in6_addr local; + + if (!bvrf) + return -1; + + seg_num = bfd->segnum; + if (seg_num > 0) + segment_list = bfd->seg_list; + + sd = bfd->sock; + + local = bfd->key.local; + peer = bfd->key.peer; + + if (bp_raw_sbfd_red_send(sd, (uint8_t *)data, datalen, bfd->key.family, &bfd->out_sip6, &local, &peer, + BFD_DEFDESTPORT, BFD_DEF_SBFD_DEST_PORT, seg_num, segment_list) < 0) + { + if(bfd->stats.tx_fail_pkt <= 1){ + char dst[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, seg_num > 0?segment_list: (&bfd->key.peer), dst, sizeof(dst)); + zlog_err("sbfd initiator send failed, dst:%s, errno:%s", dst, safe_strerror(errno)); + } + + bfd->stats.tx_fail_pkt++; + return -1; + } + + if(bfd->stats.tx_fail_pkt > 0){ + char dst[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, seg_num > 0?segment_list: (&bfd->key.peer), dst, sizeof(dst)); + zlog_warn("sbfd initiator send success, dst:%s, previous tx_fail_pkt:%d", dst, (int)bfd->stats.tx_fail_pkt); + } + bfd->stats.tx_fail_pkt = 0; + + bfd->stats.tx_ctrl_pkt++; + return 0; +} + +int _ptm_sbfd_echo_send(struct bfd_session *bfd, const void *data, size_t datalen) +{ + int sd = -1; + struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd); + + int seg_num; + struct in6_addr* segment_list = NULL; + struct in6_addr peer; + struct in6_addr local; + + if (!bvrf) + return -1; + + seg_num = bfd->segnum; + if (seg_num > 0) + segment_list = bfd->seg_list; + + sd = bfd->sock; + + local = bfd->key.local; + peer = bfd->key.peer; + if (bp_raw_sbfd_red_send(sd, (uint8_t *)data, datalen, bfd->key.family, &bfd->out_sip6, &local , &peer, + BFD_DEF_ECHO_PORT, BFD_DEF_ECHO_PORT, seg_num, segment_list) < 0) + { + if(bfd->stats.tx_fail_pkt <= 1){ + char dst[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, seg_num > 0?segment_list: (&bfd->key.peer), dst, sizeof(dst)); + zlog_err("sbfd echo send failed, bfd_name:%s, dst:%s, errno:%s", bfd->bfd_name, dst, safe_strerror(errno)); + } + + bfd->stats.tx_fail_pkt++; + return -1; + } + + if(bfd->stats.tx_fail_pkt > 0){ + char dst[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, seg_num > 0?segment_list: (&bfd->key.peer), dst, sizeof(dst)); + zlog_warn("sbfd echo send success, bfd_name:%s, dst:%s, previous tx_fail_pkt:%d", bfd->bfd_name, dst, (int)bfd->stats.tx_fail_pkt); + } + bfd->stats.tx_fail_pkt = 0; + + bfd->stats.tx_echo_pkt++; + return 0; +} + +void ptm_sbfd_initiator_snd(struct bfd_session *bfd, int fbit) +{ + struct bfd_pkt cp = {}; + + /* Set fields according to section 6.5.7 */ + cp.diag = bfd->local_diag; + BFD_SETVER(cp.diag, BFD_VERSION); + cp.flags = 0; + BFD_SETSTATE(cp.flags, bfd->ses_state); + + if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_CBIT)) + BFD_SETCBIT(cp.flags, BFD_CBIT); + + BFD_SETDEMANDBIT(cp.flags, BFD_SBFD_INITIATOR_DEMAND); + + /* + * Polling and Final can't be set at the same time. + * + * RFC 5880, Section 6.5. + */ + BFD_SETFBIT(cp.flags, fbit); + if (fbit == 0) + BFD_SETPBIT(cp.flags, bfd->polling); + + cp.detect_mult = bfd->detect_mult; + cp.len = BFD_PKT_LEN; + cp.discrs.my_discr = htonl(bfd->discrs.my_discr); + cp.discrs.remote_discr = htonl(bfd->discrs.remote_discr); + if (bfd->polling) { + cp.timers.desired_min_tx = + htonl(bfd->timers.desired_min_tx); + } else { + /* + * We can only announce current setting on poll, this + * avoids timing mismatch with our peer and give it + * the oportunity to learn. See `bs_final_handler` for + * more information. + */ + cp.timers.desired_min_tx = + htonl(bfd->cur_timers.desired_min_tx); + } + cp.timers.required_min_rx = 0; + cp.timers.required_min_echo = 0; + + if (_ptm_sbfd_init_send(bfd, &cp, BFD_PKT_LEN) != 0) + return; + + bfd->stats.tx_ctrl_pkt++; +} +void ptm_sbfd_echo_snd(struct bfd_session *bfd) +{ + struct bfd_echo_pkt bep; + + memset(&bep, 0, sizeof(bep)); + BFD_SETVER(bep.ver, BFD_ECHO_VERSION); + bep.len = BFD_ECHO_PKT_LEN; + bep.my_discr = htonl(bfd->discrs.my_discr); + + if (_ptm_sbfd_echo_send(bfd, &bep, BFD_ECHO_PKT_LEN) != 0) + return; + + if (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) + SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE); +} + +static int ptm_bfd_reflector_process_init_packet(struct bfd_vrf_global *bvrf, int sd) +{ + //uint32_t my_discr = 0; + //uint32_t remote_discr = 0; + uint8_t ttl = 0; + struct sockaddr *sa; + struct sbfd_reflector *sr; + /* Receive and parse echo packet. */ + struct bfd_pkt *cp; + ssize_t rlen; + struct sockaddr_any local, peer; + ifindex_t ifindex = IFINDEX_INTERNAL; + //vrf_id_t vrfid = VRF_DEFAULT; + uint8_t msgbuf[1516]; + + rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, + &local, &peer); + /* Short packet, better not risk reading it. */ + if (rlen < (ssize_t)sizeof(*cp)) + { + zlog_debug("small bfd packet"); + return 0; + } + cp = (struct bfd_pkt *)(msgbuf); + sr = sbfd_discr_lookup(ntohl(cp->discrs.remote_discr)); + if(sr) + { + uint32_t temp = cp->discrs.my_discr; + cp->discrs.my_discr = cp->discrs.remote_discr; + cp->discrs.remote_discr = temp; + + sa = (struct sockaddr *)&peer.sa_sin6; + + if (sendto(sd, msgbuf, rlen, 0, sa, sizeof(peer.sa_sin6)) <= 0) + { + zlog_debug("packet-send: send failure: %s", + strerror(errno)); + return -1; + } + } + else + { + zlog_debug("no reflector found in %u",cp->discrs.remote_discr); + } + return 0; +} + +int bp_peer_srh_socketv6(struct bfd_session *bs) +{ + int sd; //, pcount; + //struct sockaddr_in6 sin6; + //static int srcPort = BFD_SRCPORTINIT; + const char *device_to_bind = NULL; + int on = 1; + + if (bs->key.ifname[0]){ + device_to_bind = (const char *)bs->key.ifname; + zlog_debug("device_to_bind to ifname:%s", device_to_bind); + } + else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]){ + device_to_bind = (const char *)bs->key.vrfname; + zlog_debug("device_to_bind to vrf:%s", device_to_bind); + }else{ + zlog_debug("device_to_bind to NULL"); + } + + frr_with_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET6, SOCK_RAW, IPPROTO_RAW, + bs->vrf->vrf_id, device_to_bind); + } + if (sd == -1) { + zlog_err("ipv6-new: failed to create socket: %s", + strerror(errno)); + return -1; + } + + /* Set TTL to 255 for all transmitted packets */ + if (bp_set_ttlv6(sd, BFD_TTL_VAL) != 0) { + close(sd); + return -1; + } + + /* Set TOS to CS6 for all transmitted packets */ + if (bp_set_tosv6(sd, BFD_TOS_VAL) != 0) { + close(sd); + return -1; + } + + /*manage the IP6 header all on own onwn*/ + if (setsockopt(sd, IPPROTO_IPV6, IPV6_HDRINCL, &on, sizeof(on))){ + zlog_err("setsockopt IPV6_HDRINCL error: %s", strerror(errno)); + close(sd); + return -1; + } + + return sd; +} + +int bp_initv6_socket(const struct vrf *vrf) +{ + int sd; + frr_with_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name); + } + if (sd == -1) { + if (errno != EAFNOSUPPORT) + zlog_fatal("echov6-socket: socket: %s", + strerror(errno)); + else + zlog_warn("echov6-socket: V6 is not supported, continuing"); + + return -1; + } + + bp_set_ipv6opts(sd); + bp_bind_ipv6(sd, BFD_DEF_SBFD_DEST_PORT); + //bp_set_prio(s, SOCK_OPT_PRIO_HIGH); + return sd; +} + +static uint16_t +checksum (uint16_t *addr, int len) { + + int count = len; + register uint32_t sum = 0; + uint16_t answer = 0; + + // Sum up 2-byte values until none or only one byte left. + while (count > 1) { + sum += *(addr++); + count -= 2; + } + + // Add left-over byte, if any. + if (count > 0) { + sum += *(uint8_t *) addr; + } + + // Fold 32-bit sum into 16 bits; we lose information by doing this, + // increasing the chances of a collision. + // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits) + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + // Checksum is one's compliment of sum. + answer = ~sum; + + return (answer); +} + +static uint16_t +udp6_checksum (struct ip6_hdr iphdr, struct udphdr udphdr, uint8_t *payload, int payloadlen) { + + char buf[IP_MAXPACKET]; + char *ptr; + int chksumlen = 0; + int i; + + ptr = &buf[0]; // ptr points to beginning of buffer buf + + // Copy source IP address into buf (128 bits) + memcpy (ptr, &iphdr.ip6_src.s6_addr, sizeof (iphdr.ip6_src.s6_addr)); + ptr += sizeof (iphdr.ip6_src.s6_addr); + chksumlen += sizeof (iphdr.ip6_src.s6_addr); + + // Copy destination IP address into buf (128 bits) + memcpy (ptr, &iphdr.ip6_dst.s6_addr, sizeof (iphdr.ip6_dst.s6_addr)); + ptr += sizeof (iphdr.ip6_dst.s6_addr); + chksumlen += sizeof (iphdr.ip6_dst.s6_addr); + + // Copy UDP length into buf (32 bits) + memcpy (ptr, &udphdr.len, sizeof (udphdr.len)); + ptr += sizeof (udphdr.len); + chksumlen += sizeof (udphdr.len); + + // Copy zero field to buf (24 bits) + *ptr = 0; ptr++; + *ptr = 0; ptr++; + *ptr = 0; ptr++; + chksumlen += 3; + + // Copy next header field to buf (8 bits) + memcpy (ptr, &iphdr.ip6_nxt, sizeof (iphdr.ip6_nxt)); + ptr += sizeof (iphdr.ip6_nxt); + chksumlen += sizeof (iphdr.ip6_nxt); + + // Copy UDP source port to buf (16 bits) + memcpy (ptr, &udphdr.source, sizeof (udphdr.source)); + ptr += sizeof (udphdr.source); + chksumlen += sizeof (udphdr.source); + + // Copy UDP destination port to buf (16 bits) + memcpy (ptr, &udphdr.dest, sizeof (udphdr.dest)); + ptr += sizeof (udphdr.dest); + chksumlen += sizeof (udphdr.dest); + + // Copy UDP length again to buf (16 bits) + memcpy (ptr, &udphdr.len, sizeof (udphdr.len)); + ptr += sizeof (udphdr.len); + chksumlen += sizeof (udphdr.len); + + // Copy UDP checksum to buf (16 bits) + // Zero, since we don't know it yet + *ptr = 0; ptr++; + *ptr = 0; ptr++; + chksumlen += 2; + + // Copy payload to buf + memcpy (ptr, payload, payloadlen * sizeof (uint8_t)); + ptr += payloadlen; + chksumlen += payloadlen; + + // Pad to the next 16-bit boundary + for (i=0; ivrf_id, vrf->name); + } + if (s == -1) { + if (errno != EAFNOSUPPORT) + zlog_fatal("sbfdv6-socket: socket: %s", strerror(errno)); + else + zlog_warn("sbfdv6-socket: V6 is not supported, continuing"); + + return -1; + } + + bp_set_prio(s, SOCK_OPT_PRIO_HIGH); + + return s; +} + +static void bp_sbfd_encap_srh_ip6h(struct ip6_hdr* srh_ip6h, + struct in6_addr* sip , struct in6_addr* dip ,uint8_t seg_num, size_t datalen) +{ + /* SRH IPv6 Header */ + srh_ip6h->ip6_flow = 0; + srh_ip6h->ip6_vfc = 6 << 4; + srh_ip6h->ip6_plen = htons(sizeof(struct ip6_hdr) + + sizeof(struct udphdr) + + sizeof(struct ipv6_sr_hdr) + + sizeof(struct in6_addr) * seg_num + + datalen); + srh_ip6h->ip6_nxt = IPPROTO_ROUTING; + srh_ip6h->ip6_hlim = BFD_TTL_VAL; + + memcpy(&(srh_ip6h->ip6_src), sip, sizeof(struct in6_addr)); + memcpy(&(srh_ip6h->ip6_dst), dip, sizeof(struct in6_addr)); +} + +static void bp_sbfd_encap_srh_ip6h_red(struct ip6_hdr* srh_ip6h, + struct in6_addr* sip , struct in6_addr* dip ,uint8_t seg_num, size_t datalen, uint16_t family) +{ + /* SRH IPv6 Header */ + srh_ip6h->ip6_flow = (BFD_TOS_VAL << 20); + srh_ip6h->ip6_vfc = 6 << 4; + + if (seg_num == 1) + { + if (family == AF_INET6) + { + srh_ip6h->ip6_plen = htons(sizeof(struct ip6_hdr) + + sizeof(struct udphdr) + + datalen); + srh_ip6h->ip6_nxt = IPPROTO_IPV6; + } + else + { + srh_ip6h->ip6_plen = htons(sizeof(struct ip) + + sizeof(struct udphdr) + + datalen); + srh_ip6h->ip6_nxt = IPPROTO_IPIP; + } + + } + else + { + srh_ip6h->ip6_plen = htons(sizeof(struct ip6_hdr) + + sizeof(struct udphdr) + + sizeof(struct ipv6_sr_hdr) + + sizeof(struct in6_addr) * (seg_num - 1) + + datalen); + srh_ip6h->ip6_nxt = IPPROTO_ROUTING; + } + srh_ip6h->ip6_hlim = BFD_TTL_VAL; + + memcpy(&(srh_ip6h->ip6_src), sip, sizeof(struct in6_addr)); + memcpy(&(srh_ip6h->ip6_dst), dip, sizeof(struct in6_addr)); +} + +static void bp_sbfd_encap_srh_rth(struct ipv6_sr_hdr *srv6h, + struct in6_addr* segment_list ,uint8_t seg_num) +{ + srv6h->nexthdr = IPPROTO_IPV6; + srv6h->hdrlen = GET_RTH_HDR_LEN(RTH_BASE_HEADER_LEN + sizeof(struct in6_addr)*seg_num); + srv6h->type = 4; // IPV6_SRCRT_TYPE_4 + srv6h->segments_left = seg_num-1; //if encap reduce mode , seg_num-1 + srv6h->first_segment = seg_num-1; //if encap reduce mode , seg_num-2 + srv6h->flags = 0; + srv6h->tag = 0; + + int i; + for(i = 0;i < seg_num;i++) + { + memcpy(&srv6h->segments[i], &segment_list[seg_num-1-i], sizeof(struct in6_addr)); + } +} + +static void bp_sbfd_encap_srh_rth_red(struct ipv6_sr_hdr *srv6h, + struct in6_addr* segment_list ,uint8_t seg_num) +{ + //caller should make sure: seg_num > 1 + srv6h->nexthdr = IPPROTO_IPV6; + srv6h->hdrlen = GET_RTH_HDR_LEN(RTH_BASE_HEADER_LEN + sizeof(struct in6_addr)*(seg_num - 1)); + srv6h->type = 4; // IPV6_SRCRT_TYPE_4 + srv6h->segments_left = seg_num - 1; //if encap reduce mode , seg_num-1 + srv6h->first_segment = seg_num - 2; //if encap reduce mode , seg_num-2 + srv6h->flags = 0; + srv6h->tag = 0; + + int i; + for(i = 0; i < seg_num - 1; i++) + { + //todo: double check here + memcpy(&srv6h->segments[i], &segment_list[seg_num-1-i], sizeof(struct in6_addr)); + } +} + +static void bp_sbfd_encap_inner_ip6h(struct ip6_hdr* ip6h, struct in6_addr* sip , struct in6_addr* dip, size_t datalen) +{ + /* IPv6 Header */ + ip6h->ip6_flow = (BFD_TOS_VAL << 20); + ip6h->ip6_vfc = 6 << 4; + ip6h->ip6_plen = htons(sizeof(struct udphdr) + datalen); + ip6h->ip6_nxt = IPPROTO_UDP; + ip6h->ip6_hlim = BFD_TTL_VAL; + + memcpy(&(ip6h->ip6_src), sip, sizeof(struct in6_addr)); + memcpy(&(ip6h->ip6_dst), dip, sizeof(struct in6_addr)); +} + +static void bp_sbfd_encap_inner_iph(struct ip* iph, struct in6_addr* sip , struct in6_addr* dip, size_t datalen) +{ + /* IPv4 Header */ + iph->ip_v = 4; + iph->ip_hl = 5; + iph->ip_tos = BFD_TOS_VAL; + iph->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + datalen); + iph->ip_id = (uint16_t)frr_weak_random(); + iph->ip_ttl = BFD_TTL_VAL; + iph->ip_p = IPPROTO_UDP; + iph->ip_sum = 0; + memcpy(&iph->ip_src, sip, sizeof(iph->ip_src)); + memcpy(&iph->ip_dst, dip, sizeof(iph->ip_dst)); +} + +static void bp_sbfd_encap_udp6(struct udphdr* udph, struct ip6_hdr* ip6h, uint16_t src_port, uint16_t dst_port , uint8_t *payload, int payloadlen) +{ + udph->uh_sport = htons(src_port); + udph->uh_dport = htons(dst_port); + udph->uh_ulen = htons(sizeof(struct udphdr) + payloadlen); + udph->uh_sum = udp6_checksum (*ip6h, *udph, payload, payloadlen); +} + +static void bp_sbfd_encap_udp4(struct udphdr* udph, struct ip* iph, uint16_t src_port, uint16_t dst_port , uint8_t *payload, int payloadlen) +{ + udph->uh_sport = htons(src_port); + udph->uh_dport = htons(dst_port); + udph->uh_ulen = htons(sizeof(struct udphdr) + payloadlen); + udph->uh_sum = udp4_checksum (*iph, *udph, payload, payloadlen); +} + +/** + * @brief encap srv6 to send raw socker + * + * @param sd sokcet + * @param data actual data, e.g. bfd packet or bfd echo packet + * @param datalen actual data length + * @param sip source ip address of outer ipv6 header and inner ipv6 header + * @param dip destination ip address of inner ipv6 header + * @param src_port source port of udp + * @param dst_port destination port of udp + * @param seg_num segment number of srh header + * @param segment_list segment list of srh header and the last one segment is destination ip address of outer ipv6 header + * @return int + */ +int bp_raw_sbfd_send(int sd, uint8_t *data, size_t datalen, struct in6_addr* sip , struct in6_addr* dip, + uint16_t src_port, uint16_t dst_port, + uint8_t seg_num, struct in6_addr* segment_list) +{ + struct sockaddr_in6 sin6; + struct msghdr msg; + struct iovec iov[5]; + int flags = 0; + int ret = 0; + + /*raw sbfd layer header*/ + struct ip6_hdr srh_ip6h; // srh ipv6 + struct ipv6_sr_hdr *psrv6h; // srh Routing header + struct ip6_hdr ip6h; // inner ipv6 + struct udphdr udp; + + if (!segment_list || seg_num == 0) + { + zlog_err( + "sbfd segment_list is invalid , seg_num = %d .", seg_num); + return -1; + } + + memset(&sin6,0,sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, &segment_list[0], sizeof(sin6.sin6_addr)); + + sin6.sin6_port = 0; + + /* SRH IPv6 Header */ + bp_sbfd_encap_srh_ip6h(&srh_ip6h, sip , &segment_list[0], seg_num, datalen); + + /* SRH Routing Header */ + psrv6h = (struct ipv6_sr_hdr*)malloc(sizeof(struct ipv6_sr_hdr) + sizeof(struct in6_addr) * seg_num); + if(psrv6h == NULL) + return -1; + + bp_sbfd_encap_srh_rth(psrv6h, segment_list, seg_num); + + /* Inner IPv6 Header */ + bp_sbfd_encap_inner_ip6h(&ip6h, sip , dip, datalen); + + /* UDP Header */ + bp_sbfd_encap_udp6(&udp, &ip6h, src_port, dst_port, data, datalen); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &sin6; + msg.msg_namelen = sizeof(sin6); + msg.msg_iov = iov; + msg.msg_iovlen = 5; + iov[0].iov_base = (char *)&srh_ip6h; + iov[0].iov_len = sizeof(struct ip6_hdr); + iov[1].iov_base = (char *) psrv6h; + iov[1].iov_len = sizeof(struct ipv6_sr_hdr) + sizeof(struct in6_addr) * seg_num; + iov[2].iov_base = (char *)&ip6h; + iov[2].iov_len = sizeof(struct ip6_hdr); + iov[3].iov_base = (char *)&udp; + iov[3].iov_len = sizeof(struct udphdr); + iov[4].iov_base = data; + iov[4].iov_len = datalen; + + ret = sendmsg(sd, &msg, flags); + if (ret < 0) + { + zlog_err( + "sbfd echo send failed , ret : %d .", ret); + } + + free(psrv6h); + + return ret; + +} + +/** + * @brief encap srv6 to send raw socker red mode, just support ecore 2.5 case + * + * @param sd sokcet + * @param data actual data, e.g. bfd packet or bfd echo packet + * @param datalen actual data length + * @param sip source ip address of outer ipv6 header and inner ipv6 header + * @param dip destination ip address of inner ipv6 header + * @param src_port source port of udp + * @param dst_port destination port of udp + * @param seg_num segment number of srh header + * @param segment_list segment list of srh header and the last one segment is destination ip address of outer ipv6 header + * @param ifname out interface name + * @param vrfname vrf name + * @param nhp specified nexthop + * @return int + */ +int bp_raw_sbfd_red_send(int sd, uint8_t *data, size_t datalen, + uint16_t family, struct in6_addr* out_sip, struct in6_addr* sip , struct in6_addr* dip, + uint16_t src_port, uint16_t dst_port, + uint8_t seg_num, struct in6_addr* segment_list) +{ + static uint8_t sendbuf[BUF_SIZ]; + struct msghdr msg = {0}; + struct iovec iov; + int flags = 0; + int ret = 0; + + struct ip6_hdr *srh_ip6h; + struct ipv6_sr_hdr *psrv6h; // srh Routing header + struct ip6_hdr *ip6h; + struct ip *iph; + struct udphdr *udp; + uint8_t *payload; + + struct ipaddr out_sip_addr = {0}; + struct sockaddr_in6 dst_sin6 = {0}; + char buf_addr[INET6_ADDRSTRLEN] = {0}; + + memset(sendbuf, 0, sizeof(sendbuf)); + int total_len = 0; + + /* SRH IPv6 Header */ + if (seg_num > 0) + { + memcpy(&out_sip_addr.ipaddr_v6, out_sip, sizeof(struct in6_addr)); + + srh_ip6h = (struct ip6_hdr *)(sendbuf + total_len); + bp_sbfd_encap_srh_ip6h_red(srh_ip6h, &out_sip_addr.ipaddr_v6 , &segment_list[0], seg_num, datalen, family); + total_len += sizeof(struct ip6_hdr); + + memcpy(&dst_sin6.sin6_addr, &segment_list[0], sizeof(struct in6_addr)); + } + + //case with srh header + if(seg_num > 1){ + psrv6h = (struct ipv6_sr_hdr*)(sendbuf + total_len); + bp_sbfd_encap_srh_rth_red(psrv6h, segment_list, seg_num); + total_len += sizeof(struct ipv6_sr_hdr) + sizeof(struct in6_addr) * (seg_num - 1); + } + + if (family == AF_INET6) + { + if(seg_num == 0){ + memcpy(&dst_sin6.sin6_addr, dip, sizeof(struct in6_addr)); + } + + /* Inner IPv6 Header */ + ip6h = (struct ip6_hdr *)(sendbuf + total_len); + bp_sbfd_encap_inner_ip6h(ip6h, sip , dip, datalen); + total_len += sizeof(struct ip6_hdr); + + /* UDP Header */ + udp = (struct udphdr *)(sendbuf + total_len); + bp_sbfd_encap_udp6(udp, ip6h, src_port, dst_port, data, datalen); + total_len += sizeof(struct udphdr); + } + else + { + if(seg_num == 0){ + //should never come to here, just print a error hint + zlog_err("bp_raw_sbfd_red_send error, empty sidlist for ipv4 bfd"); + } + + /* Inner IPv4 Header */ + iph = (struct ip *)(sendbuf + total_len); + bp_sbfd_encap_inner_iph(iph, sip , dip, datalen); + total_len += sizeof(struct ip); + + /* UDP Header */ + udp = (struct udphdr *)(sendbuf + total_len); + bp_sbfd_encap_udp4(udp, iph, src_port, dst_port, data, datalen); + total_len += sizeof(struct udphdr); + + iph->ip_sum = in_cksum((const void *)iph, sizeof(struct ip)); + } + + /* BFD payload*/ + payload = (uint8_t *)(sendbuf + total_len); + memcpy(payload, data, datalen); + total_len += datalen; + + dst_sin6.sin6_family = AF_INET6; + dst_sin6.sin6_port = 0; //we don't use sin6_port in raw, but should set to 0!! + + /* message data. */ + iov.iov_base = (uint8_t *)sendbuf; + iov.iov_len = total_len; + + msg.msg_name = &dst_sin6; + msg.msg_namelen = sizeof(struct sockaddr_in6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* sendmsg */ + ret = sendmsg(sd, &msg, flags); + if (ret < 0) + { + inet_ntop(AF_INET6, &dst_sin6.sin6_addr, buf_addr, INET6_ADDRSTRLEN); + zlog_debug( + "sbfd send to:%s failed , ret:%d, errno:%s", buf_addr, ret, safe_strerror(errno)); + + return ret; + } + + return 0; +} From 1c46d9bd79e3b76d0bfc9e10e3e0169ea075665a Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 12:05:18 +0000 Subject: [PATCH 10/21] bfdd: add sbfd state machine functions Signed-off-by: wumu.zsl --- bfdd/bfd.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++ bfdd/bfd.h | 54 ++++++++- bfdd/bfdd.c | 3 +- bfdd/event.c | 94 +++++++++++++++ 4 files changed, 463 insertions(+), 2 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index f46fd4a0b42f..a7e012c19197 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -39,6 +39,10 @@ static void bs_down_handler(struct bfd_session *bs, int nstate); static void bs_init_handler(struct bfd_session *bs, int nstate); static void bs_up_handler(struct bfd_session *bs, int nstate); +static void ptm_sbfd_echo_xmt_TO(struct bfd_session *bfd); +static void sbfd_down_handler(struct bfd_session *bs, int nstate); +static void sbfd_up_handler(struct bfd_session *bs, int nstate); + /** * Remove BFD profile from all BFD sessions so we don't leave dangling * pointers. @@ -474,6 +478,37 @@ void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit) ptm_bfd_start_xmt_timer(bfd, false); } +static void ptm_sbfd_echo_xmt_TO(struct bfd_session *bfd) +{ + /* Send the scheduled sbfd-echo packet */ + ptm_sbfd_echo_snd(bfd); + + /* Restart the timer for next time */ + ptm_bfd_start_xmt_timer(bfd, true); +} + +void ptm_sbfd_init_xmt_TO(struct bfd_session *bfd, int fbit) +{ + /* Send the scheduled control packet */ + ptm_sbfd_initiator_snd(bfd, fbit); + + /* Restart the timer for next time */ + ptm_bfd_start_xmt_timer(bfd, false); +} + +void ptm_sbfd_init_reset(struct bfd_session *bfd) +{ + bfd->xmt_TO = BFD_DEF_SLOWTX; + bfd->detect_TO = 0; + ptm_sbfd_init_xmt_TO(bfd, 0); +} +void ptm_sbfd_echo_reset(struct bfd_session *bfd) +{ + bfd->echo_xmt_TO = SBFD_ECHO_DEF_SLOWTX; + bfd->echo_detect_TO = 0; + ptm_sbfd_echo_xmt_TO(bfd); +} + void ptm_bfd_echo_stop(struct bfd_session *bfd) { bfd->echo_xmt_TO = 0; @@ -573,7 +608,99 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* reset RTT */ bfd_rtt_init(bfd); } +/*sbfd session up , include sbfd and sbfd echo*/ +void ptm_sbfd_sess_up(struct bfd_session *bfd) +{ + int old_state = bfd->ses_state; + + bfd->local_diag = 0; + bfd->ses_state = PTM_BFD_UP; + UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_REM_ADMIN_DOWN); + monotime(&bfd->uptime); + + /*notify session up*/ + ptm_bfd_notify(bfd, bfd->ses_state); + + if (old_state != bfd->ses_state) { + bfd->stats.session_up++; + if (bglobal.debug_peer_event) + zlog_info("state-change: [%s] %s -> %s", + bs_to_string(bfd), state_list[old_state].str, + state_list[bfd->ses_state].str); + } +} + +/*sbfd init session TO */ +void ptm_sbfd_init_sess_dn(struct bfd_session *bfd, uint8_t diag) +{ + int old_state = bfd->ses_state; + + bfd->local_diag = diag; + bfd->ses_state = PTM_BFD_DOWN; + bfd->polling = 0; + bfd->demand_mode = 0; + monotime(&bfd->downtime); + + /* + * Only attempt to send if we have a valid socket: + * this function might be called by session disablers and in + * this case we won't have a valid socket (i.e. interface was + * removed or VRF doesn't exist anymore). + */ + if (bfd->sock != -1 && (!CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_REM_ADMIN_DOWN))) + ptm_sbfd_init_reset(bfd); + + /* Slow down the control packets, the connection is down. */ + bs_set_slow_timers(bfd); + + /* only signal clients when going from up->down state */ + if (old_state == PTM_BFD_UP) + ptm_bfd_notify(bfd, PTM_BFD_DOWN); + + /* Stop attempting to transmit or expect control packets if passive. */ + if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_PASSIVE)) { + sbfd_init_recvtimer_delete(bfd); + sbfd_init_xmttimer_delete(bfd); + } + + if (old_state != bfd->ses_state) { + bfd->stats.session_down++; + if (bglobal.debug_peer_event) + zlog_debug("state-change: [%s] %s -> %s reason:%s", + bs_to_string(bfd), state_list[old_state].str, + state_list[bfd->ses_state].str, + get_diag_str(bfd->local_diag)); + } + /* reset local address ,it might has been be changed after bfd is up*/ + //memset(&bfd->local_address, 0, sizeof(bfd->local_address)); +} + +/*sbfd echo session TO */ +void ptm_sbfd_echo_sess_dn(struct bfd_session *bfd, uint8_t diag) +{ + int old_state = bfd->ses_state; + + bfd->local_diag = diag; + bfd->discrs.remote_discr = 0; + bfd->ses_state = PTM_BFD_DOWN; + bfd->polling = 0; + bfd->demand_mode = 0; + monotime(&bfd->downtime); + /* only signal clients when going from up->down state */ + if (old_state == PTM_BFD_UP) + ptm_bfd_notify(bfd, PTM_BFD_DOWN); + + ptm_sbfd_echo_reset(bfd); + if (old_state != bfd->ses_state) { + bfd->stats.session_down++; + if (bglobal.debug_peer_event) + zlog_warn("state-change: [%s] %s -> %s reason:%s", + bs_to_string(bfd), state_list[old_state].str, + state_list[bfd->ses_state].str, + get_diag_str(bfd->local_diag)); + } +} static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, uint32_t ldisc) { @@ -638,6 +765,20 @@ void bfd_echo_xmt_cb(struct event *t) ptm_bfd_echo_xmt_TO(bs); } +void sbfd_init_xmt_cb(struct event *t) +{ + struct bfd_session *bs = EVENT_ARG(t); + + ptm_sbfd_init_xmt_TO(bs, 0); +} + +void sbfd_echo_xmt_cb(struct event *t) +{ + struct bfd_session *bs = EVENT_ARG(t); + + if (bs->echo_xmt_TO > 0) + ptm_sbfd_echo_xmt_TO(bs); +} /* Was ptm_bfd_detect_TO() */ void bfd_recvtimer_cb(struct event *t) { @@ -663,6 +804,40 @@ void bfd_echo_recvtimer_cb(struct event *t) break; } } +void sbfd_init_recvtimer_cb(struct event *t) +{ + struct bfd_session *bs = EVENT_ARG(t); + + switch (bs->ses_state) { + case PTM_BFD_INIT: + case PTM_BFD_UP: + ptm_sbfd_init_sess_dn(bs, BD_SBFD_DETECT_FAILED); + break; + + default: + /* Second detect time expiration, zero remote discr (section + * 6.5.1) + */ + break; + } +} +void sbfd_echo_recvtimer_cb(struct event *t) +{ + struct bfd_session *bs = EVENT_ARG(t); + + if (bglobal.debug_peer_event) + zlog_debug("%s: time-out bfd: [%s] bfd'state is %s", + __func__, bs_to_string(bs), state_list[bs->ses_state].str); + + switch (bs->ses_state) { + case PTM_BFD_INIT: + case PTM_BFD_UP: + ptm_sbfd_echo_sess_dn(bs, BD_SBFD_DETECT_FAILED); + break; + case PTM_BFD_DOWN: + break; + } +} struct bfd_session *bfd_session_new(void) { @@ -988,6 +1163,31 @@ static void bs_down_handler(struct bfd_session *bs, int nstate) } } +static void sbfd_down_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + /* + * Remote peer doesn't want to talk, so lets keep the + * connection down. + */ + break; + case PTM_BFD_UP: + /* down - > up*/ + ptm_sbfd_sess_up(bs); + break; + + case PTM_BFD_DOWN: + break; + + default: + if (bglobal.debug_peer_event) + zlog_err("state-change: unhandled sbfd state: %d", + nstate); + break; + } +} + static void bs_init_handler(struct bfd_session *bs, int nstate) { switch (nstate) { @@ -1039,6 +1239,32 @@ static void bs_up_handler(struct bfd_session *bs, int nstate) } } +static void sbfd_up_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + case PTM_BFD_DOWN: + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + ptm_sbfd_echo_sess_dn(bs, BD_ECHO_FAILED); + } + else + ptm_sbfd_init_sess_dn(bs, BD_ECHO_FAILED); + + break; + + case PTM_BFD_UP: + /* Path is up and working. */ + break; + + default: + if (bglobal.debug_peer_event) + zlog_debug("state-change: unhandled neighbor state: %d", + nstate); + break; + } +} + void bs_state_handler(struct bfd_session *bs, int nstate) { switch (bs->ses_state) { @@ -1063,6 +1289,58 @@ void bs_state_handler(struct bfd_session *bs, int nstate) } } +void sbfd_echo_state_handler(struct bfd_session *bs, int nstate) +{ + if (bglobal.debug_peer_event) + zlog_debug("%s: bfd(%u) state: %s , notify state: %s", + __func__, bs->discrs.my_discr, + state_list[bs->ses_state].str, state_list[nstate].str); + + switch (bs->ses_state) { + case PTM_BFD_ADM_DOWN: + // bs_admin_down_handler(bs, nstate); + break; + case PTM_BFD_DOWN: + sbfd_down_handler(bs, nstate); + break; + case PTM_BFD_UP: + sbfd_up_handler(bs, nstate); + break; + + default: + if (bglobal.debug_peer_event) + zlog_debug("state-change: [%s] is in invalid state: %d", + bs_to_string(bs), nstate); + break; + } +} + +void sbfd_initiator_state_handler(struct bfd_session *bs, int nstate) +{ + if (bglobal.debug_peer_event) + zlog_debug("%s: sbfd(%u) state: %s , notify state: %s", + __func__, bs->discrs.my_discr, + state_list[bs->ses_state].str, state_list[nstate].str); + + switch (bs->ses_state) { + case PTM_BFD_ADM_DOWN: + // bs_admin_down_handler(bs, nstate); + break; + case PTM_BFD_DOWN: + sbfd_down_handler(bs, nstate); + break; + case PTM_BFD_UP: + sbfd_up_handler(bs, nstate); + break; + + default: + if (bglobal.debug_peer_event) + zlog_debug("state-change: [%s] is in invalid state: %d", + bs_to_string(bs), nstate); + break; + } +} + /* * Handles echo timer manipulation after updating timer. */ @@ -2068,6 +2346,42 @@ unsigned long bfd_get_session_count(void) return bfd_key_hash->count; } +struct bfd_session_name_match_unique { + const char *bfd_name; + struct bfd_session *bfd_found; +}; + +static int _bfd_session_name_cmp(struct hash_bucket *hb, void *arg) +{ + struct bfd_session *bs = hb->data; + struct bfd_session_name_match_unique *match = (struct bfd_session_name_match_unique *)arg; + + if (strlen(bs->bfd_name) != strlen(match->bfd_name)) + { + return HASHWALK_CONTINUE; + } + + if (!strncmp(bs->bfd_name, match->bfd_name, strlen(bs->bfd_name))) { + match->bfd_found = bs; + return HASHWALK_ABORT; + } + return HASHWALK_CONTINUE; +} + +struct bfd_session * bfd_session_get_by_name(const char * name) +{ + if (!name || name[0] == '\0') + return NULL; + + struct bfd_session_name_match_unique match; + match.bfd_name = name; + match.bfd_found = NULL; + + hash_walk(bfd_key_hash, _bfd_session_name_cmp, &match); + + return match.bfd_found; +} + void bfd_rtt_init(struct bfd_session *bfd) { uint8_t i; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index e9efe94a7f94..efe4f1dcad80 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -19,6 +19,7 @@ #include "lib/qobj.h" #include "lib/queue.h" #include "lib/vrf.h" +#include "lib/bfd.h" #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) @@ -27,9 +28,11 @@ #endif #ifndef MAXNAMELEN -#define MAXNAMELEN 32 +#define MAXNAMELEN 128 #endif +#define MAXALIASNAMELEN 256 + #define BPC_DEF_DETECTMULTIPLIER 3 #define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ #define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ @@ -86,6 +89,10 @@ struct bfd_peer_cfg { bool bpc_has_profile; char bpc_profile[64]; + + vrf_id_t vrf_id; + char bfd_name[BFD_NAME_SIZE +1]; + uint8_t bfd_name_len; }; /* bfd Authentication Type. */ @@ -194,6 +201,8 @@ struct bfd_echo_pkt { #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) +#define RTH_BASE_HEADER_LEN 8 +#define GET_RTH_HDR_LEN(size) (((size)>>3) - 1) enum bfd_diagnosticis { BD_OK = 0, /* Control Detection Time Expired. */ @@ -212,6 +221,8 @@ enum bfd_diagnosticis { BD_ADMIN_DOWN = 7, /* Reverse Concatenated Path Down. */ BD_REVCONCATPATH_DOWN = 8, + /* Sbfd Detect Function Failed. */ + BD_SBFD_DETECT_FAILED = 9, /* 9..31: reserved. */ }; @@ -233,6 +244,7 @@ enum bfd_session_flags { BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */ BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */ BFD_SESS_FLAG_MAC_SET = 1 << 11, /* MAC of peer known */ + BFD_SESS_FLAG_REM_ADMIN_DOWN = 1 << 13, /* remote notify admindown */ }; enum bfd_mode_type { @@ -382,6 +394,12 @@ struct bfd_session { uint8_t rtt_valid; /* number of valid samples */ uint8_t rtt_index; /* last index added */ uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ + char bfd_name[BFD_NAME_SIZE +1]; + + uint32_t bfd_mode; + uint8_t segnum; + struct in6_addr out_sip6; + struct in6_addr seg_list[0]; }; struct bfd_diag_str_list { @@ -409,6 +427,7 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define PTM_BFD_DOWN 1 #define PTM_BFD_INIT 2 #define PTM_BFD_UP 3 +#define PTM_BFD_DEL 4 /* Various constants */ @@ -420,6 +439,7 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEF_DES_MIN_ECHO_TX (50 * 1000) /* microseconds. */ #define BFD_DEF_REQ_MIN_ECHO_RX (50 * 1000) /* microseconds. */ #define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */ +#define SBFD_ECHO_DEF_SLOWTX (3000 * 1000) /* microseconds. */ /** Minimum multi hop TTL. */ #define BFD_DEF_MHOP_TTL 254 #define BFD_PKT_LEN 24 /* Length of control packet */ @@ -434,7 +454,11 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEFDESTPORT 3784 #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 +#define BFD_DEF_SBFD_DEST_PORT 7784 +#define BFD_SBFD_INITIATOR_DEMAND 1 +#define BFD_IPV6_UDP_DISABLE_CHECKSUM 1 +#define UDP_NO_CHECK6_RX 102 /* * bfdd.c @@ -558,13 +582,23 @@ typedef void (*bfd_ev_cb)(struct event *t); void bfd_recvtimer_update(struct bfd_session *bs); void bfd_echo_recvtimer_update(struct bfd_session *bs); +void sbfd_init_recvtimer_update(struct bfd_session *bs); +void sbfd_echo_recvtimer_update(struct bfd_session *bs); + void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter); void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter); +void sbfd_init_xmttimer_update(struct bfd_session *bs, uint64_t jitter); +void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter); void bfd_xmttimer_delete(struct bfd_session *bs); void bfd_echo_xmttimer_delete(struct bfd_session *bs); +void sbfd_init_xmttimer_delete(struct bfd_session *bs); +void sbfd_echo_xmttimer_delete(struct bfd_session *bs); + void bfd_recvtimer_delete(struct bfd_session *bs); void bfd_echo_recvtimer_delete(struct bfd_session *bs); +void sbfd_init_recvtimer_delete(struct bfd_session *bs); +void sbfd_echo_recvtimer_delete(struct bfd_session *bs); void bfd_recvtimer_assign(struct bfd_session *bs, bfd_ev_cb cb, int sd); void bfd_echo_recvtimer_assign(struct bfd_session *bs, bfd_ev_cb cb, int sd); @@ -587,6 +621,9 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd); void ptm_bfd_echo_start(struct bfd_session *bfd); void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit); void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo); +void ptm_sbfd_init_xmt_TO(struct bfd_session *bfd, int fbit); +void ptm_sbfd_init_reset(struct bfd_session *bfd); +void ptm_sbfd_echo_reset(struct bfd_session *bfd); struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, @@ -621,6 +658,7 @@ const struct bfd_session *bfd_session_next(const struct bfd_session *bs, bool mhop); void bfd_sessions_remove_manual(void); void bfd_profiles_remove(void); +void bs_sbfd_echo_timer_handler(struct bfd_session *bs); void bfd_rtt_init(struct bfd_session *bfd); extern void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf); @@ -687,6 +725,11 @@ void bfd_echo_recvtimer_cb(struct event *t); void bfd_xmt_cb(struct event *t); void bfd_echo_xmt_cb(struct event *t); +void sbfd_init_recvtimer_cb(struct event *t); +void sbfd_echo_recvtimer_cb(struct event *t); +void sbfd_init_xmt_cb(struct event *t); +void sbfd_echo_xmt_cb(struct event *t); + extern struct in6_addr zero_addr; /** @@ -822,4 +865,13 @@ int bfd_dplane_update_session_counters(struct bfd_session *bs); void bfd_dplane_show_counters(struct vty *vty); + +/*sbfd*/ +void ptm_sbfd_echo_sess_dn(struct bfd_session *bfd, uint8_t diag); +void ptm_sbfd_init_sess_dn(struct bfd_session *bfd, uint8_t diag); +void ptm_sbfd_sess_up(struct bfd_session *bfd); +void sbfd_echo_state_handler(struct bfd_session *bs, int nstate); +void sbfd_initiator_state_handler(struct bfd_session *bs, int nstate); + +struct bfd_session * bfd_session_get_by_name(const char * name); #endif /* _BFD_H_ */ diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index c2d8e926bff6..47b51ae94aba 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -150,6 +150,7 @@ const struct bfd_diag_str_list diag_list[] = { {.str = "concatenated-path-down", .type = BD_CONCATPATH_DOWN}, {.str = "administratively-down", .type = BD_ADMIN_DOWN}, {.str = "reverse-concat-path-down", .type = BD_REVCONCATPATH_DOWN}, + {.str = "sbfd-detect-failed", .type = BD_SBFD_DETECT_FAILED}, {.str = NULL}, }; @@ -359,7 +360,7 @@ int main(int argc, char *argv[]) bfd_vrf_init(); access_list_init(); - + /* Initialize zebra connection. */ bfdd_zclient_init(&bglobal.bfdd_privs); diff --git a/bfdd/event.c b/bfdd/event.c index e797e71f050a..8742496b9410 100644 --- a/bfdd/event.c +++ b/bfdd/event.c @@ -58,6 +58,80 @@ void bfd_echo_recvtimer_update(struct bfd_session *bs) &bs->echo_recvtimer_ev); } +void sbfd_init_recvtimer_update(struct bfd_session *bs) +{ + struct timeval tv = {.tv_sec = 0, .tv_usec = bs->detect_TO}; + + /* Remove previous schedule if any. */ + sbfd_init_recvtimer_delete(bs); + + /* Don't add event if peer is deactivated. */ + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) + return; + + tv_normalize(&tv); +#ifdef BFD_EVENT_DEBUG + log_debug("%s: sec = %ld, usec = %ld", __func__, tv.tv_sec, tv.tv_usec); +#endif /* BFD_EVENT_DEBUG */ + + event_add_timer_tv(master, sbfd_init_recvtimer_cb, bs, &tv, + &bs->recvtimer_ev); +} + +void sbfd_echo_recvtimer_update(struct bfd_session *bs) +{ + struct timeval tv = {.tv_sec = 0, .tv_usec = bs->echo_detect_TO}; + + /* Remove previous schedule if any. */ + sbfd_echo_recvtimer_delete(bs); + + /* Don't add event if peer is deactivated. */ + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) + return; + + tv_normalize(&tv); + + event_add_timer_tv(master, sbfd_echo_recvtimer_cb, bs, &tv, + &bs->echo_recvtimer_ev); +} + +void sbfd_init_xmttimer_update(struct bfd_session *bs, uint64_t jitter) +{ + struct timeval tv = {.tv_sec = 0, .tv_usec = jitter}; + + /* Remove previous schedule if any. */ + sbfd_init_xmttimer_delete(bs); + + /* Don't add event if peer is deactivated. */ + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) + return; + + tv_normalize(&tv); + + event_add_timer_tv(master, sbfd_init_xmt_cb, bs, &tv, &bs->xmttimer_ev); +} + +void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) +{ + struct timeval tv = {.tv_sec = 0, .tv_usec = jitter}; + + /* Remove previous schedule if any. */ + sbfd_echo_xmttimer_delete(bs); + + /* Don't add event if peer is deactivated. */ + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) + return; + + tv_normalize(&tv); + + event_add_timer_tv(master, sbfd_echo_xmt_cb, bs, &tv, + &bs->echo_xmttimer_ev); +} + void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter) { struct timeval tv = {.tv_sec = 0, .tv_usec = jitter}; @@ -112,3 +186,23 @@ void bfd_echo_xmttimer_delete(struct bfd_session *bs) { EVENT_OFF(bs->echo_xmttimer_ev); } + +void sbfd_init_recvtimer_delete(struct bfd_session *bs) +{ + EVENT_OFF(bs->recvtimer_ev); +} + +void sbfd_echo_recvtimer_delete(struct bfd_session *bs) +{ + EVENT_OFF(bs->echo_recvtimer_ev); +} + +void sbfd_init_xmttimer_delete(struct bfd_session *bs) +{ + EVENT_OFF(bs->xmttimer_ev); +} + +void sbfd_echo_xmttimer_delete(struct bfd_session *bs) +{ + EVENT_OFF(bs->echo_xmttimer_ev); +} \ No newline at end of file From f055db1cbcd10409a48d00c7ec4a1368181d5807 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 13:00:44 +0000 Subject: [PATCH 11/21] bfdd: create a hash table for local sbfd reflector info Signed-off-by: wumu.zsl --- bfdd/bfd.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ bfdd/bfd.h | 15 +++++++- 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index a7e012c19197..a81e149331d0 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -23,6 +23,7 @@ DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory"); DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory"); DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer"); DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF"); +DEFINE_MTYPE_STATIC(BFDD, SBFD_REFLECTOR, "SBFD REFLECTOR"); /* * Prototypes @@ -1812,6 +1813,10 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc) static struct hash *bfd_id_hash; static struct hash *bfd_key_hash; +/*sbfd reflector discr hash*/ +static struct hash *sbfd_rflt_hash; +static unsigned int sbfd_discr_hash_do(const void *p); + static unsigned int bfd_id_hash_do(const void *p); static unsigned int bfd_key_hash_do(const void *p); @@ -1887,6 +1892,20 @@ static bool bfd_key_hash_cmp(const void *n1, const void *n2) return true; } +/* SBFD disr hash . */ +static unsigned int sbfd_discr_hash_do(const void *p) +{ + const struct sbfd_reflector *sr = p; + + return jhash_1word(sr->discr, 0); +} + +static bool sbfd_discr_hash_cmp(const void *n1, const void *n2) +{ + const struct sbfd_reflector *sr1 = n1, *sr2 = n2; + + return sr1->discr == sr2->discr; +} /* * Hash public interface / exported functions. @@ -1911,6 +1930,15 @@ struct bfd_session *bfd_key_lookup(struct bfd_key key) return hash_lookup(bfd_key_hash, &bs); } +struct sbfd_reflector *sbfd_discr_lookup(uint32_t discr) +{ + struct sbfd_reflector sr; + + sr.discr= discr; + + return hash_lookup(sbfd_rflt_hash, &sr); +} + /* * Delete functions. * @@ -1939,6 +1967,15 @@ struct bfd_session *bfd_key_delete(struct bfd_key key) return hash_release(bfd_key_hash, &bs); } +struct sbfd_reflector *sbfd_discr_delete(uint32_t discr) +{ + struct sbfd_reflector sr; + + sr.discr = discr; + + return hash_release(sbfd_rflt_hash, &sr); +} + /* Iteration functions. */ void bfd_id_iterate(hash_iter_func hif, void *arg) { @@ -1950,6 +1987,11 @@ void bfd_key_iterate(hash_iter_func hif, void *arg) hash_iterate(bfd_key_hash, hif, arg); } +void sbfd_discr_iterate(hash_iter_func hif, void *arg) +{ + hash_iterate(sbfd_rflt_hash, hif, arg); +} + /* * Insert functions. * @@ -1966,12 +2008,25 @@ bool bfd_key_insert(struct bfd_session *bs) return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs); } +bool sbfd_discr_insert(struct sbfd_reflector *sr) +{ + return (hash_get(sbfd_rflt_hash, sr, hash_alloc_intern) == sr); +} + +unsigned long sbfd_discr_get_count(void) +{ + return sbfd_rflt_hash->count; +} + + void bfd_initialize(void) { bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp, "BFD session discriminator hash"); bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp, "BFD session hash"); + sbfd_rflt_hash = hash_create(sbfd_discr_hash_do, sbfd_discr_hash_cmp, + "SBFD reflector discriminator hash"); TAILQ_INIT(&bplist); } @@ -1983,6 +2038,15 @@ static void _bfd_free(struct hash_bucket *hb, bfd_session_free(bs); } +static void _sbfd_reflector_free(struct hash_bucket *hb, + void *arg __attribute__((__unused__))) +{ + struct sbfd_reflector *sr = hb->data; + + + sbfd_reflector_free(sr->discr); +} + void bfd_shutdown(void) { struct bfd_profile *bp; @@ -1997,9 +2061,13 @@ void bfd_shutdown(void) bfd_id_iterate(_bfd_free, NULL); assert(bfd_key_hash->count == 0); + sbfd_discr_iterate(_sbfd_reflector_free, NULL); + assert(sbfd_rflt_hash->count == 0); + /* Now free the hashes themselves. */ hash_free(bfd_id_hash); hash_free(bfd_key_hash); + hash_free(sbfd_rflt_hash); /* Free all profile allocations. */ while ((bp = TAILQ_FIRST(&bplist)) != NULL) @@ -2346,6 +2414,45 @@ unsigned long bfd_get_session_count(void) return bfd_key_hash->count; } +struct sbfd_reflector *sbfd_reflector_new(const uint32_t discr, struct in6_addr *sip) +{ + struct sbfd_reflector *sr; + + sr = sbfd_discr_lookup(discr); + if (sr) + return sr; + + sr = XCALLOC(MTYPE_SBFD_REFLECTOR, sizeof(*sr)); + sr->discr = discr; + memcpy(&sr->local, sip, sizeof(struct in6_addr)); + + sbfd_discr_insert(sr); + + + + return sr; +} + +void sbfd_reflector_free(const uint32_t discr) +{ + struct sbfd_reflector *sr; + + sr = sbfd_discr_lookup(discr); + if (!sr) + return; + + sbfd_discr_delete(discr); + XFREE(MTYPE_SBFD_REFLECTOR, sr); + + return; +} + +void sbfd_reflector_flush() +{ + sbfd_discr_iterate(_sbfd_reflector_free, NULL); + return; +} + struct bfd_session_name_match_unique { const char *bfd_name; struct bfd_session *bfd_found; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index efe4f1dcad80..852af139749c 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -421,6 +421,11 @@ struct bfd_session_observer { }; TAILQ_HEAD(obslist, bfd_session_observer); +/*sbfd reflector struct*/ +struct sbfd_reflector{ + uint32_t discr; + struct in6_addr local; +}; /* States defined per 4.1 */ #define PTM_BFD_ADM_DOWN 0 @@ -704,18 +709,22 @@ void bfd_vrf_terminate(void); struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd); struct bfd_session *bfd_id_lookup(uint32_t id); struct bfd_session *bfd_key_lookup(struct bfd_key key); - +struct sbfd_reflector *sbfd_discr_lookup(uint32_t discr); struct bfd_session *bfd_id_delete(uint32_t id); struct bfd_session *bfd_key_delete(struct bfd_key key); +struct sbfd_reflector *sbfd_discr_delete(uint32_t discr); bool bfd_id_insert(struct bfd_session *bs); bool bfd_key_insert(struct bfd_session *bs); +bool sbfd_discr_insert(struct sbfd_reflector *sr); typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg); void bfd_key_iterate(hash_iter_func hif, void *arg); +void sbfd_discr_iterate(hash_iter_func hif, void *arg); unsigned long bfd_get_session_count(void); +unsigned long sbfd_discr_get_count(void); /* Export callback functions for `event.c`. */ extern struct event_loop *master; @@ -865,6 +874,10 @@ int bfd_dplane_update_session_counters(struct bfd_session *bs); void bfd_dplane_show_counters(struct vty *vty); +/*sbfd relfector*/ +struct sbfd_reflector *sbfd_reflector_new(const uint32_t discr, struct in6_addr *sip); +void sbfd_reflector_free(const uint32_t discr); +void sbfd_reflector_flush(void); /*sbfd*/ void ptm_sbfd_echo_sess_dn(struct bfd_session *bfd, uint8_t diag); From 23a05ed73c85848736d9eca1b1b10ee6f2ca0473 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 13:15:22 +0000 Subject: [PATCH 12/21] bfdd: enable sbfd session create related sockets and start timers to send sbfd packets Signed-off-by: wumu.zsl --- bfdd/bfd.c | 117 ++++++++++++++++++++++++++++++++++++++++++----------- bfdd/bfd.h | 13 ++++-- 2 files changed, 103 insertions(+), 27 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index a81e149331d0..068d735f6839 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -197,10 +197,13 @@ void bfd_session_apply(struct bfd_session *bs) } /* Toggle 'passive-mode' if default value. */ - if (bs->peer_profile.passive == false) - bfd_set_passive_mode(bs, bp->passive); - else - bfd_set_passive_mode(bs, bs->peer_profile.passive); + if (bs->bfd_mode == BFD_MODE_TYPE_BFD) + { + if (bs->peer_profile.passive == false) + bfd_set_passive_mode(bs, bp->passive); + else + bfd_set_passive_mode(bs, bs->peer_profile.passive); + } /* Toggle 'no shutdown' if default value. */ if (bs->peer_profile.admin_shutdown == false) @@ -283,7 +286,7 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, - bpc->bpc_localif, bpc->bpc_vrfname, bpc->bfd_name); + bpc->bpc_localif, bpc->bpc_vrfname, bpc->bfd_name); return bfd_key_lookup(key); } @@ -356,14 +359,30 @@ int bfd_session_enable(struct bfd_session *bs) * could use the destination port (3784) for the source * port we wouldn't need a socket per session. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO + || bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + psock = bp_peer_srh_socketv6(bs); + if (psock <= 0){ + zlog_err("bp_peer_srh_socketv6 error"); + return 0; + } + } + else if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) + { psock = bp_peer_socket(bs); - if (psock == -1) + if (psock == -1){ + zlog_err("bp_peer_socket error"); return 0; - } else { + } + } + else + { psock = bp_peer_socketv6(bs); - if (psock == -1) + if (psock == -1){ + zlog_err("bp_peer_socketv6 error"); return 0; + } } /* @@ -374,10 +393,17 @@ int bfd_session_enable(struct bfd_session *bs) /* Only start timers if we are using active mode. */ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE) == 0) { - bfd_recvtimer_update(bs); - ptm_bfd_start_xmt_timer(bs, false); + if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) + { + bfd_echo_recvtimer_update(bs); + ptm_bfd_start_xmt_timer(bs, true); + } + else + { + bfd_recvtimer_update(bs); + ptm_bfd_start_xmt_timer(bs, false); + } } - /* initialize RTT */ bfd_rtt_init(bs); @@ -406,6 +432,8 @@ void bfd_session_disable(struct bfd_session *bs) bfd_recvtimer_delete(bs); bfd_xmttimer_delete(bs); ptm_bfd_echo_stop(bs); + bs->vrf = NULL; + bs->ifp = NULL; /* Set session down so it doesn't report UP and disabled. */ ptm_bfd_sess_dn(bs, BD_PATH_DOWN); @@ -445,10 +473,20 @@ void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo) jitter = (xmt_TO * (75 + (frr_weak_random() % maxpercent))) / 100; /* XXX remove that division above */ - if (is_echo) - bfd_echo_xmttimer_update(bfd, jitter); - else - bfd_xmttimer_update(bfd, jitter); + if (bfd->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) + { + if(is_echo) + sbfd_echo_xmttimer_update(bfd, jitter); + else + sbfd_init_xmttimer_update(bfd, jitter); + + }else{ + if(is_echo) + bfd_echo_xmttimer_update(bfd, jitter); + else + bfd_xmttimer_update(bfd, jitter); + + } } static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd) @@ -535,6 +573,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) bfd->local_diag = 0; bfd->ses_state = PTM_BFD_UP; + UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_REM_ADMIN_DOWN); monotime(&bfd->uptime); /* Connection is up, lets negotiate timers. */ @@ -604,7 +643,8 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET); memset(bfd->peer_hw_addr, 0, sizeof(bfd->peer_hw_addr)); /* reset local address ,it might has been be changed after bfd is up*/ - memset(&bfd->local_address, 0, sizeof(bfd->local_address)); + if(bfd->bfd_mode == BFD_MODE_TYPE_BFD) + memset(&bfd->local_address, 0, sizeof(bfd->local_address)); /* reset RTT */ bfd_rtt_init(bfd); @@ -798,6 +838,10 @@ void bfd_echo_recvtimer_cb(struct event *t) { struct bfd_session *bs = EVENT_ARG(t); + if (bglobal.debug_peer_event) + zlog_debug("%s: time-out bfd: [%s] bfd'state is %s", + __func__, bs_to_string(bs), state_list[bs->ses_state].str); + switch (bs->ses_state) { case PTM_BFD_INIT: case PTM_BFD_UP: @@ -840,11 +884,14 @@ void sbfd_echo_recvtimer_cb(struct event *t) } } -struct bfd_session *bfd_session_new(void) +struct bfd_session *bfd_session_new(enum bfd_mode_type mode, uint8_t segnum) { struct bfd_session *bs; - bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs)); + //"sizeof(struct in6_addr)*segnum" increase extra mem for sbfd segments + bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(struct bfd_session) + sizeof(struct in6_addr)*segnum); + bs->segnum = segnum; + bs->bfd_mode = mode; /* Set peer session defaults. */ bfd_profile_set_default(&bs->peer_profile); @@ -982,7 +1029,7 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) } /* Get BFD session storage with its defaults. */ - bfd = bfd_session_new(); + bfd = bfd_session_new(BFD_MODE_TYPE_BFD, 0); /* * Store interface/VRF name in case we need to delay session @@ -1444,6 +1491,15 @@ void bs_set_slow_timers(struct bfd_session *bs) /* Set the appropriated timeouts for slow connection. */ bs->detect_TO = (BFD_DEFDETECTMULT * BFD_DEF_SLOWTX); bs->xmt_TO = BFD_DEF_SLOWTX; + + /* add for sbfd-echo slow connection */ + if (BFD_MODE_TYPE_SBFD_ECHO == bs->bfd_mode){ + bs->echo_xmt_TO = SBFD_ECHO_DEF_SLOWTX; + bs->timers.desired_min_echo_tx = BFD_DEFDESIREDMINTX; + bs->timers.required_min_echo_rx = BFD_DEFDESIREDMINTX; + bs->peer_profile.min_echo_rx = BFD_DEFDESIREDMINTX; + bs->peer_profile.min_echo_tx = BFD_DEFDESIREDMINTX; + } } void bfd_set_echo(struct bfd_session *bs, bool echo) @@ -1735,6 +1791,9 @@ const char *bs_to_string(const struct bfd_session *bs) if (bs->key.ifname[0]) pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s", bs->key.ifname); + if (bs->bfd_name[0]) + pos += snprintf(buf + pos, sizeof(buf) - pos, " bfd_name:%s", + bs->bfd_name); (void)pos; @@ -1868,6 +1927,9 @@ static bool bfd_key_hash_cmp(const void *n1, const void *n2) if (memcmp(bs1->key.vrfname, bs2->key.vrfname, sizeof(bs1->key.vrfname))) return false; + if (memcmp(bs1->key.bfdname, bs2->key.bfdname, + sizeof(bs1->key.bfdname))) + return false; /* * Local address is optional and can be empty. @@ -2077,6 +2139,7 @@ void bfd_shutdown(void) struct bfd_session_iterator { int bsi_stop; bool bsi_mhop; + uint32_t bsi_bfdmode; const struct bfd_session *bsi_bs; }; @@ -2088,7 +2151,7 @@ static int _bfd_session_next(struct hash_bucket *hb, void *arg) /* Previous entry signaled stop. */ if (bsi->bsi_stop == 1) { /* Match the single/multi hop sessions. */ - if (bs->key.mhop != bsi->bsi_mhop) + if ((bs->key.mhop != bsi->bsi_mhop) && (bs->bfd_mode != bsi->bsi_bfdmode)) return HASHWALK_CONTINUE; bsi->bsi_bs = bs; @@ -2100,7 +2163,7 @@ static int _bfd_session_next(struct hash_bucket *hb, void *arg) bsi->bsi_stop = 1; /* Set entry to NULL to signal end of list. */ bsi->bsi_bs = NULL; - } else if (bsi->bsi_bs == NULL && bsi->bsi_mhop == bs->key.mhop) { + } else if (bsi->bsi_bs == NULL && bsi->bsi_mhop == bs->key.mhop && bsi->bsi_bfdmode == bs->bfd_mode) { /* We want the first list item. */ bsi->bsi_stop = 1; bsi->bsi_bs = hb->data; @@ -2116,13 +2179,14 @@ static int _bfd_session_next(struct hash_bucket *hb, void *arg) * `bs` might point to NULL to get the first item of the data structure. */ const struct bfd_session *bfd_session_next(const struct bfd_session *bs, - bool mhop) + bool mhop, uint32_t bfd_mode) { struct bfd_session_iterator bsi; bsi.bsi_stop = 0; bsi.bsi_bs = bs; bsi.bsi_mhop = mhop; + bsi.bsi_bfdmode = bfd_mode; hash_walk(bfd_key_hash, _bfd_session_next, &bsi); if (bsi.bsi_stop == 0) return NULL; @@ -2321,6 +2385,8 @@ static int bfd_vrf_enable(struct vrf *vrf) bvrf->bg_shop6 = bp_udp6_shop(vrf); if (bvrf->bg_mhop6 == -1) bvrf->bg_mhop6 = bp_udp6_mhop(vrf); + if (!bvrf->bg_initv6) + bvrf->bg_initv6 = bp_initv6_socket(vrf); if (bvrf->bg_ev[0] == NULL && bvrf->bg_shop != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, @@ -2334,6 +2400,9 @@ static int bfd_vrf_enable(struct vrf *vrf) if (bvrf->bg_ev[3] == NULL && bvrf->bg_mhop6 != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, &bvrf->bg_ev[3]); + if (!bvrf->bg_ev[6] && bvrf->bg_initv6 != -1) + event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_initv6, + &bvrf->bg_ev[6]); /* Toggle echo if VRF was disabled. */ bfd_vrf_toggle_echo(bvrf); @@ -2370,6 +2439,7 @@ static int bfd_vrf_disable(struct vrf *vrf) EVENT_OFF(bvrf->bg_ev[3]); EVENT_OFF(bvrf->bg_ev[4]); EVENT_OFF(bvrf->bg_ev[5]); + EVENT_OFF(bvrf->bg_ev[6]); /* Close all descriptors. */ socket_close(&bvrf->bg_echo); @@ -2378,6 +2448,7 @@ static int bfd_vrf_disable(struct vrf *vrf) socket_close(&bvrf->bg_shop6); socket_close(&bvrf->bg_mhop6); socket_close(&bvrf->bg_echov6); + socket_close(&bvrf->bg_initv6); return 0; } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 852af139749c..bfc85ff89dbf 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -90,7 +90,7 @@ struct bfd_peer_cfg { bool bpc_has_profile; char bpc_profile[64]; - vrf_id_t vrf_id; + vrf_id_t vrf_id; char bfd_name[BFD_NAME_SIZE +1]; uint8_t bfd_name_len; }; @@ -154,6 +154,7 @@ struct bfd_echo_pkt { uint64_t time_sent_usec; }; +#define BFD_XMTDEL_DELAY_TIMER 5 /* Macros for manipulating control packets */ #define BFD_VERMASK 0x07 @@ -283,6 +284,7 @@ struct bfd_session_stats { uint64_t session_up; uint64_t session_down; uint64_t znotification; + uint64_t tx_fail_pkt; }; /** @@ -477,9 +479,10 @@ struct bfd_vrf_global { int bg_mhop6; int bg_echo; int bg_echov6; + int bg_initv6; struct vrf *vrf; - struct event *bg_ev[6]; + struct event *bg_ev[7]; }; /* Forward declaration of data plane context struct. */ @@ -656,11 +659,13 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc); void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct sockaddr_any *local, bool mhop, const char *ifname, const char *vrfname, const char *bfdname); -struct bfd_session *bfd_session_new(void); + +struct bfd_session *bfd_session_new(enum bfd_mode_type mode, uint8_t segnum); + struct bfd_session *bs_registrate(struct bfd_session *bs); void bfd_session_free(struct bfd_session *bs); const struct bfd_session *bfd_session_next(const struct bfd_session *bs, - bool mhop); + bool mhop, uint32_t bfd_mode); void bfd_sessions_remove_manual(void); void bfd_profiles_remove(void); void bs_sbfd_echo_timer_handler(struct bfd_session *bs); From 11a7582975cad6d12e6fb4b0259de1a64dc36f0c Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 13:16:49 +0000 Subject: [PATCH 13/21] bfdd: process sbfd in packets in bfd_recv_cb Signed-off-by: wumu.zsl --- bfdd/bfd_packet.c | 57 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 80ed54777594..cf3819bfbec2 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -35,7 +35,6 @@ #include "bfd.h" #define BUF_SIZ 1024 #define SOCK_OPT_PRIO_HIGH 6 - /* * Prototypes */ @@ -65,7 +64,7 @@ int bp_raw_sbfd_red_send(int sd, uint8_t *data, size_t datalen, uint16_t family, struct in6_addr* out_sip, struct in6_addr* sip , struct in6_addr* dip, uint16_t src_port, uint16_t dst_port, uint8_t seg_num, struct in6_addr* segment_list); - + #ifdef BFD_LINUX ssize_t bfd_recv_ipv4_fp(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, ifindex_t *ifindex, @@ -391,7 +390,25 @@ static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s) /* Compute detect time */ bfd->echo_detect_TO = bfd->remote_detect_mult * bfd->echo_xmt_TO; - /* Update echo receive timeout. */ + /* Update sbfd-echo session state */ + if (bfd->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO){ + sbfd_echo_state_handler(bfd, PTM_BFD_UP); + + if(bfd->echo_xmt_TO != bfd->timers.desired_min_echo_tx) + { + bfd->echo_xmt_TO = bfd->timers.desired_min_echo_tx; + //reset xmt timer TO after UP + ptm_bfd_start_xmt_timer(bfd, true); + } + + bfd->echo_detect_TO = bfd->detect_mult * bfd->echo_xmt_TO; + /* Update sbfd echo receive timeout. */ + if (bfd->echo_detect_TO > 0) + sbfd_echo_recvtimer_update(bfd); + return 0; + } + + /* Update bfd-echo receive timeout. */ if (bfd->echo_detect_TO > 0) bfd_echo_recvtimer_update(bfd); @@ -747,6 +764,11 @@ static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6, &bvrf->bg_ev[5]); } + else if (sd == bvrf->bg_initv6) { + EVENT_OFF(bvrf->bg_ev[6]); + event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_initv6, + &bvrf->bg_ev[6]); + } } PRINTFRR(6, 7) @@ -839,6 +861,11 @@ void bfd_recv_cb(struct event *t) /* Schedule next read. */ bfd_sd_reschedule(bvrf, sd); + /* The reflector handle SBFD init packets. */ + if(sd == bvrf->bg_initv6){ + ptm_bfd_reflector_process_init_packet(bvrf, sd); + return; + } /* Handle echo packets. */ if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) { ptm_bfd_process_echo_pkt(bvrf, sd); @@ -1013,6 +1040,30 @@ void bfd_recv_cb(struct event *t) else bfd->remote_cbit = 0; + /* The sender handle SBFD init session. */ + if (bfd->bfd_mode == BFD_MODE_TYPE_SBFD_INIT){ + sbfd_initiator_state_handler(bfd, PTM_BFD_UP); + if(bfd->xmt_TO != bfd->timers.desired_min_tx) + { + bfd->xmt_TO = bfd->timers.desired_min_tx; + //reset xmt timer TO after UP + ptm_bfd_start_xmt_timer(bfd, false); + } + + bfd->detect_TO = bfd->detect_mult * bfd->xmt_TO; + sbfd_init_recvtimer_update(bfd); + + if (bfd->polling && BFD_GETFBIT(cp->flags)) { + /* Disable polling. */ + bfd->polling = 0; + /* Start using our new timers. */ + bfd->cur_timers.desired_min_tx = bfd->timers.desired_min_tx; + bfd->cur_timers.required_min_rx = bfd->timers.required_min_rx; + } + + return ; + } + /* State switch from section 6.2. */ bs_state_handler(bfd, BFD_GETSTATE(cp->flags)); From 533940e664ceb8817db5e0003961017d954029a5 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 13:22:03 +0000 Subject: [PATCH 14/21] bfdd: add bfdname info when notify bfd status to PTM clients such as pathd use bfdname as a key to track sbfd state Signed-off-by: wumu.zsl --- bfdd/ptm_adapter.c | 60 +++++++++++++++++++++++++++++++++++++++------- lib/bfd.c | 32 ++++++++++++++++++++++--- lib/bfd.h | 7 ++++++ 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index f6ebefb7becb..398bf59fdd33 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -64,6 +64,7 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id); static void bfdd_client_register(struct stream *msg); static void bfdd_client_deregister(struct stream *msg); + /* * Functions */ @@ -134,7 +135,11 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) /* Change state and notify peer. */ bs->ses_state = PTM_BFD_DOWN; bs->local_diag = diag; - ptm_bfd_snd(bs, 0); + + if (bs->bfd_mode == BFD_MODE_TYPE_BFD) + { + ptm_bfd_snd(bs, 0); + } /* Session reached refcount == 0, lets delete it. */ if (bs->refcount == 0) { @@ -200,6 +205,8 @@ int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state) * - 16 bytes: ipv6 * - c: prefix length * - c: cbit + * - c: bfd name len + * - Xbytes: bfd name * * Commands: ZEBRA_BFD_DEST_REPLAY * @@ -238,9 +245,18 @@ int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state) case PTM_BFD_DOWN: case PTM_BFD_INIT: - stream_putl(msg, BFD_STATUS_DOWN); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN|BFD_SESS_FLAG_REM_ADMIN_DOWN)) + { + stream_putl(msg, BFD_STATUS_ADMIN_DOWN); + } + else + { + stream_putl(msg, BFD_STATUS_DOWN); + } + break; + case PTM_BFD_DEL: + stream_putl(msg, BFD_STATUS_DEL); break; - default: stream_putl(msg, BFD_STATUS_UNKNOWN); break; @@ -251,6 +267,9 @@ int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state) stream_putc(msg, bs->remote_cbit); + stream_putc(msg, strlen(bs->bfd_name)); + stream_put(msg, bs->bfd_name, strlen(bs->bfd_name)); + /* Write packet size. */ stream_putw_at(msg, 0, stream_get_endp(msg)); @@ -330,6 +349,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, * New format: * - header: Command, VRF * - l: pid + * - c bfd name len + * - X bytes: bfd name * - w: family * - AF_INET: * - l: destination IPv4 address @@ -363,6 +384,12 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, *pc = pc_new(pid); + STREAM_GETC(msg, bpc->bfd_name_len); + if (bpc->bfd_name_len) { + STREAM_GET(bpc->bfd_name, msg, bpc->bfd_name_len); + bpc->bfd_name[bpc->bfd_name_len] = 0; + } + /* Register/update peer information. */ _ptm_msg_read_address(msg, &bpc->bpc_peer); @@ -468,6 +495,17 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) debug_printbpc(&bpc, "ptm-add-dest: register peer"); + /* sbfd case: pathd register to a sbfd session. */ + if (bpc.bfd_name[0] != 0) + { + bs = bfd_session_get_by_name((const char *)bpc.bfd_name); + if (bs != NULL) + { + ptm_bfd_notify(bs, bs->ses_state); + } + return; + } + /* Find or start new BFD session. */ bs = bs_peer_find(&bpc); if (bs == NULL) { @@ -503,7 +541,7 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) { struct ptm_client *pc; struct ptm_client_notification *pcn; - struct bfd_session *bs; + struct bfd_session *bs = NULL; struct bfd_peer_cfg bpc; /* Read the client context and peer data. */ @@ -513,11 +551,17 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) debug_printbpc(&bpc, "ptm-del-dest: deregister peer"); /* Find or start new BFD session. */ - bs = bs_peer_find(&bpc); + if(bpc.bfd_name[0]) + bs = bfd_session_get_by_name((const char *)bpc.bfd_name); if (bs == NULL) { - if (bglobal.debug_zebra) - zlog_debug("ptm-del-dest: failed to find BFD session"); - return; + bs = bs_peer_find(&bpc); + if (bs == NULL) { + if (bglobal.debug_zebra) + zlog_debug("ptm-del-dest: failed to find BFD session"); + return; + } + + SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); } /* Unregister client peer notification. */ diff --git a/lib/bfd.c b/lib/bfd.c index bc4b1c5b51e6..7c0ccdae2c02 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -18,10 +18,12 @@ #include "table.h" #include "vty.h" #include "bfd.h" +#include "bfdd/bfd.h" DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info"); DEFINE_MTYPE_STATIC(LIB, BFD_SOURCE, "BFD source cache"); +DEFINE_HOOK(sbfd_state_change_hook, (char *bfd_name, int state),(bfd_name, state)); /** * BFD protocol integration configuration. */ @@ -142,12 +144,13 @@ static void bfd_source_cache_put(struct bfd_session_params *session); */ static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, struct prefix *sp, int *status, - int *remote_cbit, vrf_id_t vrf_id) + int *remote_cbit, vrf_id_t vrf_id, char *bfd_name) { unsigned int ifindex; struct interface *ifp = NULL; int plen; int local_remote_cbit; + uint8_t bfd_name_len = 0; /* * If the ifindex lookup fails the @@ -194,6 +197,13 @@ static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, STREAM_GETC(s, local_remote_cbit); if (remote_cbit) *remote_cbit = local_remote_cbit; + + STREAM_GETC(s, bfd_name_len); + if(bfd_name_len) { + STREAM_GET(bfd_name, s, bfd_name_len); + *(bfd_name+bfd_name_len) = 0; + } + return ifp; stream_failure: @@ -218,6 +228,8 @@ const char *bfd_get_status_str(int status) return "Up"; case BFD_STATUS_ADMIN_DOWN: return "Admin Down"; + case BFD_STATUS_DEL: + return "Del"; case BFD_STATUS_UNKNOWN: default: return "Unknown"; @@ -319,6 +331,10 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) zclient_create_header(s, args->command, args->vrf_id); stream_putl(s, getpid()); + stream_putc(s, args->bfd_name[0] ? strlen(args->bfd_name) : 0); + if (args->bfd_name[0]) + stream_put(s, args->bfd_name, strlen(args->bfd_name)); + /* Encode destination address. */ stream_putw(s, args->family); addrlen = (args->family == AF_INET) ? sizeof(struct in_addr) @@ -365,6 +381,7 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) stream_putc(s, args->profilelen); if (args->profilelen) stream_put(s, args->profile, args->profilelen); + #else /* PTM BFD */ /* Encode timers if this is a registration message. */ if (args->command != ZEBRA_BFD_DEST_DEREGISTER) { @@ -742,6 +759,7 @@ void bfd_sess_install(struct bfd_session_params *bsp) event_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); } + void bfd_sess_uninstall(struct bfd_session_params *bsp) { bsp->lastev = BSE_UNINSTALL; @@ -918,6 +936,7 @@ int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) struct prefix dp; struct prefix sp; char ifstr[128], cbitstr[32]; + char bfd_name[BFD_NAME_SIZE+1] = {0}; if (!zclient->bfd_integration) return 0; @@ -926,8 +945,7 @@ int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) if (bsglobal.shutting_down) return 0; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, - vrf_id); + ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, vrf_id, bfd_name); /* * When interface lookup fails or an invalid stream is read, we must * not proceed otherwise it will trigger an assertion while checking @@ -966,7 +984,15 @@ int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) /* Cache current time to avoid multiple monotime clock calls. */ now = monotime(NULL); + + if (bfd_name[0]) + { + hook_call(sbfd_state_change_hook, bfd_name, state); + if (bsglobal.debugging) + zlog_debug("%s: sessions updated: %s", __func__, bfd_name); + return 0; + } /* Notify all matching sessions about update. */ TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) { /* Skip not installed entries. */ diff --git a/lib/bfd.h b/lib/bfd.h index 99790f96a54b..fa8ec2df5f20 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -23,9 +23,12 @@ extern "C" { #define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */ #define BFD_STATUS_UP (1 << 2) /* BFD session status is up */ #define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */ +#define BFD_STATUS_DEL (1 << 4) /* BFD session is deleted, reserved for sbfd*/ #define BFD_PROFILE_NAME_LEN 64 +#define BFD_NAME_SIZE 255 + const char *bfd_get_status_str(int status); extern void bfd_client_sendmsg(struct zclient *zclient, int command, @@ -409,6 +412,8 @@ struct bfd_session_arg { uint32_t min_tx; /** Detection multiplier. */ uint32_t detection_multiplier; + /* bfd session name*/ + char bfd_name[BFD_NAME_SIZE +1]; }; /** @@ -458,6 +463,8 @@ extern bool bfd_protocol_integration_shutting_down(void); extern int bfd_nht_update(const struct prefix *match, const struct zapi_route *route); +DECLARE_HOOK(sbfd_state_change_hook, (char *bfd_name, int state,int remote_cbit),(bfd_name, state)); + extern bool bfd_session_is_down(const struct bfd_session_params *session); #ifdef __cplusplus From 3da528efb61b183b5f76eb651b49ee0517c77cc9 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 25 Nov 2024 13:27:52 +0000 Subject: [PATCH 15/21] bfdd: enable pathd to recv BFD state message Signed-off-by: wumu.zsl --- bfdd/bfd.c | 10 ++++++++-- zebra/zebra_ptm.h | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 068d735f6839..cba0bcc71ca8 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -395,6 +395,9 @@ int bfd_session_enable(struct bfd_session *bs) if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE) == 0) { if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO) { + /*enable receive echo response*/ + bfd_set_echo(bs, true); + bfd_echo_recvtimer_update(bs); ptm_bfd_start_xmt_timer(bs, true); } @@ -838,9 +841,10 @@ void bfd_echo_recvtimer_cb(struct event *t) { struct bfd_session *bs = EVENT_ARG(t); - if (bglobal.debug_peer_event) + if (bglobal.debug_peer_event){ zlog_debug("%s: time-out bfd: [%s] bfd'state is %s", __func__, bs_to_string(bs), state_list[bs->ses_state].str); + } switch (bs->ses_state) { case PTM_BFD_INIT: @@ -870,9 +874,10 @@ void sbfd_echo_recvtimer_cb(struct event *t) { struct bfd_session *bs = EVENT_ARG(t); - if (bglobal.debug_peer_event) + if (bglobal.debug_peer_event){ zlog_debug("%s: time-out bfd: [%s] bfd'state is %s", __func__, bs_to_string(bs), state_list[bs->ses_state].str); + } switch (bs->ses_state) { case PTM_BFD_INIT: @@ -2352,6 +2357,7 @@ static int bfd_vrf_new(struct vrf *vrf) bvrf->bg_mhop6 = -1; bvrf->bg_echo = -1; bvrf->bg_echov6 = -1; + bvrf->bg_initv6 = -1; return 0; } diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 20a53e2fea46..af54aff1edd6 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -53,7 +53,9 @@ struct zebra_ptm_cb { (protocol) == ZEBRA_ROUTE_OSPF6 || (protocol) == ZEBRA_ROUTE_ISIS || \ (protocol) == ZEBRA_ROUTE_PIM || \ (protocol) == ZEBRA_ROUTE_OPENFABRIC || \ - (protocol) == ZEBRA_ROUTE_STATIC || (protocol) == ZEBRA_ROUTE_RIP) + (protocol) == ZEBRA_ROUTE_STATIC || (protocol) == ZEBRA_ROUTE_RIP || \ + (protocol) == ZEBRA_ROUTE_SRTE) + void zebra_ptm_init(void); void zebra_ptm_finish(void); From 07332d97a5dbb96ede6f50e6f64cc048aa15d877 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Wed, 27 Nov 2024 11:32:00 +0000 Subject: [PATCH 16/21] bfdd: add some code comments Signed-off-by: wumu.zsl --- bfdd/bfd.h | 1 - bfdd/bfd_packet.c | 18 +++++++++++++++--- bfdd/bfdd_nb_config.c | 2 +- bfdd/ptm_adapter.c | 3 --- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index bfc85ff89dbf..d2abddc9d963 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -434,7 +434,6 @@ struct sbfd_reflector{ #define PTM_BFD_DOWN 1 #define PTM_BFD_INIT 2 #define PTM_BFD_UP 3 -#define PTM_BFD_DEL 4 /* Various constants */ diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index cf3819bfbec2..7c0eab2d64ea 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -1040,7 +1040,7 @@ void bfd_recv_cb(struct event *t) else bfd->remote_cbit = 0; - /* The sender handle SBFD init session. */ + /* The initiator handle SBFD reflect packet. */ if (bfd->bfd_mode == BFD_MODE_TYPE_SBFD_INIT){ sbfd_initiator_state_handler(bfd, PTM_BFD_UP); if(bfd->xmt_TO != bfd->timers.desired_min_tx) @@ -1507,8 +1507,6 @@ int bp_peer_socket(const struct bfd_session *bs) sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr)); - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) - sin.sin_addr.s_addr = INADDR_ANY; pcount = 0; do { @@ -1876,6 +1874,7 @@ int _ptm_sbfd_init_send(struct bfd_session *bfd, const void *data, size_t datale local = bfd->key.local; peer = bfd->key.peer; + /*SBFD Control pkt dst port should be 7784, src port can be any but NOT 7784 according to RFC7781 */ if (bp_raw_sbfd_red_send(sd, (uint8_t *)data, datalen, bfd->key.family, &bfd->out_sip6, &local, &peer, BFD_DEFDESTPORT, BFD_DEF_SBFD_DEST_PORT, seg_num, segment_list) < 0) { @@ -1921,6 +1920,7 @@ int _ptm_sbfd_echo_send(struct bfd_session *bfd, const void *data, size_t datale local = bfd->key.local; peer = bfd->key.peer; + /*SBFD echo pkt dst port should use BFD Echo port 3785, src port can be any according to RFC7781*/ if (bp_raw_sbfd_red_send(sd, (uint8_t *)data, datalen, bfd->key.family, &bfd->out_sip6, &local , &peer, BFD_DEF_ECHO_PORT, BFD_DEF_ECHO_PORT, seg_num, segment_list) < 0) { @@ -2034,12 +2034,24 @@ static int ptm_bfd_reflector_process_init_packet(struct bfd_vrf_global *bvrf, in return 0; } cp = (struct bfd_pkt *)(msgbuf); + if(!CHECK_FLAG(cp->flags, BFD_DEMANDBIT)){ + /*Control Packet from SBFDInitiator should have Demand bit set to 1 according to RFC7880*/ + return 0; + } + sr = sbfd_discr_lookup(ntohl(cp->discrs.remote_discr)); if(sr) { uint32_t temp = cp->discrs.my_discr; cp->discrs.my_discr = cp->discrs.remote_discr; cp->discrs.remote_discr = temp; + UNSET_FLAG(cp->flags, BFD_DEMANDBIT); + BFD_SETSTATE(cp->flags, PTM_BFD_UP); + if(CHECK_FLAG(cp->flags, BFD_PBIT)) + { + UNSET_FLAG(cp->flags, BFD_PBIT); + SET_FLAG(cp->flags, BFD_FBIT); + } sa = (struct sockaddr *)&peer.sa_sin6; diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index b41523fe895b..30102146f749 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -384,7 +384,7 @@ static int bfd_session_destroy(enum nb_event event, zlog_info("bfd_session_destroy: %s", bs_to_string(bs)); if (bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bfd_mode == BFD_MODE_TYPE_SBFD_INIT){ - ptm_bfd_notify(bs, PTM_BFD_DEL); + ptm_bfd_notify(bs, PTM_BFD_DOWN); } bfd_session_free(bs); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 398bf59fdd33..20dd926c322d 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -254,9 +254,6 @@ int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state) stream_putl(msg, BFD_STATUS_DOWN); } break; - case PTM_BFD_DEL: - stream_putl(msg, BFD_STATUS_DEL); - break; default: stream_putl(msg, BFD_STATUS_UNKNOWN); break; From 6daa1eea198143de879f416c4c104bda00e072ff Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Thu, 28 Nov 2024 07:20:17 +0000 Subject: [PATCH 17/21] bfdd: sbfd Initiator support multihop session Signed-off-by: wumu.zsl --- bfdd/bfd_packet.c | 2 +- bfdd/bfdd_nb_config.c | 7 ++++--- bfdd/bfdd_vty.c | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 7c0eab2d64ea..1373cb8c96d4 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -1876,7 +1876,7 @@ int _ptm_sbfd_init_send(struct bfd_session *bfd, const void *data, size_t datale /*SBFD Control pkt dst port should be 7784, src port can be any but NOT 7784 according to RFC7781 */ if (bp_raw_sbfd_red_send(sd, (uint8_t *)data, datalen, bfd->key.family, &bfd->out_sip6, &local, &peer, - BFD_DEFDESTPORT, BFD_DEF_SBFD_DEST_PORT, seg_num, segment_list) < 0) + BFD_DEF_MHOP_DEST_PORT, BFD_DEF_SBFD_DEST_PORT, seg_num, segment_list) < 0) { if(bfd->stats.tx_fail_pkt <= 1){ char dst[INET6_ADDRSTRLEN] = {0}; diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 30102146f749..767f8387abc3 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -301,8 +301,9 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop, uint32 /* Set configuration flags. */ bs->refcount = 1; SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); - // if (mhop) - // SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (mhop) + SET_FLAG(bs->flags, BFD_SESS_FLAG_MH); + if (bs->key.family == AF_INET6) SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); @@ -1237,7 +1238,7 @@ int bfdd_bfd_sessions_srte_sbfd_source_ipv6_destroy( */ int bfdd_bfd_sessions_srte_sbfd_init_create(struct nb_cb_create_args *args) { - return bfd_session_create(args, false, BFD_MODE_TYPE_SBFD_INIT); + return bfd_session_create(args, true, BFD_MODE_TYPE_SBFD_INIT); } int bfdd_bfd_sessions_srte_sbfd_init_destroy(struct nb_cb_destroy_args *args) diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 4a5e2ba34e01..9b04a2b501b3 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -91,9 +91,10 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\tpeer %s", inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf))); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - vty_out(vty, " multihop"); + if (bs->bfd_mode == BFD_MODE_TYPE_BFD){ + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + vty_out(vty, " multihop"); + } if (bs->bfd_mode == BFD_MODE_TYPE_SBFD_ECHO || bs->bfd_mode == BFD_MODE_TYPE_SBFD_INIT) vty_out(vty, " bfd-mode %s", bfd_mode_type_to_string(bs->bfd_mode)); From 35dc4a40ef22b6ecd8a9b3f0244185c79399a7f9 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Fri, 29 Nov 2024 03:28:13 +0000 Subject: [PATCH 18/21] doc: add sbfd doc Signed-off-by: wumu.zsl --- doc/user/sbfd.rst | 380 +++++++++++++++++++++++++++++++++++++++++++++ doc/user/subdir.am | 1 + 2 files changed, 381 insertions(+) create mode 100644 doc/user/sbfd.rst diff --git a/doc/user/sbfd.rst b/doc/user/sbfd.rst new file mode 100644 index 000000000000..3825bdd61732 --- /dev/null +++ b/doc/user/sbfd.rst @@ -0,0 +1,380 @@ +.. _sbfd: + +**** +SBFD +**** + +:abbr:`SBFD (Seamless Bidirectional Forwarding Detection)` is: + + Seamless Bidirectional Forwarding Detection, a simplified mechanism for using BFD with a large + proportion of negotiation aspects eliminated, thus providing benefits + such as quick provisioning, as well as improved control and + flexibility for network nodes initiating path monitoring. + + -- :rfc:`7880` + +It is described and extended by the following RFCs: + +* :rfc:`7880` +* :rfc:`7881` + +.. _sbfd-sate-machine: + +SBFD state machine +================== + +SBFD takes the same data packet formart as BFD, but with a much simpler state machine. +According to RFC7880, SBFD has a statelss SBFDReflector and a stateful SBFDInitiator with the state machine as below: +:: + + +--+ + ADMIN DOWN, | | + TIMER | V + +------+ UP +------+ + | |-------------------->| |----+ + | DOWN | | UP | | UP + | |<--------------------| |<---+ + +------+ ADMIN DOWN, +------+ + TIMER + + Figure 1: SBFDInitiator Finite State Machine + +* If SBFDInitiator doesn't receive the response packet in time, session is DOWN. +* If SBFDInitiator receives the response packet in time: reponse state is ADMINDOWN, session goes DOWN; reponse state is UP, session goes UP. + +.. note:: + + SBFDReflector is stateless, it just transmit a packet in response to a received S-BFD packet having a valid S-BFD Discriminator in the Your Discriminator field. + + +.. _sbfd-extention: + +SBFD extension - SRv6 encapsulation +=================================== + +SBFDInitiator periodically send packets to monitor the connection to SBFDReflector. We set up an SBFD connection between the source and the destination node of a path, +with the source node serving as Initiator and the destination node as Reflector. The communicated SBFD packets should also follow every exact hop in the path, +from the source to the destination, which could be achieved by segment routing. This requirement extends the node verification to the path verification. +In the following example, we set up a sbfd session to monitor the path A-B-D (all nodes in the topo are SRv6 ready, which can decap and forward SRv6 packets). + +:: + + +------------C-----------+ + / \ + A---------------B---------------D + ^ ^ ^ + | | | + End: 100::A End: 100::B End: 100::D + Loopback: 200::A Loopback: 200::D + BFD Discrim: 123 BFD Discrim: 456 + + +A is the SBFDInitiator, and D is the SBFDReflector, A will trasmit the SBFD packet to B as the format: + +:: + IPv6(src="200::A", dst="100::B", nh=43)/IPv6ExtHdrSegmentRouting(addresses=["100::D"], nh=41, segleft=1)/IPv6(src="200::A", dst="200::D")/UDP(dport=7784)/BFD(my_dis=123, your_disc=456, state=UP) + + +Upon receiving the packet, B will take the Srv6 End action since the dst ip 100::B is the End address, B will the shift the dst address according to Srv6 spec, then trasmit the SBFD packet to D as the format: + +:: + IPv6(src="200::A", dst="100::D", nh=41)/IPv6(src="200::A", dst="200::D")/UDP(dport=7784)/BFD(my_dis=123, your_disc=456, state=UP) + + +After D receive the packet, It will decap the outer IPv6 header since the dst ip 100::D is the End address, the decaped packet is: + +:: + IPv6(src="200::A", dst="200::D")/UDP(dport=7784)/BFD(my_dis=123, your_disc=456, state=UP) + + +This packet will be routed to kernel stack of D since its dst is 200::D. Then the SBFDReflector service on D will get the packet and Reflect it. The response packet will be: + +:: + IPv6(src="200::D", dst="200::A")/UDP(sport=7784)/BFD(my_dis=456, your_disc=123, state=UP) + + +This packet will be routed in the topo according to the dst ip 200::A, it will go back to A by D-B-A or D-C-A in this case. + + + + In this example, Command used to configure the SBFDInitiator on A is: + +.. clicmd:: peer 200::D bfd-mode sbfd-init bfd-name a-b-d local-address 200::A remote-discr 456 encap-type SRv6 encap-data 100::B,100::D source-ipv6 200::A + + + Command used to configure the SBFDReflector on D is: + +.. clicmd:: sbfd reflector source-address 200::D discriminator 456 + + +.. _sbfd-echo: + +Echo SBFD with SRv6 encapsulation +================================= + +The SBFD Initiator-Reflector mode requires the configuration on both source and destination nodes. It can not work if the remote node has no SBD feature supported, especial on some third-party devices. +The Echo SBFD can solve this kind of deployment issue since it only requires the configuration on source node. +For example, we use Echo SBFD session to protect Srv6 path: A-B-D + +:: + + +------------C-----------+ + / \ + A---------------B---------------D + ^ ^ ^ + | | | + End: 100::A End: 100::B End: 100::D + Loopback: 200::A Loopback: 200::D + BFD Discrim: 123 + + +A is also the SBFDInitiator, and B, C, D is Srv6 ready nodes, A will trasmit the SBFD packet to B as the format: + +:: + IPv6(src="200::A", dst="100::B", nh=43)/IPv6ExtHdrSegmentRouting(addresses=["100::D"], nh=41, segleft=1)/IPv6(src="200::A", dst="200::A")/UDP(dport=3785)/BFD(my_dis=123, your_disc=123, state=UP) + + +Upon receiving the packet, B will take the Srv6 End action since the dst ip 100::B is the End address, B will the shift the dst address according to Srv6 spec, then trasmit the SBFD packet to D as the format: + +:: + IPv6(src="200::A", dst="100::D", nh=41)/IPv6(src="200::A", dst="200::A")/UDP(dport=3785)/BFD(my_dis=123, your_disc=123, state=UP) + + +After D receive the packet, It will decap the outer IPv6 header since the dst ip 100::D is the End address, the decaped packet is: + +:: + IPv6(src="200::A", dst="200::A")/UDP(dport=3785)/BFD(my_dis=123, your_disc=123, state=UP) + + +This packet will be routed in the topo according to the dst ip 200::A, it will go back to A by D-B-A or D-C-A in this case. + + + + In this example, Command used to configure the SBFDInitiator on A is: + +.. clicmd:: peer 200::A bfd-mode sbfd-echo bfd-name a-b-d local-address 200::A encap-type SRv6 encap-data 100::B,100::D source-ipv6 200::A + + + no confiuration needed on D. + + +.. _sbfd-normal: + +normal SBFD with no SRv6 encapsulation +====================================== + +We can also configure a SBFD Initiator-Reflector session based on simple IPv6/IPv4 packet, no Srv6 involved in this case. + +:: + + +------------C-----------+ + / \ + A---------------B---------------D + ^ ^ ^ + | | | + Loopback: 200::A Loopback: 200::D + BFD Discrim: 123 BFD Discrim: 456 + + + +A is the SBFDInitiator, and D is the SBFDReflector, A will trasmit the SBFD packet to B or C as the format: + +:: + IPv6(src="200::A", dst="200::D")/UDP(dport=7784)/BFD(my_dis=123, your_disc=456, state=UP) + + +Upon receiving the packet, B/C will route the packet to D according to the dst ip 200::D. + +After D receive the packet, packet will be sent to kernel stack of D since its dst is 200::D. Then the SBFDReflector service on D will get the packet and reflect it. The response packet will be: + +:: + IPv6(src="200::D", dst="200::A")/UDP(sport=7784)/BFD(my_dis=456, your_disc=123, state=UP) + + +This packet will be routed in the topo according to the dst ip 200::A, it will go back to A by D-B-A or D-C-A in this case. + + + In this example, Command used to configure the SBFDInitiator on A is: + +.. clicmd:: peer 200::D bfd-mode sbfd-init bfd-name a-d local-address 200::A remote-discr 456 + + + Command used to configure the SBFDReflector on D is: + +.. clicmd:: sbfd reflector source-address 200::D discriminator 456 + + +.. note:: + + Currently some features are not yet implemented: + 1) SBFD in IPv4 packet + 2) the ADMIN DOWN logic + 3) SBFD echo function in a initiator session + + +.. _sbfd-show: + +show commond +============ + +The exsiting bfd show command is also appliable to SBFD sessions, for example: +This command will show all the BFD and SBFD sessions in the bfdd: + +.. clicmd:: show bfd peers + + +:: + BFD Peers: + peer 200::D bfd-mode sbfd-init bfd-name a-d local-address 200::A remote-discr 456 vrf default + ID: 1421669725 + Remote ID: 456 + Active mode + Minimum TTL: 254 + Status: up + Uptime: 5 hour(s), 48 minute(s), 39 second(s) + Diagnostics: ok + Remote diagnostics: ok + Peer Type: sbfd initiator + Local timers: + Detect-multiplier: 3 + Receive interval: 300ms + Transmission interval: 1000ms + Echo receive interval: 50ms + Echo transmission interval: disabled + Remote timers: + Detect-multiplier: - + Receive interval: - + Transmission interval: - + Echo receive interval: - + +This command will show all the BFD and SBFD session packet counters: + +.. clicmd:: show bfd peers counters + +:: + BFD Peers: + peer 200::A bfd-mode sbfd-echo bfd-name a-b-d local-address 200::A encap-type SRv6 encap-data 100::B,100::D source-ipv6 200::A + Control packet input: 0 packets + Control packet output: 0 packets + Echo packet input: 23807 packets + Echo packet output: 23807 packets + Session up events: 1 + Session down events: 0 + Zebra notifications: 1 + Tx fail packet: 0 + + peer 200::D bfd-mode sbfd-init bfd-name a-d local-address 200::A remote-discr 456 vrf default + Control packet input: 25289 packets + Control packet output: 51812 packets + Echo packet input: 0 packets + Echo packet output: 0 packets + Session up events: 5 + Session down events: 4 + Zebra notifications: 9 + Tx fail packet: 0 + + +we also implemented a new show command to display SBFD session only, the bfd-name is the key to search the sessioon. + +.. clicmd:: show bfd bfd-name a-b-d + +:: + BFD Peers: + peer 200::A bfd-mode sbfd-echo bfd-name a-b-d local-address 200::A encap-type SRv6 encap-data 100::B,100::D source-ipv6 200::A + ID: 123 + Remote ID: 123 + Active mode + Status: up + Uptime: 5 hour(s), 39 minute(s), 34 second(s) + Diagnostics: ok + Remote diagnostics: ok + Peer Type: echo + Local timers: + Detect-multiplier: 3 + Receive interval: 300ms + Transmission interval: 300ms + Echo receive interval: 300ms + Echo transmission interval: 1000ms + Remote timers: + Detect-multiplier: - + Receive interval: - + Transmission interval: - + Echo receive interval: - + + +.. _sbfd-implement: + +implementation +=============== + +Some considerations when implementing sbfd. + + + +.. _sbfd-implement-coexist: + +SBFD Co-exist with BFD +-------------------------- + +Both SBFD and Classical BFD have their unique discriminator, SBFD can co-exist with BFD since they sharing a same discriminator pool in bfdd. +Also in bfdd SBFD and BFD can share most code logic, SBFD packet and BFD packet are demultiplexed by different discriminators. + + +.. _sbfd-implement-bfdname: + +SBFD name +--------- + +We introduced a bfd-name for every sbfd session. A unique bfd-name can be used to identify a sbfd session quickly. This is quite useful in our Srv6 deployment for path protection case. +In the previous example, if use the sbfd session to protect the path A-B-D, we would assign the name 'path-a-b-d' or 'a-b-d' to the session. + +Meanwhile bfdd will notify the sbfd status to the Pathd, we should add the bfd-name field in PTM bfd notify message ZEBRA_BFD_DEST_REPLAY: + +:: + * Message format: + * - header: command, vrf + * - l: interface index + * - c: family + * - AF_INET: + * - 4 bytes: ipv4 + * - AF_INET6: + * - 16 bytes: ipv6 + * - c: prefix length + * - l: bfd status + * - c: family + * - AF_INET: + * - 4 bytes: ipv4 + * - AF_INET6: + * - 16 bytes: ipv6 + * - c: prefix length + * - c: cbit + * - c: bfd name len <---- new field + * - Xbytes: bfd name <---- new field + * + * Commands: ZEBRA_BFD_DEST_REPLAY + * + * q(64), l(32), w(16), c(8) + + + +.. _sbfd-implement-port: + +SBFD UDP port +--------- + +According to RFC7881, SBFD Control packet dst port should be 7784, src port can be any but NOT 7784. In our implementation, the UDP ports in packet are set as: + +:: + UDP(sport=4784, dport=7784)/BFD() + +we choose the 4784 as the source port, so the reflected packet will take 4784 as the dst port, this is a local BFD_MULTI_HOP_PORT so the reflected packet can be handled by the existing bfd_recv_cb function. + + + +For echo SBFD with SRv6 encapsulation case, we re-use the BFD Echo port, the UDP ports in packet are set as: + +:: + UDP(sport=3785, dport=3785)/BFD() + + +we choose the 3785 as the source port, so the echo back packet will take 3785 as the dst port, this is a local BFD_DEF_ECHO_PORT so the packet can be handled by the existing bfd_recv_cb function. diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 395ce305fe94..e4e12788e70d 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -55,6 +55,7 @@ user_RSTFILES = \ doc/user/watchfrr.rst \ doc/user/wecmp_linkbw.rst \ doc/user/mgmtd.rst \ + doc/user/sbfd.rst \ # end EXTRA_DIST += \ From a6270ec02c2e5cd51a6486c4d6d38920cb95dfaa Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Wed, 18 Dec 2024 12:03:09 +0000 Subject: [PATCH 19/21] bfdd: Fix topo tests regression issue caused by SBFD code Signed-off-by: wumu.zsl --- bfdd/bfd.c | 9 +++++---- bfdd/bfdd_cli.c | 17 ++++------------- bfdd/ptm_adapter.c | 1 - 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index cba0bcc71ca8..51cdd01da18a 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -398,7 +398,8 @@ int bfd_session_enable(struct bfd_session *bs) /*enable receive echo response*/ bfd_set_echo(bs, true); - bfd_echo_recvtimer_update(bs); + bs->echo_detect_TO = (bs->remote_detect_mult * bs->echo_xmt_TO); + sbfd_echo_recvtimer_update(bs); ptm_bfd_start_xmt_timer(bs, true); } else @@ -2156,7 +2157,7 @@ static int _bfd_session_next(struct hash_bucket *hb, void *arg) /* Previous entry signaled stop. */ if (bsi->bsi_stop == 1) { /* Match the single/multi hop sessions. */ - if ((bs->key.mhop != bsi->bsi_mhop) && (bs->bfd_mode != bsi->bsi_bfdmode)) + if ((bs->key.mhop != bsi->bsi_mhop) || (bs->bfd_mode != bsi->bsi_bfdmode)) return HASHWALK_CONTINUE; bsi->bsi_bs = bs; @@ -2391,7 +2392,7 @@ static int bfd_vrf_enable(struct vrf *vrf) bvrf->bg_shop6 = bp_udp6_shop(vrf); if (bvrf->bg_mhop6 == -1) bvrf->bg_mhop6 = bp_udp6_mhop(vrf); - if (!bvrf->bg_initv6) + if (bvrf->bg_initv6 == -1) bvrf->bg_initv6 = bp_initv6_socket(vrf); if (bvrf->bg_ev[0] == NULL && bvrf->bg_shop != -1) @@ -2406,7 +2407,7 @@ static int bfd_vrf_enable(struct vrf *vrf) if (bvrf->bg_ev[3] == NULL && bvrf->bg_mhop6 != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, &bvrf->bg_ev[3]); - if (!bvrf->bg_ev[6] && bvrf->bg_initv6 != -1) + if (bvrf->bg_ev[6] == NULL && bvrf->bg_initv6 != -1) event_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_initv6, &bvrf->bg_ev[6]); diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 1a03ed45bda1..31b58d65979b 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -271,7 +271,7 @@ DEFPY_YANG_NOSH( { int ret, slen; char value[32]; - char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32],xpath_bfdmode[XPATH_MAXLEN + 32]; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32]; if (!bfdname) { vty_out(vty,"%% ERROR: bfd name is required\n"); @@ -313,10 +313,6 @@ DEFPY_YANG_NOSH( snprintf(xpath_sl, sizeof(xpath_sl), "%s/dest-addr", xpath); nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, peer_str); - snprintf(xpath_bfdmode, sizeof(xpath_bfdmode), "%s/bfd-mode", xpath); - snprintf(value, sizeof(value), "%d", BFD_MODE_TYPE_SBFD_ECHO); - nb_cli_enqueue_change(vty, xpath_bfdmode, NB_OP_MODIFY, value); - /* Apply settings immediately. */ ret = nb_cli_apply_changes(vty, NULL); if (ret == CMD_SUCCESS) @@ -399,7 +395,7 @@ DEFPY_YANG_NOSH( { int ret, slen, peer_ver, local_ver; char value[32]; - char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32],xpath_bfdmode[XPATH_MAXLEN + 32],xpath_rd[XPATH_MAXLEN + 32]; + char xpath[XPATH_MAXLEN], xpath_sl[XPATH_MAXLEN + 32],xpath_rd[XPATH_MAXLEN + 32]; if (!bfdname) { vty_out(vty,"%% ERROR: bfd name is required\n"); @@ -449,10 +445,6 @@ DEFPY_YANG_NOSH( nb_cli_enqueue_change(vty, xpath_sl, NB_OP_MODIFY, source_ipv6_str); } - snprintf(xpath_bfdmode, sizeof(xpath_bfdmode), "%s/bfd-mode", xpath); - snprintf(value, sizeof(value), "%d", BFD_MODE_TYPE_SBFD_INIT); - nb_cli_enqueue_change(vty, xpath_bfdmode, NB_OP_MODIFY, value); - snprintf(xpath_rd, sizeof(xpath_rd), "%s/remote-discr", xpath); nb_cli_enqueue_change(vty, xpath_rd, NB_OP_MODIFY, discr_str); @@ -554,12 +546,11 @@ static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode, } 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 (yang_dnode_exists(dnode, "bfd-mode")) - vty_out(vty, " bfd-mode %s", _bfd_cli_bfd_mode_type_to_string(yang_dnode_get_uint32(dnode, "bfd-mode"))); - if (yang_dnode_exists(dnode, "source-addr")) vty_out(vty, " local-address %s", yang_dnode_get_string(dnode, "source-addr")); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 20dd926c322d..2387a7ab7d8f 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -558,7 +558,6 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) return; } - SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); } /* Unregister client peer notification. */ From dbcdd72215bc24c24a99a1cb7c231a15a1bf2b25 Mon Sep 17 00:00:00 2001 From: "wumu.zsl" Date: Mon, 6 Jan 2025 12:14:09 +0000 Subject: [PATCH 20/21] tests: add basic topotest cases for sbfd Initiator and Reflector Signed-off-by: wumu.zsl --- tests/topotests/sbfd_topo1/__init__.py | 0 tests/topotests/sbfd_topo1/r1/bfdd.conf | 7 + tests/topotests/sbfd_topo1/r1/zebra.conf | 7 + tests/topotests/sbfd_topo1/r2/bfdd.conf | 7 + tests/topotests/sbfd_topo1/r2/zebra.conf | 7 + tests/topotests/sbfd_topo1/sbfd_topo1.dot | 45 ++++ tests/topotests/sbfd_topo1/test_sbfd_topo1.py | 217 ++++++++++++++++++ 7 files changed, 290 insertions(+) create mode 100644 tests/topotests/sbfd_topo1/__init__.py create mode 100644 tests/topotests/sbfd_topo1/r1/bfdd.conf create mode 100644 tests/topotests/sbfd_topo1/r1/zebra.conf create mode 100644 tests/topotests/sbfd_topo1/r2/bfdd.conf create mode 100644 tests/topotests/sbfd_topo1/r2/zebra.conf create mode 100644 tests/topotests/sbfd_topo1/sbfd_topo1.dot create mode 100644 tests/topotests/sbfd_topo1/test_sbfd_topo1.py diff --git a/tests/topotests/sbfd_topo1/__init__.py b/tests/topotests/sbfd_topo1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/sbfd_topo1/r1/bfdd.conf b/tests/topotests/sbfd_topo1/r1/bfdd.conf new file mode 100644 index 000000000000..437f063d8f1a --- /dev/null +++ b/tests/topotests/sbfd_topo1/r1/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/sbfd_topo1/r1/zebra.conf b/tests/topotests/sbfd_topo1/r1/zebra.conf new file mode 100644 index 000000000000..5f19bd87aa2a --- /dev/null +++ b/tests/topotests/sbfd_topo1/r1/zebra.conf @@ -0,0 +1,7 @@ +ip forwarding +ipv6 forwarding +! + +interface r1-eth0 + ipv6 address 2001::10/64 +! diff --git a/tests/topotests/sbfd_topo1/r2/bfdd.conf b/tests/topotests/sbfd_topo1/r2/bfdd.conf new file mode 100644 index 000000000000..437f063d8f1a --- /dev/null +++ b/tests/topotests/sbfd_topo1/r2/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/sbfd_topo1/r2/zebra.conf b/tests/topotests/sbfd_topo1/r2/zebra.conf new file mode 100644 index 000000000000..0c6ee75f705d --- /dev/null +++ b/tests/topotests/sbfd_topo1/r2/zebra.conf @@ -0,0 +1,7 @@ +ip forwarding +ipv6 forwarding +! + +interface r2-eth0 + ipv6 address 2001::20/64 +! diff --git a/tests/topotests/sbfd_topo1/sbfd_topo1.dot b/tests/topotests/sbfd_topo1/sbfd_topo1.dot new file mode 100644 index 000000000000..437e8230ce20 --- /dev/null +++ b/tests/topotests/sbfd_topo1/sbfd_topo1.dot @@ -0,0 +1,45 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="template"; + + # Routers + r1 [ + shape=doubleoctagon, + label="A\nAS 100\n1.1.1.1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="B\nAS 200\n1.1.1.2", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + shape=oval, + label="s1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + + # Connections + r1 -- s1 [label="A-eth0"]; + r2 -- s1 [label="B-eth0"]; + +} diff --git a/tests/topotests/sbfd_topo1/test_sbfd_topo1.py b/tests/topotests/sbfd_topo1/test_sbfd_topo1.py new file mode 100644 index 000000000000..31ea05e595f7 --- /dev/null +++ b/tests/topotests/sbfd_topo1/test_sbfd_topo1.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python + +# +#