summaryrefslogtreecommitdiffstats
path: root/isisd/isis_bfd.c
diff options
context:
space:
mode:
authorChristian Franke <chris@opensourcerouting.org>2018-09-28 20:33:55 +0200
committerChristian Franke <chris@opensourcerouting.org>2018-10-05 14:08:34 +0200
commita5eba4e9a55960f696c1e4906f9fc2ac59c1fa81 (patch)
treebd838d8891ddf65cd40da741fb425836642fecb1 /isisd/isis_bfd.c
parentisisd: Add debugging for BFD (diff)
downloadfrr-a5eba4e9a55960f696c1e4906f9fc2ac59c1fa81.tar.xz
frr-a5eba4e9a55960f696c1e4906f9fc2ac59c1fa81.zip
isisd: Track BFD state and take down adjacency on failure
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Diffstat (limited to 'isisd/isis_bfd.c')
-rw-r--r--isisd/isis_bfd.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index 6f89d9873..59d88e9e3 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -38,6 +38,7 @@ DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
struct bfd_session {
struct in_addr dst_ip;
struct in_addr src_ip;
+ int status;
};
static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
@@ -45,7 +46,7 @@ static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
{
struct bfd_session *rv;
- rv = XMALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
+ rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
rv->dst_ip = *dst_ip;
rv->src_ip = *src_ip;
return rv;
@@ -60,6 +61,40 @@ static void bfd_session_free(struct bfd_session **session)
*session = NULL;
}
+static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
+ int new_status)
+{
+ if (!adj->bfd_session)
+ return;
+
+ if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr)
+ return;
+
+ int old_status = adj->bfd_session->status;
+ adj->bfd_session->status = new_status;
+
+ if (old_status == new_status)
+ return;
+
+ if (isis->debugs & DEBUG_BFD) {
+ char dst_str[INET6_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &adj->bfd_session->dst_ip,
+ dst_str, sizeof(dst_str));
+ zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s",
+ dst_str, adj->circuit->interface->name,
+ bfd_get_status_str(old_status),
+ bfd_get_status_str(new_status));
+ }
+
+ if (old_status != BFD_STATUS_UP
+ || new_status != BFD_STATUS_DOWN) {
+ return;
+ }
+
+ isis_adj_state_change(adj, ISIS_ADJ_DOWN, "bfd session went down");
+}
+
static int isis_bfd_interface_dest_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
@@ -80,6 +115,27 @@ static int isis_bfd_interface_dest_update(int command, struct zclient *zclient,
dst_buf, ifp->name, bfd_get_status_str(status));
}
+ struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return 0;
+
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ struct list *adjdb = circuit->u.bc.adjdb[level - 1];
+
+ struct listnode *node, *nnode;
+ struct isis_adjacency *adj;
+
+ for (ALL_LIST_ELEMENTS(adjdb, node, nnode, adj))
+ bfd_adj_event(adj, &dst_ip, status);
+ }
+ } else if (circuit->circ_type == CIRCUIT_T_P2P) {
+ if (circuit->u.p2p.neighbor) {
+ bfd_adj_event(circuit->u.p2p.neighbor,
+ &dst_ip, status);
+ }
+ }
+
return 0;
}