summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Zalamena <rzalamena@opensourcerouting.org>2019-05-31 16:48:25 -0300
committerRafael Zalamena <rzalamena@opensourcerouting.org>2019-06-22 10:10:56 -0300
commit2a573ff672f4b0eb76138362403a680bc9fc7fce (patch)
tree919f6343a318d3a0fc7157ce6528ab939f6472d4
parent47a7b00c2d4eb6cf65ca1a2d11e5078d64d465d0 (diff)
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>
-rw-r--r--bfdd/bfd.c30
-rw-r--r--bfdd/bfd.h1
-rw-r--r--bfdd/bfdd_cli.c12
-rw-r--r--bfdd/bfdd_northbound.c60
4 files changed, 98 insertions, 5 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index 828059eb4a..fc9d033437 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -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.
*/
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 78b21a9b6f..10aeb3e52c 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -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);
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index dac1c2521d..64500cef7d 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -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);
diff --git a/bfdd/bfdd_northbound.c b/bfdd/bfdd_northbound.c
index 4b21a21162..fd007b57b2 100644
--- a/bfdd/bfdd_northbound.c
+++ b/bfdd/bfdd_northbound.c
@@ -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;
}