diff options
Diffstat (limited to 'bfdd/bfd.c')
| -rw-r--r-- | bfdd/bfd.c | 548 | 
1 files changed, 517 insertions, 31 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c index f32bc2598b..164910556b 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 @@ -39,6 +40,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. @@ -192,10 +197,12 @@ 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) @@ -222,10 +229,11 @@ void bfd_profile_remove(struct bfd_session *bs)  	bfd_session_apply(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) +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 vrf *vrf = NULL; +  	memset(key, 0, sizeof(*key));  	switch (peer->sa_sin.sin_family) { @@ -248,10 +256,20 @@ 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)); -	else +	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) @@ -259,8 +277,8 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)  	struct bfd_key key;  	/* 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); +	gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif, +		    bpc->bpc_vrfname, bpc->bfd_name);  	return bfd_key_lookup(key);  } @@ -333,14 +351,24 @@ 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 {  		psock = bp_peer_socketv6(bs); -		if (psock == -1) +		if (psock == -1) { +			zlog_err("bp_peer_socketv6 error");  			return 0; +		}  	}  	/* @@ -351,10 +379,18 @@ 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) { +			/*enable receive echo response*/ +			bfd_set_echo(bs, true); +			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 { +			bfd_recvtimer_update(bs); +			ptm_bfd_start_xmt_timer(bs, false); +		} +	}  	/* initialize RTT */  	bfd_rtt_init(bs); @@ -383,6 +419,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); @@ -422,10 +460,18 @@ 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) @@ -456,6 +502,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; @@ -550,12 +627,103 @@ 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);  } +/*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; +	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) +		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)  { @@ -599,7 +767,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); @@ -620,6 +788,21 @@ 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)  { @@ -638,6 +821,11 @@ 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: @@ -646,11 +834,49 @@ void bfd_echo_recvtimer_cb(struct event *t)  	}  } -struct bfd_session *bfd_session_new(void) +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_PATH_DOWN); +		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_PATH_DOWN); +		break; +	case PTM_BFD_DOWN: +		break; +	} +} + +struct bfd_session *bfd_session_new(enum bfd_mode_type mode)  {  	struct bfd_session *bs; -	bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs)); +	bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(struct bfd_session)); +	bs->segnum = 0; +	bs->bfd_mode = mode;  	/* Set peer session defaults. */  	bfd_profile_set_default(&bs->peer_profile); @@ -788,7 +1014,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);  	/*  	 * Store interface/VRF name in case we need to delay session @@ -970,6 +1196,30 @@ 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) { @@ -1021,6 +1271,29 @@ 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) { @@ -1045,6 +1318,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.   */ @@ -1147,6 +1472,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) @@ -1438,6 +1772,8 @@ 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; @@ -1516,6 +1852,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); @@ -1567,6 +1907,8 @@ 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. @@ -1591,6 +1933,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. @@ -1615,6 +1971,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.   * @@ -1643,6 +2008,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)  { @@ -1654,6 +2028,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.   * @@ -1670,12 +2049,24 @@ 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);  } @@ -1687,6 +2078,14 @@ 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; @@ -1701,9 +2100,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) @@ -1713,6 +2116,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;  }; @@ -1724,7 +2128,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; @@ -1736,7 +2140,8 @@ 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; @@ -1751,14 +2156,15 @@ 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) +const struct bfd_session *bfd_session_next(const struct bfd_session *bs, 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; @@ -1924,6 +2330,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;  } @@ -1957,6 +2364,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 == -1) +		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, @@ -1970,6 +2379,8 @@ 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] == NULL && 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); @@ -2006,6 +2417,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); @@ -2014,6 +2426,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;  } @@ -2050,6 +2463,79 @@ 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; +}; + +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;  | 
