diff options
| -rw-r--r-- | bfdd/bfd.c | 310 | ||||
| -rw-r--r-- | bfdd/bfd.h | 25 | ||||
| -rw-r--r-- | bfdd/event.c | 87 | 
3 files changed, 422 insertions, 0 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 987106e5d6..754f6aa782 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -40,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. @@ -468,6 +472,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; @@ -568,6 +603,96 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)  	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)  { @@ -632,6 +757,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)  { @@ -658,6 +798,42 @@ void bfd_echo_recvtimer_cb(struct event *t)  	}  } +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; @@ -984,6 +1160,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) { @@ -1035,6 +1235,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) { @@ -1059,6 +1282,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.   */ @@ -2170,6 +2445,41 @@ void sbfd_reflector_flush()  	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; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index d0f43b8878..e4421a358f 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -580,13 +580,21 @@ 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); @@ -609,6 +617,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, @@ -642,6 +653,7 @@ const struct bfd_session *bfd_session_next(const struct bfd_session *bs, bool mh  					   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);  void bfd_rtt_init(struct bfd_session *bfd);  extern void bfd_vrf_toggle_echo(struct bfd_vrf_global *bfd_vrf); @@ -712,6 +724,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;  /** @@ -852,4 +869,12 @@ struct sbfd_reflector *sbfd_reflector_new(const uint32_t discr, struct in6_addr  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); +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/event.c b/bfdd/event.c index e797e71f05..e5f43b6cc6 100644 --- a/bfdd/event.c +++ b/bfdd/event.c @@ -58,6 +58,73 @@ 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 +179,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); +}  | 
