]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bfdd: Handling local and remote admin-down
authorSumitAgarwal123 <sumit.agarwal@broadcom.com>
Mon, 21 Oct 2019 05:53:01 +0000 (22:53 -0700)
committerSumitAgarwal123 <sumit.agarwal@broadcom.com>
Tue, 29 Oct 2019 04:38:20 +0000 (21:38 -0700)
Scenarios where this code change is required:

1. BFD is un-configured from BGP at remote end.

Neighbour BFD sends ADMIN_DOWN state, but BFD on local side will send
DOWN to BGP, resulting in BGP session DOWN.
Removing BFD session administratively shouldn't bring DOWN BGP session
at local or remote.

2. BFD is un-configured from BGP or shutdown locally.

BFD will send state DOWN to BGP resulting in BGP session DOWN.
(This is akin to saying do not use BFD for BGP)
Removing BFD session administratively shouldn't bring DOWN BGP session at
local or remote.

Signed-off-by: Sayed Mohd Saquib sayed.saquib@broadcom.com
12 files changed:
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfdd_northbound.c
bfdd/control.c
bfdd/ptm_adapter.c
bgpd/bgp_bfd.c
isisd/isis_bfd.c
lib/bfd.c
lib/bfd.h
ospf6d/ospf6_bfd.c
ospfd/ospf_bfd.c
pimd/pim_bfd.c

index feb9827ce1ff30093f166ecea7cb1e0a65ea15cc..50c46fbd3dc47a714ed5b1d3a9b86c5c76d22dbe 100644 (file)
@@ -49,6 +49,8 @@ static void bs_admin_down_handler(struct bfd_session *bs, int nstate);
 static void bs_down_handler(struct bfd_session *bs, int nstate);
 static void bs_init_handler(struct bfd_session *bs, int nstate);
 static void bs_up_handler(struct bfd_session *bs, int nstate);
+static void bs_neighbour_admin_down_handler(struct bfd_session *bfd,
+                                           uint8_t diag);
 
 /* Zeroed array with the size of an IPv6 address. */
 struct in6_addr zero_addr;
@@ -307,7 +309,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd)
        /* Start sending control packets with poll bit immediately. */
        ptm_bfd_snd(bfd, 0);
 
-       control_notify(bfd);
+       control_notify(bfd, bfd->ses_state);
 
        if (old_state != bfd->ses_state) {
                bfd->stats.session_up++;
@@ -335,7 +337,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
 
        /* only signal clients when going from up->down state */
        if (old_state == PTM_BFD_UP)
-               control_notify(bfd);
+               control_notify(bfd, PTM_BFD_DOWN);
 
        /* Stop echo packet transmission if they are active */
        if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
@@ -570,7 +572,7 @@ skip_echo:
 
                /* Change and notify state change. */
                bs->ses_state = PTM_BFD_ADM_DOWN;
-               control_notify(bs);
+               control_notify(bs, bs->ses_state);
 
                /* Don't try to send packets with a disabled session. */
                if (bs->sock != -1)
@@ -584,7 +586,7 @@ skip_echo:
 
                /* Change and notify state change. */
                bs->ses_state = PTM_BFD_DOWN;
-               control_notify(bs);
+               control_notify(bs, bs->ses_state);
 
                /* Enable all timers. */
                bfd_recvtimer_update(bs);
@@ -856,10 +858,46 @@ static void bs_init_handler(struct bfd_session *bs, int nstate)
        }
 }
 
+static void bs_neighbour_admin_down_handler(struct bfd_session *bfd,
+                                           uint8_t diag)
+{
+       int old_state = bfd->ses_state;
+
+       bfd->local_diag = diag;
+       bfd->discrs.remote_discr = 0;
+       bfd->ses_state = PTM_BFD_DOWN;
+       bfd->polling = 0;
+       bfd->demand_mode = 0;
+       monotime(&bfd->downtime);
+
+       /* Slow down the control packets, the connection is down. */
+       bs_set_slow_timers(bfd);
+
+       /* only signal clients when going from up->down state */
+       if (old_state == PTM_BFD_UP)
+               control_notify(bfd, PTM_BFD_ADM_DOWN);
+
+       /* Stop echo packet transmission if they are active */
+       if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
+               ptm_bfd_echo_stop(bfd);
+
+       if (old_state != bfd->ses_state) {
+               bfd->stats.session_down++;
+
+               log_info("state-change: [%s] %s -> %s reason:%s",
+                       bs_to_string(bfd), state_list[old_state].str,
+                       state_list[bfd->ses_state].str,
+                       get_diag_str(bfd->local_diag));
+       }
+}
+
 static void bs_up_handler(struct bfd_session *bs, int nstate)
 {
        switch (nstate) {
        case PTM_BFD_ADM_DOWN:
+               bs_neighbour_admin_down_handler(bs, BD_ADMIN_DOWN);
+               break;
+
        case PTM_BFD_DOWN:
                /* Peer lost or asked to shutdown connection. */
                ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN);
index cdec78d1226066ceb130c38f3cd5942628fbff20..89f97d2e305d2b59a77d5a2accb4fdbf6b1d4cf0 100644 (file)
@@ -369,7 +369,7 @@ TAILQ_HEAD(bcslist, bfd_control_socket);
 
 int control_init(const char *path);
 void control_shutdown(void);
-int control_notify(struct bfd_session *bs);
+int control_notify(struct bfd_session *bs, uint8_t notify_state);
 int control_notify_config(const char *op, struct bfd_session *bs);
 int control_accept(struct thread *t);
 
@@ -632,7 +632,7 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf);
 void bfdd_sessions_disable_vrf(struct vrf *vrf);
 void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf);
 
-int ptm_bfd_notify(struct bfd_session *bs);
+int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state);
 
 
 /*
index 7cd2fb6b9aebe49d36e9ee492466ac0e227c576d..b8a7e955537b9ea92a832ddf1f2e2bec3b7b4954 100644 (file)
@@ -405,7 +405,7 @@ static int bfdd_bfd_sessions_single_hop_administrative_down_modify(
 
                /* Change and notify state change. */
                bs->ses_state = PTM_BFD_DOWN;
-               control_notify(bs);
+               control_notify(bs, bs->ses_state);
 
                /* Enable all timers. */
                bfd_recvtimer_update(bs);
@@ -428,7 +428,7 @@ static int bfdd_bfd_sessions_single_hop_administrative_down_modify(
 
                /* Change and notify state change. */
                bs->ses_state = PTM_BFD_ADM_DOWN;
-               control_notify(bs);
+               control_notify(bs, bs->ses_state);
 
                ptm_bfd_snd(bs, 0);
        }
index c308d647d83e36c5084babc7e362dd6de02d4c7c..5c5421c041057bba33cdea79b924b6b525225b93 100644 (file)
@@ -774,13 +774,13 @@ static void _control_notify(struct bfd_control_socket *bcs,
        control_queue_enqueue(bcs, bcm);
 }
 
-int control_notify(struct bfd_session *bs)
+int control_notify(struct bfd_session *bs, uint8_t notify_state)
 {
        struct bfd_control_socket *bcs;
        struct bfd_notify_peer *bnp;
 
        /* Notify zebra listeners as well. */
-       ptm_bfd_notify(bs);
+       ptm_bfd_notify(bs, notify_state);
 
        /*
         * PERFORMANCE: reuse the bfd_control_msg allocated data for
index ae6d04e77d5e72065a20304847d41b2c5fdf97c2..2677eb31f2e4731f84d24b38f95755e69add5793 100644 (file)
@@ -153,7 +153,7 @@ static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
        return 0;
 }
 
-int ptm_bfd_notify(struct bfd_session *bs)
+int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
 {
        struct stream *msg;
 
@@ -204,12 +204,15 @@ int ptm_bfd_notify(struct bfd_session *bs)
        _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
 
        /* BFD status */
-       switch (bs->ses_state) {
+       switch (notify_state) {
        case PTM_BFD_UP:
                stream_putl(msg, BFD_STATUS_UP);
                break;
 
        case PTM_BFD_ADM_DOWN:
+               stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
+               break;
+
        case PTM_BFD_DOWN:
        case PTM_BFD_INIT:
                stream_putl(msg, BFD_STATUS_DOWN);
@@ -432,7 +435,7 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
                return;
        }
 
-       ptm_bfd_notify(bs);
+       ptm_bfd_notify(bs, bs->ses_state);
 }
 
 static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
@@ -461,6 +464,10 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
        if (bs->refcount ||
            BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
                return;
+
+       bs->ses_state = PTM_BFD_ADM_DOWN;
+       ptm_bfd_snd(bs, 0);
+
        ptm_bfd_sess_del(&bpc);
 }
 
index 57fef8e9139f5cc467dd35e26713b8379a1bc31f..0ed6057eac1b795bcb46170b49cd1308d61a2ff9 100644 (file)
@@ -282,7 +282,8 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status,
                return;
 
        old_status = bfd_info->status;
-       bfd_info->status = status;
+       BFD_SET_CLIENT_STATUS(bfd_info->status, status);
+
        bfd_info->last_update = bgp_clock();
 
        if (status != old_status) {
index 8fc7997d79f085cc46754355ebb7436a8d9bf3d3..cf4b841798748959659b4bad758c7663e4d685b9 100644 (file)
@@ -118,7 +118,8 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
 
        int old_status = adj->bfd_session->status;
 
-       adj->bfd_session->status = new_status;
+       BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status);
+
        if (old_status == new_status)
                return;
 
index 00dbd1b3d1ef1f160c4b737838b9d596ae8b8511..ffb3cbc1f86f044da7a9cf4d0b1d0131561a3b6f 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -315,6 +315,8 @@ const char *bfd_get_status_str(int status)
                return "Down";
        case BFD_STATUS_UP:
                return "Up";
+       case BFD_STATUS_ADMIN_DOWN:
+               return "Admin Down";
        case BFD_STATUS_UNKNOWN:
        default:
                return "Unknown";
index e4781f4eaf9e45cbe664dd029620f14c444fbe47..7f5d111504639ac51cac1d5765f416de0779db88 100644 (file)
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -51,9 +51,17 @@ struct bfd_gbl {
 #define BFD_FLAG_BFD_CBIT_ON (1 << 3) /* Peer registered with CBIT set to on */
 #define BFD_FLAG_BFD_CHECK_CONTROLPLANE (1 << 4) /* BFD and controlplane daemon are linked */
 
-#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
-#define BFD_STATUS_DOWN    (1 << 1) /* BFD session status is down */
-#define BFD_STATUS_UP      (1 << 2) /* BFD session status is up */
+#define BFD_STATUS_UNKNOWN    (1 << 0) /* BFD session status never received */
+#define BFD_STATUS_DOWN       (1 << 1) /* BFD session status is down */
+#define BFD_STATUS_UP         (1 << 2) /* BFD session status is up */
+#define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */
+
+#define BFD_SET_CLIENT_STATUS(current_status, new_status)                \
+       do {                                                              \
+               (current_status) =                                        \
+                       (((new_status) == BFD_STATUS_ADMIN_DOWN) ?        \
+                                         BFD_STATUS_DOWN : (new_status));\
+       } while (0)
 
 enum bfd_sess_type {
        BFD_TYPE_NOT_CONFIGURED,
index f0500601b09054851788896bfa10e4eeef989f53..4e7a0050aa26227776ed97ee4043b8f78b341c44 100644 (file)
@@ -236,7 +236,7 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
                        continue;
 
                old_status = bfd_info->status;
-               bfd_info->status = status;
+               BFD_SET_CLIENT_STATUS(bfd_info->status, status);
                monotime(&tv);
                bfd_info->last_update = tv.tv_sec;
 
index a17975270af957fd8603dad512e163b2b9212de5..73802ce13e83aaff8f97f9e299a449715b99da36 100644 (file)
@@ -240,7 +240,7 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
                        continue;
 
                old_status = bfd_info->status;
-               bfd_info->status = status;
+               BFD_SET_CLIENT_STATUS(bfd_info->status, status);
                monotime(&tv);
                bfd_info->last_update = tv.tv_sec;
 
index 87d0f9fa22d10bde25eaaf07a12b207f0ff0a5e7..01a7980858f6d660ebea49d0e0d88e01d3eb93e3 100644 (file)
@@ -270,7 +270,7 @@ static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
                        continue;
                }
                old_status = bfd_info->status;
-               bfd_info->status = status;
+               BFD_SET_CLIENT_STATUS(bfd_info->status, status);
                monotime(&tv);
                bfd_info->last_update = tv.tv_sec;