From 1a2e2fff35b1b0f5f2e5dfa09378be9b62ce8f7a Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Thu, 6 Aug 2020 16:25:44 -0300 Subject: [PATCH] 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 --- bfdd/bfd.c | 64 +++++++++++++++++++++++++++++++++++++++---- bfdd/bfd.h | 11 ++++++++ bfdd/bfdctl.h | 1 + bfdd/bfdd_cli.c | 28 +++++++++++++++++++ bfdd/bfdd_nb.c | 21 ++++++++++++++ bfdd/bfdd_nb.h | 5 ++++ bfdd/bfdd_nb_config.c | 52 +++++++++++++++++++++++++++++++++++ bfdd/bfdd_vty.c | 6 ++++ 8 files changed, 183 insertions(+), 5 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index caa80ed51d..1d50d98c78 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -88,6 +88,7 @@ static void bfd_profile_set_default(struct bfd_profile *bp) bp->admin_shutdown = true; bp->detection_multiplier = BFD_DEFDETECTMULT; bp->echo_mode = false; + bp->passive = false; bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO; bp->min_rx = BFD_DEFREQUIREDMINRX; 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); } - if (apply) + if (apply) { + bfd_set_passive_mode(bs, bs->peer_profile.passive); bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown); + } } 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); } + /* 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. */ if (bs->peer_profile.admin_shutdown) bfd_set_shutdown(bs, bp->admin_shutdown); @@ -374,8 +383,12 @@ int bfd_session_enable(struct bfd_session *bs) * protocol. */ 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; } @@ -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)) 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) { bfd->stats.session_down++; if (bglobal.debug_peer_event) @@ -766,6 +785,7 @@ static void _bfd_session_update(struct bfd_session *bs, * the session is disabled. */ bs->peer_profile.admin_shutdown = bpc->bpc_shutdown; + bfd_set_passive_mode(bs, bpc->bpc_passive); 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. */ 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; case PTM_BFD_INIT: @@ -1312,9 +1336,39 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) bs->ses_state = PTM_BFD_DOWN; control_notify(bs, bs->ses_state); - /* Enable all timers. */ - bfd_recvtimer_update(bs); + /* Enable timers if non passive, otherwise stop them. */ + 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_recvtimer_update(bs); } } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 492334a670..88ca17a9a9 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -170,6 +170,7 @@ enum bfd_session_flags { 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_CBIT = 1 << 9, /* CBIT is set */ + BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */ }; /* BFD session hash keys */ @@ -207,6 +208,8 @@ struct bfd_profile { uint32_t min_rx; /** Administrative state. */ bool admin_shutdown; + /** Passive mode. */ + bool passive; /** Echo mode (only applies to single hop). */ 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); +/** + * 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 */ void bfd_initialize(void); void bfd_shutdown(void); diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index 95cfcb1105..3cb2fba49a 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -89,6 +89,7 @@ struct bfd_peer_cfg { bool bpc_shutdown; bool bpc_cbit; + bool bpc_passive; bool bpc_has_profile; char bpc_profile[64]; diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 0dd021d475..e70354de05 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -265,6 +265,27 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, 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( bfd_peer_mult, bfd_peer_mult_cmd, "detect-multiplier (2-255)$multiplier", @@ -462,6 +483,11 @@ ALIAS_YANG(bfd_peer_shutdown, bfd_profile_shutdown_cmd, NO_STR "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, "[no] echo-mode", 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_interval_cmd); install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd); + install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd); /* Profile commands. */ 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_echo_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd); } diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c index 2ff99ca608..cf063f82fc 100644 --- a/bfdd/bfdd_nb.c +++ b/bfdd/bfdd_nb.c @@ -77,6 +77,13 @@ const struct frr_yang_module_info frr_bfdd_info = { .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", .cbs = { @@ -146,6 +153,13 @@ const struct frr_yang_module_info frr_bfdd_info = { .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", .cbs = { @@ -328,6 +342,13 @@ const struct frr_yang_module_info frr_bfdd_info = { .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", .cbs = { diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index a379c2135e..ec467f357f 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -37,6 +37,7 @@ int bfdd_bfd_profile_desired_transmission_interval_modify( int bfdd_bfd_profile_required_receive_interval_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_desired_echo_transmission_interval_modify( 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); int bfdd_bfd_sessions_single_hop_administrative_down_modify( 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( struct nb_cb_modify_args *args); 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); void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); #endif /* _FRR_BFDD_NB_H_ */ diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 970b5f2d65..d50f746d3d 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -359,6 +359,28 @@ int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args) 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 */ @@ -611,6 +633,36 @@ int bfdd_bfd_sessions_single_hop_administrative_down_modify( 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 */ diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 8318ea9665..a532b76f0e 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -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\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: "); 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, "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) { case PTM_BFD_ADM_DOWN: