From 20a42f0194ff04a7a9f358c6b1e024f340d18c0b Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Fri, 28 Sep 2018 17:05:15 +0200 Subject: [PATCH] isisd: Register/deregister BFD peers for adjacencies Signed-off-by: Christian Franke --- isisd/isis_adjacency.h | 3 + isisd/isis_bfd.c | 124 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 23b57ae1d9..2a4cb6e614 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -68,6 +68,8 @@ struct isis_dis_record { time_t last_dis_change; /* timestamp for last dis change */ }; +struct bfd_session; + struct isis_adjacency { uint8_t snpa[ETH_ALEN]; /* NeighbourSNPAAddress */ uint8_t sysid[ISIS_SYS_ID_LEN]; /* neighbourSystemIdentifier */ @@ -100,6 +102,7 @@ struct isis_adjacency { struct isis_circuit *circuit; /* back pointer */ uint16_t *mt_set; /* Topologies this adjacency is valid for */ unsigned int mt_count; /* Number of entries in mt_set */ + struct bfd_session *bfd_session; }; struct isis_threeway_adj; diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index eeacede764..2fee56827c 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -33,6 +33,33 @@ #include "isisd/isisd.h" #include "isisd/fabricd.h" +DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session") + +struct bfd_session { + struct in_addr dst_ip; + struct in_addr src_ip; +}; + +static struct bfd_session *bfd_session_new(struct in_addr *dst_ip, + struct in_addr *src_ip) +{ + struct bfd_session *rv; + + rv = XMALLOC(MTYPE_BFD_SESSION, sizeof(*rv)); + rv->dst_ip = *dst_ip; + rv->src_ip = *src_ip; + return rv; +} + +static void bfd_session_free(struct bfd_session **session) +{ + if (!*session) + return; + + XFREE(MTYPE_BFD_SESSION, *session); + *session = NULL; +} + static int isis_bfd_interface_dest_update(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { @@ -55,9 +82,102 @@ static void isis_bfd_zebra_connected(struct zclient *zclient) bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); } -void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command) +static void bfd_handle_adj_down(struct isis_adjacency *adj) +{ + if (!adj->bfd_session) + return; + + bfd_peer_sendmsg(zclient, NULL, AF_INET, + &adj->bfd_session->dst_ip, + &adj->bfd_session->src_ip, + adj->circuit->interface->name, + 0, /* ttl */ + 0, /* multihop */ + ZEBRA_BFD_DEST_DEREGISTER, + 0, /* set_flag */ + VRF_DEFAULT); + bfd_session_free(&adj->bfd_session); +} + +static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) { + struct isis_circuit *circuit = adj->circuit; + + if (!circuit->bfd_info + || !circuit->ip_router + || !adj->ipv4_address_count) + goto out; + + struct list *local_ips = fabricd_ip_addrs(adj->circuit); + if (!local_ips) + goto out; + + struct in_addr *dst_ip = &adj->ipv4_addresses[0]; + struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips)); + struct in_addr *src_ip = &local_ip->prefix; + + if (adj->bfd_session) { + if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr + || adj->bfd_session->src_ip.s_addr != src_ip->s_addr) + bfd_handle_adj_down(adj); + } + + if (!adj->bfd_session) + adj->bfd_session = bfd_session_new(dst_ip, src_ip); + + bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET, + &adj->bfd_session->dst_ip, + &adj->bfd_session->src_ip, + circuit->interface->name, + 0, /* ttl */ + 0, /* multihop */ + command, + 0, /* set flag */ + VRF_DEFAULT); return; +out: + bfd_handle_adj_down(adj); +} + +static int bfd_handle_adj_state_change(struct isis_adjacency *adj) +{ + if (adj->adj_state == ISIS_ADJ_UP) + bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER); + else + bfd_handle_adj_down(adj); + return 0; +} + +static void bfd_adj_cmd(struct isis_adjacency *adj, int command) +{ + if (adj->adj_state == ISIS_ADJ_UP + && command != ZEBRA_BFD_DEST_DEREGISTER) { + bfd_handle_adj_up(adj, command); + } else { + bfd_handle_adj_down(adj); + } +} + +void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command) +{ + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { + struct list *adjdb = circuit->u.bc.adjdb[level - 1]; + + struct listnode *node; + struct isis_adjacency *adj; + for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) + bfd_adj_cmd(adj, command); + } + break; + case CIRCUIT_T_P2P: + if (circuit->u.p2p.neighbor) + bfd_adj_cmd(circuit->u.p2p.neighbor, command); + break; + default: + break; + } } void isis_bfd_circuit_param_set(struct isis_circuit *circuit, @@ -100,6 +220,8 @@ void isis_bfd_init(void) zclient->zebra_connected = isis_bfd_zebra_connected; zclient->interface_bfd_dest_update = isis_bfd_interface_dest_update; zclient->bfd_dest_replay = isis_bfd_nbr_replay; + hook_register(isis_adj_state_change_hook, + bfd_handle_adj_state_change); hook_register(isis_circuit_config_write, bfd_circuit_write_settings); } -- 2.39.5