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.
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;
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)
{
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)
{
}
}
+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;
}
}
+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) {
}
}
+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) {
}
}
+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.
*/
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;
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);
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,
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);
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;
/**
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_ */
&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};
{
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);
+}