]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bfdd: add sbfd state machine functions
authorwumu.zsl <wumu.zsl@alibaba-inc.com>
Tue, 21 Jan 2025 06:32:47 +0000 (06:32 +0000)
committerwumu.zsl <wumu.zsl@alibaba-inc.com>
Thu, 23 Jan 2025 02:58:46 +0000 (02:58 +0000)
Signed-off-by: wumu.zsl <wumu.zsl@alibaba-inc.com>
bfdd/bfd.c
bfdd/bfd.h
bfdd/event.c

index 987106e5d6130c060d791f4a22970b488a35d2db..754f6aa7827bd3e5f5a95393707c7d6c108a32c9 100644 (file)
@@ -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;
index d0f43b88781c1cf47666a876feb965a92713cacb..e4421a358f853b85aca28dafb5a264935529704f 100644 (file)
@@ -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_ */
index e797e71f050a4e18a000609fd4c4752ce8a6edab..e5f43b6cc69802e331db4680e938988b15a27ad9 100644 (file)
@@ -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);
+}