bfdd: refactor state change handler

Expand state change handling into smaller functions with more
explanatory commentaries. This also handles some corner cases that
were not being handled.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2019-01-15 20:23:06 -02:00
parent 09720d3189
commit aef131afc5
3 changed files with 126 additions and 23 deletions

View File

@ -694,6 +694,129 @@ void bfd_set_polling(struct bfd_session *bs)
bs->polling = 1;
}
/*
* bs_<state>_handler() functions implement the BFD state machine
* transition mechanism. `<state>` is the current session state and
* the parameter `nstate` is the peer new state.
*/
void bs_admin_down_handler(struct bfd_session *bs, int nstate);
void bs_down_handler(struct bfd_session *bs, int nstate);
void bs_init_handler(struct bfd_session *bs, int nstate);
void bs_up_handler(struct bfd_session *bs, int nstate);
void bs_admin_down_handler(struct bfd_session *bs __attribute__((__unused__)),
int nstate __attribute__((__unused__)))
{
/*
* We are administratively down, there is no state machine
* handling.
*/
}
void bs_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.
*/
case PTM_BFD_UP:
/* Peer can't be up yet, wait it go to 'init' or 'down'. */
break;
case PTM_BFD_DOWN:
/*
* Remote peer agreed that the path is down, lets try to
* bring it up.
*/
bs->ses_state = PTM_BFD_INIT;
break;
case PTM_BFD_INIT:
/*
* Remote peer told us his path is up, lets turn
* activate the session.
*/
ptm_bfd_ses_up(bs);
break;
default:
log_debug("state-change: unhandled neighbor state: %d", nstate);
break;
}
}
void bs_init_handler(struct bfd_session *bs, int nstate)
{
switch (nstate) {
case PTM_BFD_ADM_DOWN:
/*
* Remote peer doesn't want to talk, so lets make the
* connection down.
*/
bs->ses_state = PTM_BFD_DOWN;
break;
case PTM_BFD_DOWN:
/* Remote peer hasn't moved to first stage yet. */
break;
case PTM_BFD_INIT:
case PTM_BFD_UP:
/* We agreed on the settings and the path is up. */
ptm_bfd_ses_up(bs);
break;
default:
log_debug("state-change: unhandled neighbor state: %d", nstate);
break;
}
}
void bs_up_handler(struct bfd_session *bs, int nstate)
{
switch (nstate) {
case PTM_BFD_ADM_DOWN:
case PTM_BFD_DOWN:
/* Peer lost or asked to shutdown connection. */
ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN);
break;
case PTM_BFD_INIT:
case PTM_BFD_UP:
/* Path is up and working. */
break;
default:
log_debug("state-change: unhandled neighbor state: %d", nstate);
break;
}
}
void bs_state_handler(struct bfd_session *bs, int nstate)
{
switch (bs->ses_state) {
case PTM_BFD_ADM_DOWN:
bs_admin_down_handler(bs, nstate);
break;
case PTM_BFD_DOWN:
bs_down_handler(bs, nstate);
break;
case PTM_BFD_INIT:
bs_init_handler(bs, nstate);
break;
case PTM_BFD_UP:
bs_up_handler(bs, nstate);
break;
default:
log_debug("state-change: [%s] is in invalid state: %d",
bs_to_string(bs), nstate);
break;
}
}
/*
* Helper functions.

View File

@ -525,6 +525,7 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc);
int bfd_session_update_label(struct bfd_session *bs, const char *nlabel);
void bfd_set_polling(struct bfd_session *bs);
void bs_state_handler(struct bfd_session *, int);
const char *satostr(struct sockaddr_any *sa);
const char *diag2str(uint8_t diag);
int strtosa(const char *addr, struct sockaddr_any *sa);

View File

@ -668,29 +668,8 @@ int bfd_recv_cb(struct thread *t)
/* Save remote diagnostics before state switch. */
bfd->remote_diag = cp->diag & BFD_DIAGMASK;
/* State switch from section 6.8.6 */
if (BFD_GETSTATE(cp->flags) == PTM_BFD_ADM_DOWN) {
if (bfd->ses_state != PTM_BFD_DOWN)
ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN);
} else {
switch (bfd->ses_state) {
case (PTM_BFD_DOWN):
if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT)
ptm_bfd_ses_up(bfd);
else if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN)
bfd->ses_state = PTM_BFD_INIT;
break;
case (PTM_BFD_INIT):
if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT
|| BFD_GETSTATE(cp->flags) == PTM_BFD_UP)
ptm_bfd_ses_up(bfd);
break;
case (PTM_BFD_UP):
if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN)
ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN);
break;
}
}
/* State switch from section 6.2. */
bs_state_handler(bfd, BFD_GETSTATE(cp->flags));
/*
* Handle echo packet status: