bfdd: implement passive mode

The passive mode is briefly described in the RFC 5880 Bidirectional
Forwarding Detection (BFD), Section 6.1. Overview:

> A system may take either an Active role or a Passive role in session
> initialization.  A system taking the Active role MUST send BFD
> Control packets for a particular session, regardless of whether it
> has received any BFD packets for that session.  A system taking the
> Passive role MUST NOT begin sending BFD packets for a particular
> session until it has received a BFD packet for that session, and thus
> has learned the remote system's discriminator value.  At least one
> system MUST take the Active role (possibly both).  The role that a
> system takes is specific to the application of BFD, and is outside
> the scope of this specification.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2020-08-06 16:25:44 -03:00
parent 8733bc48ea
commit 1a2e2fff35
8 changed files with 183 additions and 5 deletions

View File

@ -88,6 +88,7 @@ static void bfd_profile_set_default(struct bfd_profile *bp)
bp->admin_shutdown = true; bp->admin_shutdown = true;
bp->detection_multiplier = BFD_DEFDETECTMULT; bp->detection_multiplier = BFD_DEFDETECTMULT;
bp->echo_mode = false; bp->echo_mode = false;
bp->passive = false;
bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO; bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO;
bp->min_rx = BFD_DEFREQUIREDMINRX; bp->min_rx = BFD_DEFREQUIREDMINRX;
bp->min_tx = BFD_DEFDESIREDMINTX; bp->min_tx = BFD_DEFDESIREDMINTX;
@ -159,8 +160,10 @@ static void _bfd_profile_remove(struct bfd_session *bs, bool apply)
bfd_set_echo(bs, bs->peer_profile.echo_mode); bfd_set_echo(bs, bs->peer_profile.echo_mode);
} }
if (apply) if (apply) {
bfd_set_passive_mode(bs, bs->peer_profile.passive);
bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown); bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
}
} }
void bfd_profile_apply(const char *profname, struct bfd_session *bs) void bfd_profile_apply(const char *profname, struct bfd_session *bs)
@ -221,6 +224,12 @@ void bfd_profile_apply(const char *profname, struct bfd_session *bs)
bfd_set_echo(bs, bs->peer_profile.echo_mode); bfd_set_echo(bs, bs->peer_profile.echo_mode);
} }
/* 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);
/* Toggle 'no shutdown' if default value. */ /* Toggle 'no shutdown' if default value. */
if (bs->peer_profile.admin_shutdown) if (bs->peer_profile.admin_shutdown)
bfd_set_shutdown(bs, bp->admin_shutdown); bfd_set_shutdown(bs, bp->admin_shutdown);
@ -374,8 +383,12 @@ int bfd_session_enable(struct bfd_session *bs)
* protocol. * protocol.
*/ */
bs->sock = psock; bs->sock = psock;
bfd_recvtimer_update(bs);
ptm_bfd_start_xmt_timer(bs, false); /* 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);
}
return 0; return 0;
} }
@ -536,6 +549,12 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
ptm_bfd_echo_stop(bfd); ptm_bfd_echo_stop(bfd);
/* Stop attempting to transmit or expect control packets if passive. */
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_PASSIVE)) {
bfd_recvtimer_delete(bfd);
bfd_xmttimer_delete(bfd);
}
if (old_state != bfd->ses_state) { if (old_state != bfd->ses_state) {
bfd->stats.session_down++; bfd->stats.session_down++;
if (bglobal.debug_peer_event) if (bglobal.debug_peer_event)
@ -766,6 +785,7 @@ static void _bfd_session_update(struct bfd_session *bs,
* the session is disabled. * the session is disabled.
*/ */
bs->peer_profile.admin_shutdown = bpc->bpc_shutdown; bs->peer_profile.admin_shutdown = bpc->bpc_shutdown;
bfd_set_passive_mode(bs, bpc->bpc_passive);
bfd_set_shutdown(bs, bpc->bpc_shutdown); bfd_set_shutdown(bs, bpc->bpc_shutdown);
/* /*
@ -986,6 +1006,10 @@ static void bs_down_handler(struct bfd_session *bs, int nstate)
* bring it up. * bring it up.
*/ */
bs->ses_state = PTM_BFD_INIT; bs->ses_state = PTM_BFD_INIT;
/* Answer peer with INIT immediately in passive mode. */
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE))
ptm_bfd_snd(bs, 0);
break; break;
case PTM_BFD_INIT: case PTM_BFD_INIT:
@ -1312,9 +1336,39 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
bs->ses_state = PTM_BFD_DOWN; bs->ses_state = PTM_BFD_DOWN;
control_notify(bs, bs->ses_state); control_notify(bs, bs->ses_state);
/* Enable all timers. */ /* Enable timers if non passive, otherwise stop them. */
bfd_recvtimer_update(bs); if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) {
bfd_recvtimer_delete(bs);
bfd_xmttimer_delete(bs);
} else {
bfd_recvtimer_update(bs);
bfd_xmttimer_update(bs, bs->xmt_TO);
}
}
}
void bfd_set_passive_mode(struct bfd_session *bs, bool passive)
{
if (passive) {
SET_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE);
/* Session is already up and running, nothing to do now. */
if (bs->ses_state != PTM_BFD_DOWN)
return;
/* Lets disable the timers since we are now passive. */
bfd_recvtimer_delete(bs);
bfd_xmttimer_delete(bs);
} else {
UNSET_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE);
/* Session is already up and running, nothing to do now. */
if (bs->ses_state != PTM_BFD_DOWN)
return;
/* Session is down, let it attempt to start the connection. */
bfd_xmttimer_update(bs, bs->xmt_TO); bfd_xmttimer_update(bs, bs->xmt_TO);
bfd_recvtimer_update(bs);
} }
} }

View File

@ -170,6 +170,7 @@ enum bfd_session_flags {
BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */ BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */
BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */ BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */
BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */ BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */
BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */
}; };
/* BFD session hash keys */ /* BFD session hash keys */
@ -207,6 +208,8 @@ struct bfd_profile {
uint32_t min_rx; uint32_t min_rx;
/** Administrative state. */ /** Administrative state. */
bool admin_shutdown; bool admin_shutdown;
/** Passive mode. */
bool passive;
/** Echo mode (only applies to single hop). */ /** Echo mode (only applies to single hop). */
bool echo_mode; bool echo_mode;
@ -607,6 +610,14 @@ void bfd_set_echo(struct bfd_session *bs, bool echo);
*/ */
void bfd_set_shutdown(struct bfd_session *bs, bool shutdown); void bfd_set_shutdown(struct bfd_session *bs, bool shutdown);
/**
* Set the BFD session passive mode.
*
* \param bs the BFD session.
* \param passive the passive mode.
*/
void bfd_set_passive_mode(struct bfd_session *bs, bool passive);
/* BFD hash data structures interface */ /* BFD hash data structures interface */
void bfd_initialize(void); void bfd_initialize(void);
void bfd_shutdown(void); void bfd_shutdown(void);

View File

@ -89,6 +89,7 @@ struct bfd_peer_cfg {
bool bpc_shutdown; bool bpc_shutdown;
bool bpc_cbit; bool bpc_cbit;
bool bpc_passive;
bool bpc_has_profile; bool bpc_has_profile;
char bpc_profile[64]; char bpc_profile[64];

View File

@ -265,6 +265,27 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_bool(dnode, NULL) ? "" : "no "); yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
} }
DEFPY_YANG(
bfd_peer_passive, bfd_peer_passive_cmd,
"[no] passive-mode",
NO_STR
"Don't attempt to start sessions\n")
{
nb_cli_enqueue_change(vty, "./passive-mode", NB_OP_MODIFY,
no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
}
void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
if (show_defaults)
vty_out(vty, " no passive-mode\n");
else
vty_out(vty, " %spassive-mode\n",
yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
}
DEFPY_YANG( DEFPY_YANG(
bfd_peer_mult, bfd_peer_mult_cmd, bfd_peer_mult, bfd_peer_mult_cmd,
"detect-multiplier (2-255)$multiplier", "detect-multiplier (2-255)$multiplier",
@ -462,6 +483,11 @@ ALIAS_YANG(bfd_peer_shutdown, bfd_profile_shutdown_cmd,
NO_STR NO_STR
"Disable BFD peer\n") "Disable BFD peer\n")
ALIAS_YANG(bfd_peer_passive, bfd_profile_passive_cmd,
"[no] passive-mode",
NO_STR
"Don't attempt to start sessions\n")
ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd, ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
"[no] echo-mode", "[no] echo-mode",
NO_STR NO_STR
@ -530,6 +556,7 @@ bfdd_cli_init(void)
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd); install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd);
/* Profile commands. */ /* Profile commands. */
cmd_variable_handler_register(bfd_vars); cmd_variable_handler_register(bfd_vars);
@ -546,4 +573,5 @@ bfdd_cli_init(void)
install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd);
} }

View File

@ -77,6 +77,13 @@ const struct frr_yang_module_info frr_bfdd_info = {
.cli_show = bfd_cli_show_shutdown, .cli_show = bfd_cli_show_shutdown,
} }
}, },
{
.xpath = "/frr-bfdd:bfdd/bfd/profile/passive-mode",
.cbs = {
.modify = bfdd_bfd_profile_passive_mode_modify,
.cli_show = bfd_cli_show_passive,
}
},
{ {
.xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode", .xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode",
.cbs = { .cbs = {
@ -146,6 +153,13 @@ const struct frr_yang_module_info frr_bfdd_info = {
.cli_show = bfd_cli_show_shutdown, .cli_show = bfd_cli_show_shutdown,
} }
}, },
{
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/passive-mode",
.cbs = {
.modify = bfdd_bfd_sessions_single_hop_passive_mode_modify,
.cli_show = bfd_cli_show_passive,
}
},
{ {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode", .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode",
.cbs = { .cbs = {
@ -328,6 +342,13 @@ const struct frr_yang_module_info frr_bfdd_info = {
.cli_show = bfd_cli_show_shutdown, .cli_show = bfd_cli_show_shutdown,
} }
}, },
{
.xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/passive-mode",
.cbs = {
.modify = bfdd_bfd_sessions_single_hop_passive_mode_modify,
.cli_show = bfd_cli_show_passive,
}
},
{ {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator", .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator",
.cbs = { .cbs = {

View File

@ -37,6 +37,7 @@ int bfdd_bfd_profile_desired_transmission_interval_modify(
int bfdd_bfd_profile_required_receive_interval_modify( int bfdd_bfd_profile_required_receive_interval_modify(
struct nb_cb_modify_args *args); struct nb_cb_modify_args *args);
int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_desired_echo_transmission_interval_modify( int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args); struct nb_cb_modify_args *args);
@ -62,6 +63,8 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
struct nb_cb_modify_args *args); struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_administrative_down_modify( int bfdd_bfd_sessions_single_hop_administrative_down_modify(
struct nb_cb_modify_args *args); struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_passive_mode_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_echo_mode_modify( int bfdd_bfd_sessions_single_hop_echo_mode_modify(
struct nb_cb_modify_args *args); struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
@ -206,5 +209,7 @@ void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
bool show_defaults); bool show_defaults);
void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults); bool show_defaults);
void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
#endif /* _FRR_BFDD_NB_H_ */ #endif /* _FRR_BFDD_NB_H_ */

View File

@ -359,6 +359,28 @@ int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args)
return NB_OK; return NB_OK;
} }
/*
* XPath: /frr-bfdd:bfdd/bfd/profile/passive-mode
*/
int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args)
{
struct bfd_profile *bp;
bool passive;
if (args->event != NB_EV_APPLY)
return NB_OK;
passive = yang_dnode_get_bool(args->dnode, NULL);
bp = nb_running_get_entry(args->dnode, NULL, true);
if (bp->passive == passive)
return NB_OK;
bp->passive = passive;
bfd_profile_update(bp);
return NB_OK;
}
/* /*
* XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode
*/ */
@ -611,6 +633,36 @@ int bfdd_bfd_sessions_single_hop_administrative_down_modify(
return NB_OK; return NB_OK;
} }
/*
* XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/passive-mode
*/
int bfdd_bfd_sessions_single_hop_passive_mode_modify(
struct nb_cb_modify_args *args)
{
struct bfd_session *bs;
bool passive;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
return NB_OK;
case NB_EV_APPLY:
break;
case NB_EV_ABORT:
return NB_OK;
}
passive = yang_dnode_get_bool(args->dnode, NULL);
bs = nb_running_get_entry(args->dnode, NULL, true);
bs->peer_profile.passive = passive;
bfd_set_passive_mode(bs, passive);
return NB_OK;
}
/* /*
* XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
*/ */

View File

@ -111,6 +111,10 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr); vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr); vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE))
vty_out(vty, "\t\tPassive mode\n");
else
vty_out(vty, "\t\tActive mode\n");
vty_out(vty, "\t\tStatus: "); vty_out(vty, "\t\tStatus: ");
switch (bs->ses_state) { switch (bs->ses_state) {
@ -203,6 +207,8 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
json_object_int_add(jo, "id", bs->discrs.my_discr); json_object_int_add(jo, "id", bs->discrs.my_discr);
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr); json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
json_object_boolean_add(jo, "passive-mode",
CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE));
switch (bs->ses_state) { switch (bs->ses_state) {
case PTM_BFD_ADM_DOWN: case PTM_BFD_ADM_DOWN: