mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 08:28:50 +00:00 
			
		
		
		
	Use the struct instead of the pointer for flex-algo memory allocation. Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
		
			
				
	
	
		
			332 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*********************************************************************
 | 
						|
 * Copyright 2022 Hiroki Shirokura, LINE Corporation
 | 
						|
 * Copyright 2022 Masakazu Asama
 | 
						|
 * Copyright 2022 6WIND S.A.
 | 
						|
 *
 | 
						|
 * isis_flex_algo.c: IS-IS Flexible Algorithm
 | 
						|
 *
 | 
						|
 * Authors
 | 
						|
 * -------
 | 
						|
 * Hiroki Shirokura
 | 
						|
 * Masakazu Asama
 | 
						|
 * Louis Scalbert
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "memory.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "sbuf.h"
 | 
						|
#include "network.h"
 | 
						|
#include "command.h"
 | 
						|
#include "bitfield.h"
 | 
						|
 | 
						|
#include "isisd/isisd.h"
 | 
						|
#include "isisd/isis_tlvs.h"
 | 
						|
#include "isisd/isis_common.h"
 | 
						|
#include "isisd/isis_mt.h"
 | 
						|
#include "isisd/isis_misc.h"
 | 
						|
#include "isisd/isis_adjacency.h"
 | 
						|
#include "isisd/isis_circuit.h"
 | 
						|
#include "isisd/isis_pdu.h"
 | 
						|
#include "isisd/isis_lsp.h"
 | 
						|
#include "isisd/isis_spf.h"
 | 
						|
#include "isisd/isis_te.h"
 | 
						|
#include "isisd/isis_sr.h"
 | 
						|
#include "isisd/isis_spf_private.h"
 | 
						|
#include "isisd/isis_flex_algo.h"
 | 
						|
 | 
						|
#ifndef FABRICD
 | 
						|
DEFINE_MTYPE_STATIC(ISISD, FLEX_ALGO, "ISIS Flex Algo");
 | 
						|
 | 
						|
void *isis_flex_algo_data_alloc(void *voidarg)
 | 
						|
{
 | 
						|
	struct isis_flex_algo_alloc_arg *arg = voidarg;
 | 
						|
	struct isis_flex_algo_data *data;
 | 
						|
 | 
						|
	data = XCALLOC(MTYPE_FLEX_ALGO, sizeof(struct isis_flex_algo_data));
 | 
						|
 | 
						|
	for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
 | 
						|
		for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
 | 
						|
			if (!(arg->area->is_type & level))
 | 
						|
				continue;
 | 
						|
			data->spftree[tree][level - 1] = isis_spftree_new(
 | 
						|
				arg->area, &arg->area->lspdb[level - 1],
 | 
						|
				arg->area->isis->sysid, level, tree,
 | 
						|
				SPF_TYPE_FORWARD, 0, arg->algorithm);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return data;
 | 
						|
}
 | 
						|
 | 
						|
void isis_flex_algo_data_free(void *voiddata)
 | 
						|
{
 | 
						|
	struct isis_flex_algo_data *data = voiddata;
 | 
						|
 | 
						|
	for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++)
 | 
						|
		for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++)
 | 
						|
			if (data->spftree[tree][level - 1])
 | 
						|
				isis_spftree_del(
 | 
						|
					data->spftree[tree][level - 1]);
 | 
						|
	XFREE(MTYPE_FLEX_ALGO, data);
 | 
						|
}
 | 
						|
 | 
						|
static struct isis_router_cap_fad *
 | 
						|
isis_flex_algo_definition_cmp(struct isis_router_cap_fad *elected,
 | 
						|
			      struct isis_router_cap_fad *fa)
 | 
						|
{
 | 
						|
	if (!elected || fa->fad.priority > elected->fad.priority ||
 | 
						|
	    (fa->fad.priority == elected->fad.priority &&
 | 
						|
	     lsp_id_cmp(fa->sysid, elected->sysid) > 0))
 | 
						|
		return fa;
 | 
						|
 | 
						|
	return elected;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Look up the flex-algo definition with the highest priority in the LSP
 | 
						|
 * Database (LSDB). If the value of priority is the same, the flex-algo
 | 
						|
 * definition with the highest sysid will be selected.
 | 
						|
 * @param algorithm flex-algo algorithm number
 | 
						|
 * @param area pointer
 | 
						|
 * @param local router capability Flex-Algo Definition (FAD) double pointer.
 | 
						|
 *    - fad is NULL: use the local router capability FAD from LSDB for the
 | 
						|
 *      election.
 | 
						|
 *    - fad is not NULL and *fad is NULL: use no local router capability FAD for
 | 
						|
 *      the election.
 | 
						|
 *    - fad and *fad are not NULL: uses the *fad local definition instead of the
 | 
						|
 *      local definition from LSDB for the election.
 | 
						|
 * @return elected flex-algo-definition object if exist, else NULL
 | 
						|
 */
 | 
						|
static struct isis_router_cap_fad *
 | 
						|
_isis_flex_algo_elected(int algorithm, const struct isis_area *area,
 | 
						|
			struct isis_router_cap_fad **fad)
 | 
						|
{
 | 
						|
	struct flex_algo *flex_ago;
 | 
						|
	const struct isis_lsp *lsp;
 | 
						|
	struct isis_router_cap_fad *fa, *elected = NULL;
 | 
						|
 | 
						|
	if (!flex_algo_id_valid(algorithm))
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	/* No elected FAD if the algorithm is not locally configured */
 | 
						|
	flex_ago = flex_algo_lookup(area->flex_algos, algorithm);
 | 
						|
	if (!flex_ago)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	/* No elected FAD if no data-plane is enabled
 | 
						|
	 * Currently, only Segment-Routing MPLS is supported.
 | 
						|
	 * Segment-Routing SRv6 and IP will be configured in the future.
 | 
						|
	 */
 | 
						|
	if (!CHECK_FLAG(flex_ago->dataplanes, FLEX_ALGO_SR_MPLS))
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Perform FAD comparison. First, compare the priority, and if they are
 | 
						|
	 * the same, compare the sys-id.
 | 
						|
	 */
 | 
						|
	/* clang-format off */
 | 
						|
	frr_each_const(lspdb, &area->lspdb[ISIS_LEVEL1 - 1], lsp) {
 | 
						|
		/* clang-format on */
 | 
						|
 | 
						|
		if (!lsp->tlvs || !lsp->tlvs->router_cap)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (lsp->own_lsp && fad)
 | 
						|
			continue;
 | 
						|
 | 
						|
		fa = lsp->tlvs->router_cap->fads[algorithm];
 | 
						|
 | 
						|
		if (!fa)
 | 
						|
			continue;
 | 
						|
 | 
						|
		assert(algorithm == fa->fad.algorithm);
 | 
						|
 | 
						|
		memcpy(fa->sysid, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
 | 
						|
 | 
						|
		elected = isis_flex_algo_definition_cmp(elected, fa);
 | 
						|
	}
 | 
						|
 | 
						|
	if (fad && *fad)
 | 
						|
		elected = isis_flex_algo_definition_cmp(elected, *fad);
 | 
						|
 | 
						|
	return elected;
 | 
						|
}
 | 
						|
 | 
						|
struct isis_router_cap_fad *isis_flex_algo_elected(int algorithm,
 | 
						|
						   const struct isis_area *area)
 | 
						|
{
 | 
						|
	return _isis_flex_algo_elected(algorithm, area, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Check the Flex-Algo Definition is supported by the current FRR version
 | 
						|
 * @param flex-algo
 | 
						|
 * @return true if supported else false
 | 
						|
 */
 | 
						|
bool isis_flex_algo_supported(struct flex_algo *fad)
 | 
						|
{
 | 
						|
	if (fad->calc_type != CALC_TYPE_SPF)
 | 
						|
		return false;
 | 
						|
	if (fad->metric_type != MT_IGP)
 | 
						|
		return false;
 | 
						|
	if (fad->flags != 0)
 | 
						|
		return false;
 | 
						|
	if (fad->exclude_srlg)
 | 
						|
		return false;
 | 
						|
	if (fad->unsupported_subtlv)
 | 
						|
		return false;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Look for the elected Flex-Algo Definition and check that it is
 | 
						|
 * supported by the current FRR version
 | 
						|
 * @param algorithm flex-algo algorithm number
 | 
						|
 * @param area pointer
 | 
						|
 * @param local router capability Flex-Algo Definition (FAD) double pointer.
 | 
						|
 * @return elected flex-algo-definition object if exist and supported, else NULL
 | 
						|
 */
 | 
						|
static struct isis_router_cap_fad *
 | 
						|
_isis_flex_algo_elected_supported(int algorithm, const struct isis_area *area,
 | 
						|
				  struct isis_router_cap_fad **fad)
 | 
						|
{
 | 
						|
	struct isis_router_cap_fad *elected_fad;
 | 
						|
 | 
						|
	elected_fad = _isis_flex_algo_elected(algorithm, area, fad);
 | 
						|
	if (!elected_fad)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	if (isis_flex_algo_supported(&elected_fad->fad))
 | 
						|
		return elected_fad;
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
struct isis_router_cap_fad *
 | 
						|
isis_flex_algo_elected_supported(int algorithm, const struct isis_area *area)
 | 
						|
{
 | 
						|
	return _isis_flex_algo_elected_supported(algorithm, area, NULL);
 | 
						|
}
 | 
						|
 | 
						|
struct isis_router_cap_fad *
 | 
						|
isis_flex_algo_elected_supported_local_fad(int algorithm,
 | 
						|
					   const struct isis_area *area,
 | 
						|
					   struct isis_router_cap_fad **fad)
 | 
						|
{
 | 
						|
	return _isis_flex_algo_elected_supported(algorithm, area, fad);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Check LSP is participating specified SR Algorithm
 | 
						|
 *
 | 
						|
 * @param lsp        IS-IS lsp
 | 
						|
 * @param algorithm  SR Algorithm
 | 
						|
 * @return           Return true if sr-algorithm tlv includes specified
 | 
						|
 *                   algorithm in router capability tlv
 | 
						|
 */
 | 
						|
bool sr_algorithm_participated(const struct isis_lsp *lsp, uint8_t algorithm)
 | 
						|
{
 | 
						|
	if (!lsp || !lsp->tlvs || !lsp->tlvs->router_cap)
 | 
						|
		return false;
 | 
						|
	for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
 | 
						|
		if (lsp->tlvs->router_cap->algo[i] == algorithm)
 | 
						|
			return true;
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
bool isis_flex_algo_constraint_drop(struct isis_spftree *spftree,
 | 
						|
				    struct isis_lsp *lsp,
 | 
						|
				    struct isis_extended_reach *reach)
 | 
						|
{
 | 
						|
	bool ret;
 | 
						|
	struct isis_ext_subtlvs *subtlvs = reach->subtlvs;
 | 
						|
	struct isis_router_cap_fad *fad;
 | 
						|
	struct isis_asla_subtlvs *asla;
 | 
						|
	struct listnode *node;
 | 
						|
	uint32_t *link_admin_group = NULL;
 | 
						|
	uint32_t link_ext_admin_group_bitmap0;
 | 
						|
	struct admin_group *link_ext_admin_group = NULL;
 | 
						|
 | 
						|
	fad = isis_flex_algo_elected_supported(spftree->algorithm,
 | 
						|
					       spftree->area);
 | 
						|
	if (!fad)
 | 
						|
		return true;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(subtlvs->aslas, node, asla)) {
 | 
						|
		if (!CHECK_FLAG(asla->standard_apps, ISIS_SABM_FLAG_X))
 | 
						|
			continue;
 | 
						|
		if (asla->legacy) {
 | 
						|
			if (IS_SUBTLV(subtlvs, EXT_ADM_GRP))
 | 
						|
				link_admin_group = &subtlvs->adm_group;
 | 
						|
 | 
						|
			if (IS_SUBTLV(subtlvs, EXT_EXTEND_ADM_GRP) &&
 | 
						|
			    admin_group_nb_words(&subtlvs->ext_admin_group) !=
 | 
						|
				    0)
 | 
						|
				link_ext_admin_group =
 | 
						|
					&subtlvs->ext_admin_group;
 | 
						|
		} else {
 | 
						|
			if (IS_SUBTLV(asla, EXT_ADM_GRP))
 | 
						|
				link_admin_group = &asla->admin_group;
 | 
						|
			if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) &&
 | 
						|
			    admin_group_nb_words(&asla->ext_admin_group) != 0)
 | 
						|
				link_ext_admin_group = &asla->ext_admin_group;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* RFC7308 section 2.3.1
 | 
						|
	 * A receiving node that notices that the AG differs from the first 32
 | 
						|
	 * bits of the EAG SHOULD report this mismatch to the operator.
 | 
						|
	 */
 | 
						|
	if (link_admin_group && link_ext_admin_group) {
 | 
						|
		link_ext_admin_group_bitmap0 =
 | 
						|
			admin_group_get_offset(link_ext_admin_group, 0);
 | 
						|
		if (*link_admin_group != link_ext_admin_group_bitmap0)
 | 
						|
			zlog_warn(
 | 
						|
				"ISIS-SPF: LSP from %pPN neighbor %pPN. Admin-group 0x%08x differs from ext admin-group 0x%08x.",
 | 
						|
				lsp->hdr.lsp_id, reach->id, *link_admin_group,
 | 
						|
				link_ext_admin_group_bitmap0);
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Exclude Any
 | 
						|
	 */
 | 
						|
	if (!admin_group_zero(&fad->fad.admin_group_exclude_any)) {
 | 
						|
		ret = admin_group_match_any(&fad->fad.admin_group_exclude_any,
 | 
						|
					    link_admin_group,
 | 
						|
					    link_ext_admin_group);
 | 
						|
		if (ret)
 | 
						|
			return true;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Include Any
 | 
						|
	 */
 | 
						|
	if (!admin_group_zero(&fad->fad.admin_group_include_any)) {
 | 
						|
		ret = admin_group_match_any(&fad->fad.admin_group_include_any,
 | 
						|
					    link_admin_group,
 | 
						|
					    link_ext_admin_group);
 | 
						|
		if (!ret)
 | 
						|
			return true;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Include All
 | 
						|
	 */
 | 
						|
	if (!admin_group_zero(&fad->fad.admin_group_include_all)) {
 | 
						|
		ret = admin_group_match_all(&fad->fad.admin_group_include_all,
 | 
						|
					    link_admin_group,
 | 
						|
					    link_ext_admin_group);
 | 
						|
		if (!ret)
 | 
						|
			return true;
 | 
						|
	}
 | 
						|
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* ifndef FABRICD */
 |