From 7f198e063c77f1be8273d0449ddf1d1caa21f368 Mon Sep 17 00:00:00 2001 From: Hiroki Shirokura Date: Sun, 12 Dec 2021 09:43:37 +0000 Subject: [PATCH] isisd: add isis flex-algo base interface Adds basic functionality to Flex-Algo for IS-IS wrapping lib/flex_algo. The configuration interface will be added in the next commit. Signed-off-by: Hiroki Shirokura Signed-off-by: Eric Kinzie Signed-off-by: Louis Scalbert --- isisd/isis_flex_algo.c | 240 +++++++++++++++++++++++++++++++++++++++++ isisd/isis_flex_algo.h | 51 +++++++++ isisd/isis_tlvs.h | 15 +++ isisd/isisd.c | 8 ++ isisd/isisd.h | 4 + isisd/subdir.am | 2 + 6 files changed, 320 insertions(+) create mode 100644 isisd/isis_flex_algo.c create mode 100644 isisd/isis_flex_algo.h diff --git a/isisd/isis_flex_algo.c b/isisd/isis_flex_algo.c new file mode 100644 index 000000000000..94ad53b22671 --- /dev/null +++ b/isisd/isis_flex_algo.c @@ -0,0 +1,240 @@ +// 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 + +#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(*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]); +} + +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; +} + +#endif /* ifndef FABRICD */ diff --git a/isisd/isis_flex_algo.h b/isisd/isis_flex_algo.h new file mode 100644 index 000000000000..0a0e337e0172 --- /dev/null +++ b/isisd/isis_flex_algo.h @@ -0,0 +1,51 @@ +// 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.h: IS-IS Flexible Algorithm + * + * Authors + * ------- + * Hiroki Shirokura + * Masakazu Asama + * Louis Scalbert + */ + +#ifndef ISIS_FLEX_ALGO_H +#define ISIS_FLEX_ALGO_H + +#include "flex_algo.h" +#include "isisd/isis_constants.h" + +#ifndef FABRICD + +struct isis_flex_algo_data { + struct isis_spftree *spftree[SPFTREE_COUNT][ISIS_LEVELS]; + struct isis_area *area; +}; + +struct isis_flex_algo_alloc_arg { + uint8_t algorithm; + struct isis_area *area; +}; + +void *isis_flex_algo_data_alloc(void *arg); +void isis_flex_algo_data_free(void *data); + +struct isis_router_cap_fad * +isis_flex_algo_elected(int algorithm, const struct isis_area *area); +bool isis_flex_algo_supported(struct flex_algo *fad); +struct isis_router_cap_fad * +isis_flex_algo_elected_supported(int algorithm, const struct isis_area *area); +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); +struct isis_lsp; +bool sr_algorithm_participated(const struct isis_lsp *lsp, uint8_t algorithm); + +#endif /* ifndef FABRICD */ + +#endif /* ISIS_FLEX_ALGO_H */ diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 516d4b879c99..d5c96d7ab09d 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -12,6 +12,7 @@ #include "segment_routing.h" #include "openbsd-tree.h" #include "prefix.h" +#include "flex_algo.h" DECLARE_MTYPE(ISIS_SUBTLV); @@ -181,6 +182,15 @@ struct isis_lan_adj_sid { #define MSD_TYPE_BASE_MPLS_IMPOSITION 0x01 #define MSD_TLV_SIZE 2 +#ifndef FABRICD +struct isis_router_cap_fad; +struct isis_router_cap_fad { + uint8_t sysid[ISIS_SYS_ID_LEN + 2]; + + struct flex_algo fad; +}; +#endif /* ifndef FABRICD */ + struct isis_router_cap { struct in_addr router_id; uint8_t flags; @@ -191,6 +201,11 @@ struct isis_router_cap { uint8_t algo[SR_ALGORITHM_COUNT]; /* RFC 8491 */ uint8_t msd; + +#ifndef FABRICD + /* RFC9350 Flex-Algorithm */ + struct isis_router_cap_fad *fads[SR_ALGORITHM_COUNT]; +#endif /* ifndef FABRICD */ }; struct isis_item { diff --git a/isisd/isisd.c b/isisd/isisd.c index 088cc31910d3..6c4cdfb95b0f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -27,6 +27,7 @@ #include "zclient.h" #include "vrf.h" #include "spf_backoff.h" +#include "flex_algo.h" #include "lib/northbound_cli.h" #include "bfd.h" @@ -49,6 +50,7 @@ #include "isisd/isis_te.h" #include "isisd/isis_mt.h" #include "isisd/isis_sr.h" +#include "isisd/isis_flex_algo.h" #include "isisd/fabricd.h" #include "isisd/isis_nb.h" @@ -317,6 +319,12 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) if (area->is_type & IS_LEVEL_2) lsp_db_init(&area->lspdb[1]); +#ifndef FABRICD + /* Flex-Algo */ + area->flex_algos = flex_algos_alloc(isis_flex_algo_data_alloc, + isis_flex_algo_data_free); +#endif /* ifndef FABRICD */ + spftree_area_init(area); area->circuit_list = list_new(); diff --git a/isisd/isisd.h b/isisd/isisd.h index 12d9cd36c4f2..350d2c8d7225 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -220,6 +220,10 @@ struct isis_area { size_t tilfa_protected_links[ISIS_LEVELS]; /* MPLS LDP-IGP Sync */ struct ldp_sync_info_cmd ldp_sync_cmd; +#ifndef FABRICD + /* Flex-Algo */ + struct flex_algos *flex_algos; +#endif /* ifndef FABRICD */ /* Counters */ uint32_t circuit_state_changes; struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT] diff --git a/isisd/subdir.am b/isisd/subdir.am index dabf6a925ea0..49e252c85245 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -45,6 +45,7 @@ noinst_HEADERS += \ isisd/isis_spf.h \ isisd/isis_spf_private.h \ isisd/isis_sr.h \ + isisd/isis_flex_algo.h \ isisd/isis_te.h \ isisd/isis_tlvs.h \ isisd/isis_tx_queue.h \ @@ -76,6 +77,7 @@ LIBISIS_SOURCES = \ isisd/isis_routemap.c \ isisd/isis_spf.c \ isisd/isis_sr.c \ + isisd/isis_flex_algo.c \ isisd/isis_te.c \ isisd/isis_tlvs.c \ isisd/isis_tx_queue.c \