diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index a41d6ff81..9013c7c19 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -122,6 +122,8 @@ struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa, return NULL; } +DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)) + void isis_delete_adj(void *arg) { struct isis_adjacency *adj = arg; @@ -130,6 +132,10 @@ void isis_delete_adj(void *arg) return; THREAD_TIMER_OFF(adj->t_expire); + if (adj->adj_state != ISIS_ADJ_DOWN) { + adj->adj_state = ISIS_ADJ_DOWN; + hook_call(isis_adj_state_change_hook, adj); + } /* remove from SPF trees */ spftree_area_adj_del(adj->circuit->area, adj); @@ -256,8 +262,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; - isis_event_adjacency_state_change(adj, - new_state); + hook_call(isis_adj_state_change_hook, adj); /* update counter & timers for debugging * purposes */ adj->last_flap = time(NULL); @@ -270,8 +275,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, if (circuit->upadjcount[level - 1] == 0) isis_tx_queue_clean(circuit->tx_queue); - isis_event_adjacency_state_change(adj, - new_state); + hook_call(isis_adj_state_change_hook, adj); del = true; } @@ -299,8 +303,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; - isis_event_adjacency_state_change(adj, - new_state); + hook_call(isis_adj_state_change_hook, adj); if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) send_hello(circuit, level); @@ -326,8 +329,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, if (circuit->upadjcount[level - 1] == 0) isis_tx_queue_clean(circuit->tx_queue); - isis_event_adjacency_state_change(adj, - new_state); + hook_call(isis_adj_state_change_hook, adj); del = true; } } diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 2f39378c0..2a4cb6e61 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; @@ -114,6 +117,7 @@ void isis_delete_adj(void *adj); void isis_adj_process_threeway(struct isis_adjacency *adj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage); +DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)) void isis_adj_state_change(struct isis_adjacency *adj, enum isis_adj_state state, const char *reason); void isis_adj_print(struct isis_adjacency *adj); diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c new file mode 100644 index 000000000..81976f8dd --- /dev/null +++ b/isisd/isis_bfd.c @@ -0,0 +1,350 @@ +/* + * IS-IS Rout(e)ing protocol - BFD support + * Copyright (C) 2018 Christian Franke + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "zclient.h" +#include "bfd.h" + +#include "isisd/isis_bfd.h" +#include "isisd/isis_zebra.h" +#include "isisd/isis_common.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_circuit.h" +#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; + int status; +}; + +static struct bfd_session *bfd_session_new(struct in_addr *dst_ip, + struct in_addr *src_ip) +{ + struct bfd_session *rv; + + rv = XCALLOC(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 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) +{ + struct interface *ifp; + struct prefix dst_ip; + int status; + + ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, vrf_id); + if (!ifp || dst_ip.family != AF_INET) + return 0; + + if (isis->debugs & DEBUG_BFD) { + char dst_buf[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET, &dst_ip.u.prefix4, + dst_buf, sizeof(dst_buf)); + + zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s", + 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; +} + +static int isis_bfd_nbr_replay(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + + struct listnode *anode; + struct isis_area *area; + + if (isis->debugs & DEBUG_BFD) + zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors."); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + struct listnode *cnode; + struct isis_circuit *circuit; + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) + isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_UPDATE); + } + + if (isis->debugs & DEBUG_BFD) + zlog_debug("ISIS-BFD: Done with replay."); + + return 0; +} + +static void (*orig_zebra_connected)(struct zclient *); +static void isis_bfd_zebra_connected(struct zclient *zclient) +{ + if (orig_zebra_connected) + orig_zebra_connected(zclient); + + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); +} + +static void bfd_debug(struct in_addr *dst, struct in_addr *src, + const char *interface, int command) +{ + if (!(isis->debugs & DEBUG_BFD)) + return; + + char dst_str[INET6_ADDRSTRLEN]; + char src_str[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str)); + inet_ntop(AF_INET, src, src_str, sizeof(src_str)); + + const char *command_str; + + switch (command) { + case ZEBRA_BFD_DEST_REGISTER: + command_str = "Register"; + break; + case ZEBRA_BFD_DEST_DEREGISTER: + command_str = "Deregister"; + break; + case ZEBRA_BFD_DEST_UPDATE: + command_str = "Update"; + break; + default: + command_str = "Unknown-Cmd"; + break; + } + + zlog_debug("ISIS-BFD: %s peer %s on %s (src %s)", + command_str, dst_str, interface, src_str); +} + +static void bfd_handle_adj_down(struct isis_adjacency *adj) +{ + if (!adj->bfd_session) + return; + + bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, + adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER); + + 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_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, + circuit->interface->name, command); + 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, + uint32_t min_rx, uint32_t min_tx, + uint32_t detect_mult, int defaults) +{ + int command = 0; + + bfd_set_param(&circuit->bfd_info, min_rx, + min_tx, detect_mult, defaults, &command); + + if (command) + isis_bfd_circuit_cmd(circuit, command); +} + +static int bfd_circuit_write_settings(struct isis_circuit *circuit, + struct vty *vty) +{ + struct bfd_info *bfd_info = circuit->bfd_info; + + if (!bfd_info) + return 0; + + vty_out(vty, " %s bfd\n", PROTO_NAME); + return 1; +} + +void isis_bfd_init(void) +{ + bfd_gbl_init(); + + orig_zebra_connected = zclient->zebra_connected; + 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); +} diff --git a/isisd/isis_bfd.h b/isisd/isis_bfd.h new file mode 100644 index 000000000..3193f1606 --- /dev/null +++ b/isisd/isis_bfd.h @@ -0,0 +1,31 @@ +/* + * IS-IS Rout(e)ing protocol - BFD support + * Copyright (C) 2018 Christian Franke + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef ISIS_BFD_H +#define ISIS_BFD_H + +struct isis_circuit; + +void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command); +void isis_bfd_circuit_param_set(struct isis_circuit *circuit, + uint32_t min_rx, uint32_t min_tx, + uint32_t detect_mult, int defaults); +void isis_bfd_init(void); + +#endif + diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 58c6dfa36..74488a1fc 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -924,6 +924,10 @@ void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, return; } +DEFINE_HOOK(isis_circuit_config_write, + (struct isis_circuit *circuit, struct vty *vty), + (circuit, vty)) + int isis_interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); @@ -1138,7 +1142,8 @@ int isis_interface_config_write(struct vty *vty) circuit->passwd.passwd); write++; } - write += circuit_write_mt_settings(circuit, vty); + write += hook_call(isis_circuit_config_write, + circuit, vty); } vty_endframe(vty, "!\n"); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index ea68767fe..e83424a4a 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -65,6 +65,8 @@ struct isis_p2p_info { struct thread *t_send_p2p_hello; /* send P2P IIHs in this thread */ }; +struct bfd_info; + struct isis_circuit { int state; uint8_t circuit_id; /* l1/l2 bcast CircuitID */ @@ -127,6 +129,7 @@ struct isis_circuit { #define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01 uint8_t flags; bool disable_threeway_adj; + struct bfd_info *bfd_info; /* * Counters as in 10589--11.2.5.9 */ @@ -190,4 +193,8 @@ ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, bool enabled); +DECLARE_HOOK(isis_circuit_config_write, + (struct isis_circuit *circuit, struct vty *vty), + (circuit, vty)) + #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 5dcc0a132..9f58c24b7 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -216,25 +216,6 @@ void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) * * ***********************************************************************/ -void isis_event_adjacency_state_change(struct isis_adjacency *adj, int newstate) -{ - /* adjacency state change event. - * - the only proto-type was supported */ - - /* invalid arguments */ - if (!adj || !adj->circuit || !adj->circuit->area) - return; - - if (isis->debugs & DEBUG_EVENTS) - zlog_debug("ISIS-Evt (%s) Adjacency State change", - adj->circuit->area->area_tag); - - /* LSP generation again */ - lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); - - return; -} - /* events supporting code */ int isis_event_dis_status_change(struct thread *thread) diff --git a/isisd/isis_events.h b/isisd/isis_events.h index c3d8cf046..25643f4ed 100644 --- a/isisd/isis_events.h +++ b/isisd/isis_events.h @@ -31,9 +31,6 @@ void isis_event_circuit_type_change(struct isis_circuit *circuit, int newtype); /* * Events related to adjacencies */ -void isis_event_adjacency_state_change(struct isis_adjacency *adj, - int newstate); - int isis_event_dis_status_change(struct thread *thread); /* diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 1258bec06..61ba51ffb 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1997,3 +1997,15 @@ void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit) fabricd_lsp_flood(lsp); } } + +static int lsp_handle_adj_state_change(struct isis_adjacency *adj) +{ + lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); + return 0; +} + +void lsp_init(void) +{ + hook_register(isis_adj_state_change_hook, + lsp_handle_adj_state_change); +} diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 4e6379447..4beee1008 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -101,5 +101,6 @@ int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set); void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit); +void lsp_init(void); #endif /* ISIS_LSP */ diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 4d6a6da5d..7956ddeaf 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -55,6 +55,9 @@ #include "isisd/isis_te.h" #include "isisd/isis_errors.h" #include "isisd/isis_vty_common.h" +#include "isisd/isis_bfd.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_mt.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" @@ -213,11 +216,14 @@ int main(int argc, char **argv, char **envp) isis_redist_init(); isis_route_map_init(); isis_mpls_te_init(); + lsp_init(); + mt_init(); /* create the global 'isis' instance */ isis_new(1); isis_zebra_init(master); + isis_bfd_init(); frr_config_fork(); frr_run(master); diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index e0227f465..7493b90d3 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -302,7 +302,8 @@ circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid) return setting; } -int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty) +static int circuit_write_mt_settings(struct isis_circuit *circuit, + struct vty *vty) { int written = 0; struct listnode *node; @@ -551,3 +552,9 @@ void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id, metric, subtlvs, subtlv_len); } + +void mt_init(void) +{ + hook_register(isis_circuit_config_write, + circuit_write_mt_settings); +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 8c57d24af..515b63f50 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -109,7 +109,6 @@ void circuit_mt_init(struct isis_circuit *circuit); void circuit_mt_finish(struct isis_circuit *circuit); struct isis_circuit_mt_setting * circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid); -int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); struct isis_circuit_mt_setting ** circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count); bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, @@ -122,4 +121,5 @@ void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, uint8_t *id, uint32_t metric, uint8_t *subtlvs, uint8_t subtlv_len); +void mt_init(void); #endif diff --git a/isisd/isis_vty_common.c b/isisd/isis_vty_common.c index 2b98a88b3..c21176304 100644 --- a/isisd/isis_vty_common.c +++ b/isisd/isis_vty_common.c @@ -28,12 +28,14 @@ #include "command.h" #include "spf_backoff.h" +#include "bfd.h" #include "isis_circuit.h" #include "isis_csm.h" #include "isis_misc.h" #include "isis_mt.h" #include "isisd.h" +#include "isis_bfd.h" #include "isis_vty_common.h" struct isis_circuit *isis_circuit_lookup(struct vty *vty) @@ -498,6 +500,49 @@ DEFUN (no_circuit_topology, return isis_circuit_mt_enabled_set(circuit, mtid, false); } +DEFUN (isis_bfd, + isis_bfd_cmd, + PROTO_NAME " bfd", + PROTO_HELP + "Enable BFD support\n") +{ + struct isis_circuit *circuit = isis_circuit_lookup(vty); + + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (circuit->bfd_info + && CHECK_FLAG(circuit->bfd_info->flags, BFD_FLAG_PARAM_CFG)) { + return CMD_SUCCESS; + } + + isis_bfd_circuit_param_set(circuit, BFD_DEF_MIN_RX, + BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, true); + + return CMD_SUCCESS; +} + +DEFUN (no_isis_bfd, + no_isis_bfd_cmd, + "no " PROTO_NAME " bfd", + NO_STR + PROTO_HELP + "Disables BFD support\n" +) +{ + struct isis_circuit *circuit = isis_circuit_lookup(vty); + + if (!circuit) + return CMD_ERR_NO_MATCH; + + if (!circuit->bfd_info) + return CMD_SUCCESS; + + isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_DEREGISTER); + bfd_info_free(&circuit->bfd_info); + return CMD_SUCCESS; +} + DEFUN (set_overload_bit, set_overload_bit_cmd, "set-overload-bit", @@ -930,6 +975,9 @@ void isis_vty_init(void) install_element(INTERFACE_NODE, &circuit_topology_cmd); install_element(INTERFACE_NODE, &no_circuit_topology_cmd); + install_element(INTERFACE_NODE, &isis_bfd_cmd); + install_element(INTERFACE_NODE, &no_isis_bfd_cmd); + install_element(ROUTER_NODE, &set_overload_bit_cmd); install_element(ROUTER_NODE, &no_set_overload_bit_cmd); diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 4fbcf8721..20c10d0b2 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -27,6 +27,8 @@ extern struct zclient *zclient; void isis_zebra_init(struct thread_master *); void isis_zebra_stop(void); +struct isis_route_info; + void isis_zebra_route_update(struct prefix *prefix, struct prefix_ipv6 *src_p, struct isis_route_info *route_info); diff --git a/isisd/isisd.c b/isisd/isisd.c index e5e43c4b7..94e6a6385 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -746,6 +746,8 @@ void print_debug(struct vty *vty, int flags, int onoff) vty_out(vty, "IS-IS LSP scheduling debugging is %s\n", onoffs); if (flags & DEBUG_FABRICD_FLOODING) vty_out(vty, "OpenFabric Flooding debugging is %s\n", onoffs); + if (flags & DEBUG_BFD) + vty_out(vty, "IS-IS BFD debugging is %s\n", onoffs); } DEFUN_NOSH (show_debugging, @@ -831,6 +833,10 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug " PROTO_NAME " flooding\n"); write++; } + if (flags & DEBUG_BFD) { + vty_out(vty, "debug " PROTO_NAME " bfd\n"); + write++; + } write += spf_backoff_write_config(vty); return write; @@ -1214,6 +1220,33 @@ DEFUN (no_debug_isis_lsp_sched, return CMD_SUCCESS; } +DEFUN (debug_isis_bfd, + debug_isis_bfd_cmd, + "debug " PROTO_NAME " bfd", + DEBUG_STR + PROTO_HELP + PROTO_NAME " interaction with BFD\n") +{ + isis->debugs |= DEBUG_BFD; + print_debug(vty, DEBUG_BFD, 1); + + return CMD_SUCCESS; +} + +DEFUN (no_debug_isis_bfd, + no_debug_isis_bfd_cmd, + "no debug " PROTO_NAME " bfd", + NO_STR + UNDEBUG_STR + PROTO_HELP + PROTO_NAME " interaction with BFD\n") +{ + isis->debugs &= ~DEBUG_BFD; + print_debug(vty, DEBUG_BFD, 0); + + return CMD_SUCCESS; +} + DEFUN (show_hostname, show_hostname_cmd, "show " PROTO_NAME " hostname", @@ -2215,6 +2248,8 @@ void isis_init() install_element(ENABLE_NODE, &no_debug_isis_lsp_gen_cmd); install_element(ENABLE_NODE, &debug_isis_lsp_sched_cmd); install_element(ENABLE_NODE, &no_debug_isis_lsp_sched_cmd); + install_element(ENABLE_NODE, &debug_isis_bfd_cmd); + install_element(ENABLE_NODE, &no_debug_isis_bfd_cmd); install_element(CONFIG_NODE, &debug_isis_adj_cmd); install_element(CONFIG_NODE, &no_debug_isis_adj_cmd); @@ -2244,6 +2279,8 @@ void isis_init() install_element(CONFIG_NODE, &no_debug_isis_lsp_gen_cmd); install_element(CONFIG_NODE, &debug_isis_lsp_sched_cmd); install_element(CONFIG_NODE, &no_debug_isis_lsp_sched_cmd); + install_element(CONFIG_NODE, &debug_isis_bfd_cmd); + install_element(CONFIG_NODE, &no_debug_isis_bfd_cmd); install_element(CONFIG_NODE, &router_isis_cmd); install_element(CONFIG_NODE, &no_router_isis_cmd); diff --git a/isisd/isisd.h b/isisd/isisd.h index 864021428..7572f5517 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -211,6 +211,7 @@ extern struct thread_master *master; #define DEBUG_LSP_GEN (1<<13) #define DEBUG_LSP_SCHED (1<<14) #define DEBUG_FABRICD_FLOODING (1<<15) +#define DEBUG_BFD (1<<16) #define lsp_debug(...) \ do { \ diff --git a/isisd/subdir.am b/isisd/subdir.am index 7571255e5..552bc49b8 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -27,6 +27,7 @@ endif noinst_HEADERS += \ isisd/dict.h \ isisd/isis_adjacency.h \ + isisd/isis_bfd.h \ isisd/isis_circuit.h \ isisd/isis_common.h \ isisd/isis_constants.h \ @@ -60,6 +61,7 @@ noinst_HEADERS += \ LIBISIS_SOURCES = \ isisd/dict.c \ isisd/isis_adjacency.c \ + isisd/isis_bfd.c \ isisd/isis_circuit.c \ isisd/isis_csm.c \ isisd/isis_dr.c \ diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index b71124161..e4a4adba0 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -1030,8 +1030,7 @@ int zebra_ptm_bfd_client_deregister(struct zserv *client) char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; - if (proto != ZEBRA_ROUTE_OSPF && proto != ZEBRA_ROUTE_BGP - && proto != ZEBRA_ROUTE_OSPF6 && proto != ZEBRA_ROUTE_PIM) + if (!IS_BFD_ENABLED_PROTOCOL(proto)) return 0; if (IS_ZEBRA_DEBUG_EVENT) @@ -1310,17 +1309,8 @@ static void zebra_ptm_send_clients(struct stream *msg) /* Send message to all running client daemons. */ for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { - switch (client->proto) { - case ZEBRA_ROUTE_BGP: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_PIM: - break; - - default: - /* NOTHING: skip this daemon. */ + if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; - } zserv_send_message(client, msg); @@ -1341,23 +1331,9 @@ static int _zebra_ptm_bfd_client_deregister(struct zserv *zs) struct stream *msg; struct ptm_process *pp; - /* Filter daemons that must receive this treatment. */ - switch (zs->proto) { - case ZEBRA_ROUTE_BGP: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_PIM: - break; - - case ZEBRA_ROUTE_BFD: - /* Don't try to send BFDd messages to itself. */ + if (!IS_BFD_ENABLED_PROTOCOL(zs->proto)) return 0; - default: - /* Unsupported daemon. */ - return 0; - } - /* Find daemon pid by zebra connection pointer. */ pp = pp_lookup_byzs(zs); if (pp == NULL) { diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index ada4f7b4f..d0cdaf0bc 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -59,6 +59,15 @@ struct zebra_ptm_cb { #define ZEBRA_IF_PTM_ENABLE_ON 1 #define ZEBRA_IF_PTM_ENABLE_UNSPEC 2 +#define IS_BFD_ENABLED_PROTOCOL(protocol) ( \ + (protocol) == ZEBRA_ROUTE_BGP || \ + (protocol) == ZEBRA_ROUTE_OSPF || \ + (protocol) == ZEBRA_ROUTE_OSPF6 || \ + (protocol) == ZEBRA_ROUTE_ISIS || \ + (protocol) == ZEBRA_ROUTE_PIM || \ + (protocol) == ZEBRA_ROUTE_OPENFABRIC \ +) + void zebra_ptm_init(void); void zebra_ptm_finish(void); int zebra_ptm_connect(struct thread *t); diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 815f61d15..420105198 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -24,6 +24,7 @@ #include "stream.h" #include "zebra/zserv.h" #include "zebra/zapi_msg.h" +#include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" #include "zebra/zebra_memory.h" @@ -76,11 +77,7 @@ void zebra_interface_bfd_update(struct interface *ifp, struct prefix *dp, struct zserv *client; for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { - /* Supporting for OSPF, BGP and PIM */ - if (client->proto != ZEBRA_ROUTE_OSPF - && client->proto != ZEBRA_ROUTE_BGP - && client->proto != ZEBRA_ROUTE_OSPF6 - && client->proto != ZEBRA_ROUTE_PIM) + if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; /* Notify to the protocol daemons. */ @@ -110,11 +107,7 @@ void zebra_bfd_peer_replay_req(void) struct zserv *client; for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { - /* Supporting for BGP */ - if ((client->proto != ZEBRA_ROUTE_BGP) - && (client->proto != ZEBRA_ROUTE_OSPF) - && (client->proto != ZEBRA_ROUTE_OSPF6) - && (client->proto != ZEBRA_ROUTE_PIM)) + if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; /* Notify to the protocol daemons. */