mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 08:28:50 +00:00 
			
		
		
		
	We should probably prevent any type of namespace collision with something else. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			324 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/**
 | 
						|
 * ospf_bfd.c: OSPF BFD handling routines
 | 
						|
 *
 | 
						|
 * @copyright Copyright (C) 2015 Cumulus Networks, Inc.
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "command.h"
 | 
						|
#include "json.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "frrevent.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 event_loop *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);
 | 
						|
}
 |