diff options
| author | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2021-03-24 09:39:55 -0300 | 
|---|---|---|
| committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2023-01-13 15:32:12 -0300 | 
| commit | 351ad684058412e4ac187692913a4ce150088d3f (patch) | |
| tree | 1c779e8507739f617749a5d240cae5e79d71df09 /staticd | |
| parent | 73df597f5ed7d71d690ef71eec5cb573f15d39ad (diff) | |
staticd: BFD integration northbound support
Implement all BFD integration northbound callbacks and integrate BFD
with `staticd` route installation procedure.
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
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 0000000000..dda0487139 --- /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 5935364d5a..68d9ba97b4 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 5c3030fcfa..96c9f8d9b7 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 4a3d9e17a4..cbb5b8234f 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 ed4cdc51ce..3595cc5644 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 71c3689be5..7082e8959d 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 cb36304473..316247adb3 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 bb0fc95bc2..022428281f 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  | 
