diff options
Diffstat (limited to 'bgpd/bgp_bfd.c')
| -rw-r--r-- | bgpd/bgp_bfd.c | 59 | 
1 files changed, 47 insertions, 12 deletions
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 14ff5f2e11..add93d3a5f 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -26,6 +26,7 @@  #include "bgpd/bgp_debug.h"  #include "bgpd/bgp_vty.h"  #include "bgpd/bgp_packet.h" +#include "bgpd/bgp_network.h"  DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data"); @@ -53,14 +54,23 @@ static void bfd_session_status_update(struct bfd_session_params *bsp,  					peer->host);  			return;  		} -		peer->last_reset = PEER_DOWN_BFD_DOWN; -		/* rfc9384 */ -		if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) -			bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, -					BGP_NOTIFY_CEASE_BFD_DOWN); - -		BGP_EVENT_ADD(peer->connection, BGP_Stop); +		/* Once the BFD session is UP, and later BGP session is UP, +		 * BFD notices that peer->su_local changed, and BFD session goes down. +		 * We should trigger BGP session reset if BFD session is UP +		 * only when BGP session is UP already. +		 * Otherwise, we end up resetting BGP session when BFD session is UP, +		 * when the source address is changed, e.g. 0.0.0.0 -> 10.0.0.1. +		 */ +		if (bss->last_event > peer->uptime) { +			peer->last_reset = PEER_DOWN_BFD_DOWN; +			/* rfc9384 */ +			if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) +				bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, +						BGP_NOTIFY_CEASE_BFD_DOWN); + +			BGP_EVENT_ADD(peer->connection, BGP_Stop); +		}  	}  	if (bss->state == BSS_UP && bss->previous_state != BSS_UP && @@ -104,6 +114,10 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)  	 */  	gconfig = pg->conf; +	if (CHECK_FLAG(gconfig->flags, PEER_FLAG_UPDATE_SOURCE) || +	    CHECK_FLAG(p->flags_override, PEER_FLAG_UPDATE_SOURCE)) +		bgp_peer_bfd_update_source(p); +  	/*  	 * If using default control plane independent configuration,  	 * then prefer group's (e.g. it means it wasn't manually configured). @@ -141,24 +155,45 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)  void bgp_peer_bfd_update_source(struct peer *p)  { -	struct bfd_session_params *session = p->bfd_config->session; -	const union sockunion *source; +	struct bfd_session_params *session; +	const union sockunion *source = NULL;  	bool changed = false;  	int family;  	union {  		struct in_addr v4;  		struct in6_addr v6;  	} src, dst; +	struct interface *ifp; +	union sockunion addr; + +	if (!p->bfd_config) +		return; +	session = p->bfd_config->session;  	/* Nothing to do for groups. */  	if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))  		return;  	/* Figure out the correct source to use. */ -	if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE) && p->update_source) -		source = p->update_source; -	else +	if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE)) { +		if (p->update_source) { +			source = p->update_source; +		} else if (p->update_if) { +			ifp = if_lookup_by_name(p->update_if, p->bgp->vrf_id); +			if (ifp) { +				sockunion_init(&addr); +				if (bgp_update_address(ifp, &p->connection->su, &addr)) { +					if (BGP_DEBUG(bfd, BFD_LIB)) +						zlog_debug("%s: can't find the source address for interface %s", +							   __func__, p->update_if); +				} + +				source = &addr; +			} +		} +	} else {  		source = p->su_local; +	}  	/* Update peer's source/destination addresses. */  	bfd_sess_addresses(session, &family, &src.v6, &dst.v6);  | 
