diff options
Diffstat (limited to 'staticd')
-rw-r--r-- | staticd/static_bfd.c | 219 | ||||
-rw-r--r-- | staticd/static_nb.c | 27 | ||||
-rw-r--r-- | staticd/static_nb.h | 7 | ||||
-rw-r--r-- | staticd/static_nb_config.c | 107 | ||||
-rw-r--r-- | staticd/static_routes.c | 4 | ||||
-rw-r--r-- | staticd/static_routes.h | 26 | ||||
-rw-r--r-- | staticd/static_zebra.c | 4 | ||||
-rw-r--r-- | staticd/subdir.am | 2 |
8 files changed, 396 insertions, 0 deletions
diff --git a/staticd/static_bfd.c b/staticd/static_bfd.c new file mode 100644 index 000000000..dda048713 --- /dev/null +++ b/staticd/static_bfd.c @@ -0,0 +1,219 @@ +/* + * Static daemon BFD integration. + * + * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/bfd.h" +#include "lib/printfrr.h" +#include "lib/srcdest_table.h" + +#include "staticd/static_routes.h" +#include "staticd/static_zebra.h" + +#include "lib/openbsd-queue.h" + +/* + * Next hop BFD monitoring settings. + */ +static void static_next_hop_bfd_change(struct static_nexthop *sn, + const struct bfd_session_status *bss) +{ + switch (bss->state) { + case BSS_UNKNOWN: + /* FALLTHROUGH: no known state yet. */ + case BSS_ADMIN_DOWN: + /* NOTHING: we or the remote end administratively shutdown. */ + break; + case BSS_DOWN: + /* Peer went down, remove this next hop. */ + zlog_info("%s: next hop is down, remove it from RIB", __func__); + sn->path_down = true; + static_zebra_route_add(sn->pn, true); + break; + case BSS_UP: + /* Peer is back up, add this next hop. */ + zlog_info("%s: next hop is up, add it to RIB", __func__); + sn->path_down = false; + static_zebra_route_add(sn->pn, true); + break; + } +} + +static void static_next_hop_bfd_updatecb( + __attribute__((unused)) struct bfd_session_params *bsp, + const struct bfd_session_status *bss, void *arg) +{ + static_next_hop_bfd_change(arg, bss); +} + +static inline int +static_next_hop_type_to_family(const struct static_nexthop *sn) +{ + switch (sn->type) { + case STATIC_IPV4_GATEWAY_IFNAME: + case STATIC_IPV6_GATEWAY_IFNAME: + case STATIC_IPV4_GATEWAY: + case STATIC_IPV6_GATEWAY: + if (sn->type == STATIC_IPV4_GATEWAY || + sn->type == STATIC_IPV4_GATEWAY_IFNAME) + return AF_INET; + else + return AF_INET6; + break; + case STATIC_IFNAME: + case STATIC_BLACKHOLE: + default: + zlog_err("%s: invalid next hop type", __func__); + break; + } + + return AF_UNSPEC; +} + +void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn, + const struct lyd_node *dnode) +{ + bool use_interface; + bool use_profile; + bool use_source; + bool onlink; + bool mhop; + int family; + struct ipaddr source; + + use_interface = false; + use_source = yang_dnode_exists(dnode, "./source"); + use_profile = yang_dnode_exists(dnode, "./profile"); + onlink = yang_dnode_exists(dnode, "../onlink") && + yang_dnode_get_bool(dnode, "../onlink"); + mhop = yang_dnode_get_bool(dnode, "./multi-hop"); + + + family = static_next_hop_type_to_family(sn); + if (family == AF_UNSPEC) + return; + + if (sn->type == STATIC_IPV4_GATEWAY_IFNAME || + sn->type == STATIC_IPV6_GATEWAY_IFNAME) + use_interface = true; + + /* Reconfigure or allocate new memory. */ + if (sn->bsp == NULL) + sn->bsp = bfd_sess_new(static_next_hop_bfd_updatecb, sn); + + /* Configure the session. */ + if (use_source) + yang_dnode_get_ip(&source, dnode, "./source"); + + if (onlink || mhop == false) + bfd_sess_set_auto_source(sn->bsp, false); + else + bfd_sess_set_auto_source(sn->bsp, !use_source); + + /* Configure the session.*/ + if (family == AF_INET) + bfd_sess_set_ipv4_addrs(sn->bsp, + use_source ? &source.ip._v4_addr : NULL, + &sn->addr.ipv4); + else if (family == AF_INET6) + bfd_sess_set_ipv6_addrs(sn->bsp, + use_source ? &source.ip._v6_addr : NULL, + &sn->addr.ipv6); + + bfd_sess_set_interface(sn->bsp, use_interface ? sn->ifname : NULL); + + bfd_sess_set_profile(sn->bsp, use_profile ? yang_dnode_get_string( + dnode, "./profile") + : NULL); + + bfd_sess_set_hop_count(sn->bsp, (onlink || mhop == false) ? 1 : 254); + + /* Install or update the session. */ + bfd_sess_install(sn->bsp); + + /* Update current path status. */ + sn->path_down = (bfd_sess_status(sn->bsp) != BSS_UP); +} + +void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn) +{ + bfd_sess_free(&sn->bsp); + + /* Reset path status. */ + sn->path_down = false; +} + +void static_next_hop_bfd_source(struct static_nexthop *sn, + const struct ipaddr *source) +{ + int family; + + if (sn->bsp == NULL) + return; + + family = static_next_hop_type_to_family(sn); + if (family == AF_UNSPEC) + return; + + bfd_sess_set_auto_source(sn->bsp, false); + if (family == AF_INET) + bfd_sess_set_ipv4_addrs(sn->bsp, &source->ip._v4_addr, + &sn->addr.ipv4); + else if (family == AF_INET6) + bfd_sess_set_ipv6_addrs(sn->bsp, &source->ip._v6_addr, + &sn->addr.ipv6); + + bfd_sess_install(sn->bsp); +} + +void static_next_hop_bfd_auto_source(struct static_nexthop *sn) +{ + if (sn->bsp == NULL) + return; + + bfd_sess_set_auto_source(sn->bsp, true); + bfd_sess_install(sn->bsp); +} + +void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop) +{ + if (sn->bsp == NULL) + return; + + bfd_sess_set_hop_count(sn->bsp, mhop ? 254 : 1); + bfd_sess_install(sn->bsp); +} + +void static_next_hop_bfd_profile(struct static_nexthop *sn, const char *name) +{ + if (sn->bsp == NULL) + return; + + bfd_sess_set_profile(sn->bsp, name); + bfd_sess_install(sn->bsp); +} + +void static_bfd_initialize(struct zclient *zc, struct thread_master *tm) +{ + /* Initialize BFD integration library. */ + bfd_protocol_integration_init(zc, tm); +} diff --git a/staticd/static_nb.c b/staticd/static_nb.c index 5935364d5..68d9ba97b 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -117,6 +117,33 @@ const struct frr_yang_module_info frr_staticd_info = { } }, { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring", + .cbs = { + .create = route_next_hop_bfd_create, + .destroy = route_next_hop_bfd_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/source", + .cbs = { + .modify = route_next_hop_bfd_source_modify, + .destroy = route_next_hop_bfd_source_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/multi-hop", + .cbs = { + .modify = route_next_hop_bfd_multi_hop_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/profile", + .cbs = { + .modify = route_next_hop_bfd_profile_modify, + .destroy = route_next_hop_bfd_profile_destroy, + } + }, + { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list", .cbs = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create, diff --git a/staticd/static_nb.h b/staticd/static_nb.h index 5c3030fcf..96c9f8d9b 100644 --- a/staticd/static_nb.h +++ b/staticd/static_nb.h @@ -63,6 +63,13 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy( struct nb_cb_destroy_args *args); +int route_next_hop_bfd_create(struct nb_cb_create_args *args); +int route_next_hop_bfd_destroy(struct nb_cb_destroy_args *args); +int route_next_hop_bfd_source_modify(struct nb_cb_modify_args *args); +int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args); +int route_next_hop_bfd_profile_modify(struct nb_cb_modify_args *args); +int route_next_hop_bfd_profile_destroy(struct nb_cb_destroy_args *args); +int route_next_hop_bfd_multi_hop_modify(struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy( diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 4a3d9e17a..cbb5b8234 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -750,6 +750,113 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa /* * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring + */ +int route_next_hop_bfd_create(struct nb_cb_create_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_monitor_enable(sn, args->dnode); + return NB_OK; +} + +int route_next_hop_bfd_destroy(struct nb_cb_destroy_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_monitor_disable(sn); + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/source + */ +int route_next_hop_bfd_source_modify(struct nb_cb_modify_args *args) +{ + struct static_nexthop *sn; + struct ipaddr source; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_ip(&source, args->dnode, NULL); + static_next_hop_bfd_source(sn, &source); + return NB_OK; +} + +int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_auto_source(sn); + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/multi-hop + */ +int route_next_hop_bfd_multi_hop_modify(struct nb_cb_modify_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_multi_hop(sn, + yang_dnode_get_bool(args->dnode, NULL)); + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/profile + */ +int route_next_hop_bfd_profile_modify(struct nb_cb_modify_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_profile(sn, + yang_dnode_get_string(args->dnode, NULL)); + + return NB_OK; +} + +int route_next_hop_bfd_profile_destroy(struct nb_cb_destroy_args *args) +{ + struct static_nexthop *sn; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + sn = nb_running_get_entry(args->dnode, NULL, true); + static_next_hop_bfd_profile(sn, NULL); + + return NB_OK; +} + +/* + * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list */ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create( diff --git a/staticd/static_routes.c b/staticd/static_routes.c index ed4cdc51c..3595cc564 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -276,6 +276,8 @@ struct static_nexthop *static_add_nexthop(struct static_path *pn, /* Make new static route structure. */ nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop)); + /* Copy back pointers. */ + nh->rn = rn; nh->pn = pn; nh->type = type; @@ -393,6 +395,8 @@ void static_delete_nexthop(struct static_nexthop *nh) struct route_node *rn = pn->rn; static_nexthop_list_del(&(pn->nexthop_list), nh); + /* Remove BFD session/configuration if any. */ + bfd_sess_free(&nh->bsp); if (nh->nh_vrf_id == VRF_UNKNOWN) goto EXIT; diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 71c3689be..7082e8959 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -20,6 +20,7 @@ #ifndef __STATIC_ROUTES_H__ #define __STATIC_ROUTES_H__ +#include "lib/bfd.h" #include "lib/mpls.h" #include "table.h" #include "memory.h" @@ -30,6 +31,8 @@ extern "C" { DECLARE_MGROUP(STATIC); +#include "staticd/static_vrf.h" + /* Static route label information */ struct static_nh_label { uint8_t num_labels; @@ -148,6 +151,13 @@ struct static_nexthop { /* SR-TE color */ uint32_t color; + + /** BFD integration data. */ + struct bfd_session_params *bsp; + /** Back pointer for route node. */ + struct route_node *rn; + /** Path connection status. */ + bool path_down; }; DECLARE_DLIST(static_nexthop_list, struct static_nexthop, list); @@ -218,6 +228,22 @@ extern void zebra_stable_node_cleanup(struct route_table *table, extern void static_get_nh_str(struct static_nexthop *nh, char *nexthop, size_t size); +/* + * BFD integration. + */ +extern void static_next_hop_bfd_source(struct static_nexthop *sn, + const struct ipaddr *source); +extern void static_next_hop_bfd_auto_source(struct static_nexthop *sn); +extern void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn, + const struct lyd_node *dnode); +extern void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn); +extern void static_next_hop_bfd_profile(struct static_nexthop *sn, + const char *name); +extern void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop); + +/** Call this function after zebra client initialization. */ +extern void static_bfd_initialize(struct zclient *zc, struct thread_master *tm); + #ifdef __cplusplus } #endif diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index cb3630447..316247adb 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -441,6 +441,9 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) api_nh = &api.nexthops[nh_num]; if (nh->nh_vrf_id == VRF_UNKNOWN) continue; + /* Skip next hop which peer is down. */ + if (nh->path_down) + continue; api_nh->vrf_id = nh->nh_vrf_id; if (nh->onlink) @@ -545,6 +548,7 @@ void static_zebra_init(void) zclient->zebra_connected = zebra_connected; static_nht_hash_init(static_nht_hash); + static_bfd_initialize(zclient, master); } /* static_zebra_stop used by tests/lib/test_grpc.cpp */ diff --git a/staticd/subdir.am b/staticd/subdir.am index bb0fc95bc..022428281 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -10,6 +10,7 @@ man8 += $(MANBUILD)/frr-staticd.8 endif staticd_libstatic_a_SOURCES = \ + staticd/static_bfd.c \ staticd/static_debug.c \ staticd/static_nht.c \ staticd/static_routes.c \ @@ -38,5 +39,6 @@ staticd_staticd_SOURCES = staticd/static_main.c staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP) nodist_staticd_staticd_SOURCES = \ + yang/frr-bfdd.yang.c \ yang/frr-staticd.yang.c \ # end |