diff options
Diffstat (limited to 'ospfd/ospf_bfd.c')
-rw-r--r-- | ospfd/ospf_bfd.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c new file mode 100644 index 0000000..fb117ec --- /dev/null +++ b/ospfd/ospf_bfd.c @@ -0,0 +1,338 @@ +/** + * ospf_bfd.c: OSPF BFD handling routines + * + * @copyright Copyright (C) 2015 Cumulus Networks, Inc. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 <zebra.h> + +#include "command.h" +#include "json.h" +#include "linklist.h" +#include "memory.h" +#include "prefix.h" +#include "thread.h" +#include "buffer.h" +#include "stream.h" +#include "zclient.h" +#include "vty.h" +#include "table.h" +#include "bfd.h" +#include "ospfd.h" +#include "ospf_asbr.h" +#include "ospf_lsa.h" +#include "ospf_lsdb.h" +#include "ospf_neighbor.h" +#include "ospf_interface.h" +#include "ospf_nsm.h" +#include "ospf_bfd.h" +#include "ospf_dump.h" +#include "ospf_vty.h" + +DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data"); + +/* + * ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when + * neighbor state is changed to/from 2way. + */ +void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state) +{ + if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay)) + bfd_sess_install(nbr->bfd_session); + else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay)) + bfd_sess_uninstall(nbr->bfd_session); +} + +static void ospf_bfd_session_change(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg) +{ + struct ospf_neighbor *nbr = arg; + + /* BFD peer went down. */ + if (bss->state == BFD_STATUS_DOWN + && bss->previous_state == BFD_STATUS_UP) { + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); + + OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); + } + + /* BFD peer went up. */ + if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN) + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); +} + +void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr) +{ + struct ospf_interface *oi = nbr->oi; + struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp); + + /* BFD configuration was removed. */ + if (oip->bfd_config == NULL) { + bfd_sess_free(&nbr->bfd_session); + return; + } + + /* New BFD session. */ + if (nbr->bfd_session == NULL) { + nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr); + bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src); + bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name); + bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id); + } + + /* Set new configuration. */ + bfd_sess_set_timers(nbr->bfd_session, + oip->bfd_config->detection_multiplier, + oip->bfd_config->min_rx, oip->bfd_config->min_tx); + bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile); + + /* Don't start sessions on down OSPF sessions. */ + if (nbr->state < NSM_TwoWay) + return; + + bfd_sess_install(nbr->bfd_session); +} + +static void ospf_interface_bfd_apply(struct interface *ifp) +{ + struct ospf_interface *oi; + struct route_table *nbrs; + struct ospf_neighbor *nbr; + struct route_node *irn; + struct route_node *nrn; + + /* Iterate over all interfaces and set neighbors BFD session. */ + for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) { + if ((oi = irn->info) == NULL) + continue; + if ((nbrs = oi->nbrs) == NULL) + continue; + for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) { + if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self) + continue; + + ospf_neighbor_bfd_apply(nbr); + } + } +} + +static void ospf_interface_enable_bfd(struct interface *ifp) +{ + struct ospf_if_params *oip = IF_DEF_PARAMS(ifp); + + if (oip->bfd_config) + return; + + /* Allocate memory for configurations and set defaults. */ + oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config)); + oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + oip->bfd_config->min_rx = BFD_DEF_MIN_RX; + oip->bfd_config->min_tx = BFD_DEF_MIN_TX; +} + +void ospf_interface_disable_bfd(struct interface *ifp, + struct ospf_if_params *oip) +{ + XFREE(MTYPE_BFD_CONFIG, oip->bfd_config); + ospf_interface_bfd_apply(ifp); +} + +/* + * ospf_bfd_write_config - Write the interface BFD configuration. + */ +void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params + __attribute__((unused))) +{ +#if HAVE_BFDD == 0 + if (params->bfd_config->detection_multiplier != BFD_DEF_DETECT_MULT + || params->bfd_config->min_rx != BFD_DEF_MIN_RX + || params->bfd_config->min_tx != BFD_DEF_MIN_TX) + vty_out(vty, " ip ospf bfd %d %d %d\n", + params->bfd_config->detection_multiplier, + params->bfd_config->min_rx, params->bfd_config->min_tx); + else +#endif /* ! HAVE_BFDD */ + vty_out(vty, " ip ospf bfd\n"); + + if (params->bfd_config->profile[0]) + vty_out(vty, " ip ospf bfd profile %s\n", + params->bfd_config->profile); +} + +void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp, + struct json_object *json) +{ + struct ospf_if_params *params = IF_DEF_PARAMS(ifp); + struct bfd_configuration *bfd_config = params->bfd_config; + struct json_object *json_bfd; + + if (bfd_config == NULL) + return; + + if (json) { + json_bfd = json_object_new_object(); + json_object_int_add(json_bfd, "detectionMultiplier", + bfd_config->detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + bfd_config->min_rx); + json_object_int_add(json_bfd, "txMinInterval", + bfd_config->min_tx); + json_object_object_add(json, "peerBfdInfo", json_bfd); + } else + vty_out(vty, + " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + bfd_config->detection_multiplier, bfd_config->min_rx, + bfd_config->min_tx); +} + +DEFUN (ip_ospf_bfd, + ip_ospf_bfd_cmd, + "ip ospf bfd", + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + ospf_interface_enable_bfd(ifp); + ospf_interface_bfd_apply(ifp); + return CMD_SUCCESS; +} + +#if HAVE_BFDD > 0 +DEFUN_HIDDEN( +#else +DEFUN( +#endif /* HAVE_BFDD */ + ip_ospf_bfd_param, + ip_ospf_bfd_param_cmd, + "ip ospf bfd (2-255) (50-60000) (50-60000)", + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + "Detect Multiplier\n" + "Required min receive interval\n" + "Desired min transmit interval\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + int idx_number = 3; + int idx_number_2 = 4; + int idx_number_3 = 5; + + ospf_interface_enable_bfd(ifp); + + params = IF_DEF_PARAMS(ifp); + params->bfd_config->detection_multiplier = + strtol(argv[idx_number]->arg, NULL, 10); + params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10); + params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10); + + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} + +DEFUN (ip_ospf_bfd_prof, + ip_ospf_bfd_prof_cmd, + "ip ospf bfd profile BFDPROF", + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + int idx_prof = 4; + + params = IF_DEF_PARAMS(ifp); + if (!params->bfd_config) { + vty_out(vty, "ip ospf bfd has not been set\n"); + return CMD_WARNING; + } + + strlcpy(params->bfd_config->profile, argv[idx_prof]->arg, + sizeof(params->bfd_config->profile)); + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_bfd_prof, + no_ip_ospf_bfd_prof_cmd, + "no ip ospf bfd profile [BFDPROF]", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + if (!params->bfd_config) + return CMD_SUCCESS; + + params->bfd_config->profile[0] = 0; + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_bfd, + no_ip_ospf_bfd_cmd, +#if HAVE_BFDD > 0 + "no ip ospf bfd", +#else + "no ip ospf bfd [(2-255) (50-60000) (50-60000)]", +#endif /* HAVE_BFDD */ + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Disables BFD support\n" +#if HAVE_BFDD == 0 + "Detect Multiplier\n" + "Required min receive interval\n" + "Desired min transmit interval\n" +#endif /* !HAVE_BFDD */ +) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp)); + return CMD_SUCCESS; +} + +void ospf_bfd_init(struct thread_master *tm) +{ + bfd_protocol_integration_init(zclient, tm); + + /* Install BFD command */ + install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd); + install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd); + install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd); + install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd); + install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd); +} |