bfdd: support global BFD reset

Add command 'no bfd' to remove all BFD sessions configuration and fix
other daemon integration.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2019-05-31 16:48:25 -03:00
parent 47a7b00c2d
commit 2a573ff672
4 changed files with 98 additions and 5 deletions

View file

@ -1290,6 +1290,7 @@ static unsigned int bfd_key_hash_do(const void *p);
static void _bfd_free(struct hash_bucket *hb,
void *arg __attribute__((__unused__)));
int _bfd_session_next(struct hash_bucket *hb, void *arg);
void _bfd_session_remove_manual(struct hash_bucket *hb, void *arg);
/* BFD hash for our discriminator. */
static unsigned int bfd_id_hash_do(const void *p)
@ -1587,6 +1588,35 @@ const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
return bsi.bsi_bs;
}
void _bfd_session_remove_manual(struct hash_bucket *hb,
void *arg __attribute__((__unused__)))
{
struct bfd_session *bs = hb->data;
/* Delete only manually configured sessions. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
return;
bs->refcount--;
BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
/* Don't delete sessions still in use. */
if (bs->refcount != 0)
return;
bfd_session_free(bs);
}
/*
* bfd_sessions_remove_manual: remove all manually configured sessions.
*
* NOTE: this function doesn't remove automatically created sessions.
*/
void bfd_sessions_remove_manual(void)
{
hash_iterate(bfd_key_hash, _bfd_session_remove_manual, NULL);
}
/*
* VRF related functions.
*/

View file

@ -550,6 +550,7 @@ struct bfd_session *bs_registrate(struct bfd_session *bs);
void bfd_session_free(struct bfd_session *bs);
const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
bool mhop);
void bfd_sessions_remove_manual(void);
/* BFD hash data structures interface */
void bfd_initialize(void);

View file

@ -52,6 +52,16 @@
/*
* Functions.
*/
DEFUN(
bfd_config_reset, bfd_config_reset_cmd,
"no bfd",
NO_STR
"Configure BFD peers\n")
{
nb_cli_enqueue_change(vty, "/frr-bfdd:bfdd/bfd", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
void bfd_cli_show_header(struct vty *vty,
struct lyd_node *dnode __attribute__((__unused__)),
bool show_defaults __attribute__((__unused__)))
@ -343,6 +353,8 @@ void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
void
bfdd_cli_init(void)
{
install_element(CONFIG_NODE, &bfd_config_reset_cmd);
install_element(BFD_NODE, &bfd_peer_enter_cmd);
install_element(BFD_NODE, &bfd_no_peer_cmd);

View file

@ -71,11 +71,27 @@ int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
switch (event) {
case NB_EV_VALIDATE:
bfd_session_get_key(mhop, dnode, &bk);
if (bfd_key_lookup(bk))
bs = bfd_key_lookup(bk);
/* This session was already configured by CLI. */
if (bs != NULL && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
bfd_session_get_key(mhop, dnode, &bk);
bs = bfd_key_lookup(bk);
/* This session was already configured by another daemon. */
if (bs != NULL) {
/* Now it is configured also by CLI. */
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
bs->refcount++;
resource->ptr = bs;
break;
}
bs = bfd_session_new();
if (bs == NULL)
return NB_ERR_RESOURCE;
@ -84,6 +100,7 @@ int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
bfd_session_get_key(mhop, dnode, &bs->key);
/* Set configuration flags. */
bs->refcount = 1;
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
if (mhop)
BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
@ -95,14 +112,18 @@ int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
case NB_EV_APPLY:
bs = resource->ptr;
if (bs_registrate(bs) == NULL)
/* Only attempt to registrate if freshly allocated. */
if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL)
return NB_ERR_RESOURCE;
nb_running_set_entry(dnode, bs);
break;
case NB_EV_ABORT:
bfd_session_free(resource->ptr);
bs = resource->ptr;
if (bs->refcount <= 1)
bfd_session_free(resource->ptr);
break;
}
@ -112,6 +133,7 @@ int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
int bfd_session_destroy(enum nb_event event, const struct lyd_node *dnode,
bool mhop)
{
struct bfd_session *bs;
struct bfd_key bk;
switch (event) {
@ -126,7 +148,18 @@ int bfd_session_destroy(enum nb_event event, const struct lyd_node *dnode,
break;
case NB_EV_APPLY:
bfd_session_free(nb_running_unset_entry(dnode));
bs = nb_running_unset_entry(dnode);
/* CLI is not using this session anymore. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
break;
BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
bs->refcount--;
/* There are still daemons using it. */
if (bs->refcount > 0)
break;
bfd_session_free(bs);
break;
case NB_EV_ABORT:
@ -152,7 +185,24 @@ static int bfdd_bfd_create(enum nb_event event,
static int bfdd_bfd_destroy(enum nb_event event, const struct lyd_node *dnode)
{
/* NOTHING */
switch (event) {
case NB_EV_VALIDATE:
/* NOTHING */
return NB_OK;
case NB_EV_PREPARE:
/* NOTHING */
return NB_OK;
case NB_EV_APPLY:
bfd_sessions_remove_manual();
break;
case NB_EV_ABORT:
/* NOTHING */
return NB_OK;
}
return NB_OK;
}