2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* IS-IS Rout(e)ing protocol - isis_spf.c
|
|
|
|
* The SPT algorithm
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001,2002 Sampo Saaristo
|
|
|
|
* Tampere University of Technology
|
|
|
|
* Institute of Communications Engineering
|
2017-04-27 12:54:21 +02:00
|
|
|
* Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2023-03-07 20:22:48 +01:00
|
|
|
#include "frrevent.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "linklist.h"
|
|
|
|
#include "vty.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "command.h"
|
2020-08-23 04:24:06 +02:00
|
|
|
#include "termtable.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "memory.h"
|
|
|
|
#include "prefix.h"
|
2020-11-07 01:15:39 +01:00
|
|
|
#include "filter.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "if.h"
|
2020-10-24 02:05:30 +02:00
|
|
|
#include "hash.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "table.h"
|
2017-02-21 23:52:29 +01:00
|
|
|
#include "spf_backoff.h"
|
2018-07-26 22:53:08 +02:00
|
|
|
#include "srcdest_table.h"
|
2020-07-13 14:37:59 +02:00
|
|
|
#include "vrf.h"
|
2022-09-02 16:33:52 +02:00
|
|
|
#include "lib/json.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2020-10-24 02:05:30 +02:00
|
|
|
#include "isis_errors.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "isis_constants.h"
|
|
|
|
#include "isis_common.h"
|
2012-03-24 16:35:20 +01:00
|
|
|
#include "isis_flags.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "isisd.h"
|
|
|
|
#include "isis_misc.h"
|
|
|
|
#include "isis_adjacency.h"
|
|
|
|
#include "isis_circuit.h"
|
|
|
|
#include "isis_pdu.h"
|
|
|
|
#include "isis_lsp.h"
|
|
|
|
#include "isis_dynhn.h"
|
|
|
|
#include "isis_spf.h"
|
|
|
|
#include "isis_route.h"
|
|
|
|
#include "isis_csm.h"
|
2017-04-27 13:56:47 +02:00
|
|
|
#include "isis_mt.h"
|
2017-07-23 15:06:09 +02:00
|
|
|
#include "isis_tlvs.h"
|
2022-01-21 15:54:15 +01:00
|
|
|
#include "isis_flex_algo.h"
|
2020-11-26 03:39:09 +01:00
|
|
|
#include "isis_zebra.h"
|
2018-04-02 18:39:46 +02:00
|
|
|
#include "fabricd.h"
|
2018-05-10 18:52:17 +02:00
|
|
|
#include "isis_spf_private.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2021-03-22 18:27:58 +01:00
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPFTREE, "ISIS SPFtree");
|
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
|
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
|
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX, "ISIS vertex");
|
2020-08-23 05:22:32 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency");
|
|
|
|
|
|
|
|
static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
|
|
|
|
struct list *adj_list, struct isis_lsp *lsp,
|
|
|
|
const uint8_t *pseudo_nodeid,
|
|
|
|
uint32_t pseudo_metric);
|
2017-04-27 12:54:21 +02:00
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
/*
|
|
|
|
* supports the given af ?
|
|
|
|
*/
|
|
|
|
static bool speaks(uint8_t *protocols, uint8_t count, int family)
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
|
|
if (family == AF_INET && protocols[i] == NLPID_IP)
|
|
|
|
return true;
|
|
|
|
if (family == AF_INET6 && protocols[i] == NLPID_IPV6)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
struct isis_spf_run {
|
|
|
|
struct isis_area *area;
|
|
|
|
int level;
|
|
|
|
};
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* 7.2.7 */
|
|
|
|
static void remove_excess_adjs(struct list *adjs)
|
|
|
|
{
|
2005-09-28 20:45:54 +02:00
|
|
|
struct listnode *node, *excess = NULL;
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_vertex_adj *vadj, *candidate = NULL;
|
2003-12-23 09:09:43 +01:00
|
|
|
int comp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(adjs, node, vadj)) {
|
|
|
|
struct isis_adjacency *adj, *candidate_adj;
|
|
|
|
|
|
|
|
adj = vadj->sadj->adj;
|
|
|
|
assert(adj);
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (excess == NULL)
|
|
|
|
excess = node;
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
candidate = listgetdata(excess);
|
2020-08-23 05:22:32 +02:00
|
|
|
candidate_adj = candidate->sadj->adj;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (candidate_adj->sys_type < adj->sys_type) {
|
2004-09-10 22:48:21 +02:00
|
|
|
excess = node;
|
|
|
|
continue;
|
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
if (candidate_adj->sys_type > adj->sys_type)
|
2004-09-10 22:48:21 +02:00
|
|
|
continue;
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
comp = memcmp(candidate_adj->sysid, adj->sysid,
|
|
|
|
ISIS_SYS_ID_LEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (comp > 0) {
|
|
|
|
excess = node;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (comp < 0)
|
|
|
|
continue;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (candidate_adj->circuit->idx > adj->circuit->idx) {
|
2004-09-10 22:48:21 +02:00
|
|
|
excess = node;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (candidate_adj->circuit->idx < adj->circuit->idx)
|
2004-09-10 22:48:21 +02:00
|
|
|
continue;
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
comp = memcmp(candidate_adj->snpa, adj->snpa, ETH_ALEN);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (comp > 0) {
|
|
|
|
excess = node;
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
list_delete_node(adjs, excess);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
const char *vtype2string(enum vertextype vtype)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2004-09-10 22:48:21 +02:00
|
|
|
switch (vtype) {
|
|
|
|
case VTYPE_PSEUDO_IS:
|
|
|
|
return "pseudo_IS";
|
2005-09-26 20:15:36 +02:00
|
|
|
case VTYPE_PSEUDO_TE_IS:
|
|
|
|
return "pseudo_TE-IS";
|
2004-09-10 22:48:21 +02:00
|
|
|
case VTYPE_NONPSEUDO_IS:
|
|
|
|
return "IS";
|
2005-09-26 20:15:36 +02:00
|
|
|
case VTYPE_NONPSEUDO_TE_IS:
|
|
|
|
return "TE-IS";
|
2004-09-10 22:48:21 +02:00
|
|
|
case VTYPE_ES:
|
|
|
|
return "ES";
|
|
|
|
case VTYPE_IPREACH_INTERNAL:
|
|
|
|
return "IP internal";
|
|
|
|
case VTYPE_IPREACH_EXTERNAL:
|
|
|
|
return "IP external";
|
2005-09-26 20:15:36 +02:00
|
|
|
case VTYPE_IPREACH_TE:
|
|
|
|
return "IP TE";
|
2004-09-10 22:48:21 +02:00
|
|
|
case VTYPE_IP6REACH_INTERNAL:
|
|
|
|
return "IP6 internal";
|
|
|
|
case VTYPE_IP6REACH_EXTERNAL:
|
|
|
|
return "IP6 external";
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
2017-04-27 12:54:21 +02:00
|
|
|
return NULL; /* Not reached */
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
const char *vid2string(const struct isis_vertex *vertex, char *buff, int size)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-04-27 12:54:21 +02:00
|
|
|
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
|
2020-08-21 02:24:07 +02:00
|
|
|
const char *hostname = print_sys_hostname(vertex->N.id);
|
|
|
|
strlcpy(buff, hostname, size);
|
|
|
|
return buff;
|
2017-04-27 12:54:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
if (VTYPE_IP(vertex->type)) {
|
2020-09-20 07:39:28 +02:00
|
|
|
srcdest2str(&vertex->N.ip.p.dest, &vertex->N.ip.p.src, buff,
|
|
|
|
size);
|
2017-04-27 12:54:21 +02:00
|
|
|
return buff;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
return "UNKNOWN";
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-10-24 02:05:30 +02:00
|
|
|
static bool prefix_sid_cmp(const void *value1, const void *value2)
|
|
|
|
{
|
|
|
|
const struct isis_vertex *c1 = value1;
|
|
|
|
const struct isis_vertex *c2 = value2;
|
|
|
|
|
|
|
|
if (CHECK_FLAG(c1->N.ip.sr.sid.flags,
|
|
|
|
ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)
|
|
|
|
!= CHECK_FLAG(c2->N.ip.sr.sid.flags,
|
|
|
|
ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return c1->N.ip.sr.sid.value == c2->N.ip.sr.sid.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int prefix_sid_key_make(const void *value)
|
|
|
|
{
|
|
|
|
const struct isis_vertex *vertex = value;
|
|
|
|
|
|
|
|
return jhash_1word(vertex->N.ip.sr.sid.value, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree,
|
|
|
|
struct isis_prefix_sid *psid)
|
|
|
|
{
|
|
|
|
struct isis_vertex lookup = {};
|
|
|
|
|
|
|
|
lookup.N.ip.sr.sid = *psid;
|
|
|
|
return hash_lookup(spftree->prefix_sids, &lookup);
|
|
|
|
}
|
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
void isis_vertex_adj_free(void *arg)
|
2020-08-23 05:22:32 +02:00
|
|
|
{
|
|
|
|
struct isis_vertex_adj *vadj = arg;
|
|
|
|
|
|
|
|
XFREE(MTYPE_ISIS_VERTEX_ADJ, vadj);
|
|
|
|
}
|
|
|
|
|
2018-05-10 20:02:04 +02:00
|
|
|
static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
|
2018-08-09 20:37:30 +02:00
|
|
|
void *id,
|
2018-06-25 12:16:32 +02:00
|
|
|
enum vertextype vtype)
|
2017-08-03 14:30:32 +02:00
|
|
|
{
|
|
|
|
struct isis_vertex *vertex;
|
|
|
|
|
|
|
|
vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
|
|
|
|
|
2018-08-09 20:37:30 +02:00
|
|
|
isis_vertex_id_init(vertex, id, vtype);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
vertex->Adj_N = list_new();
|
2020-08-23 05:22:32 +02:00
|
|
|
vertex->Adj_N->del = isis_vertex_adj_free;
|
2012-03-24 16:35:20 +01:00
|
|
|
vertex->parents = list_new();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) {
|
2018-05-10 20:02:04 +02:00
|
|
|
vertex->firsthops = hash_create(isis_vertex_queue_hash_key,
|
|
|
|
isis_vertex_queue_hash_cmp,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return vertex;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2021-03-22 18:27:58 +01:00
|
|
|
void isis_vertex_del(struct isis_vertex *vertex)
|
|
|
|
{
|
|
|
|
list_delete(&vertex->Adj_N);
|
|
|
|
list_delete(&vertex->parents);
|
2023-03-21 13:54:21 +01:00
|
|
|
hash_clean_and_free(&vertex->firsthops, NULL);
|
2021-03-22 18:27:58 +01:00
|
|
|
|
|
|
|
memset(vertex, 0, sizeof(struct isis_vertex));
|
|
|
|
XFREE(MTYPE_ISIS_VERTEX, vertex);
|
|
|
|
}
|
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
struct isis_vertex_adj *
|
|
|
|
isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
|
|
|
|
struct list *vadj_list, struct isis_spf_adj *sadj,
|
|
|
|
struct isis_prefix_sid *psid, bool last_hop)
|
2020-08-23 05:22:32 +02:00
|
|
|
{
|
|
|
|
struct isis_vertex_adj *vadj;
|
|
|
|
|
|
|
|
vadj = XCALLOC(MTYPE_ISIS_VERTEX_ADJ, sizeof(*vadj));
|
|
|
|
vadj->sadj = sadj;
|
2022-04-08 17:10:25 +02:00
|
|
|
if (spftree->area->srdb.enabled && psid) {
|
2020-09-20 07:39:28 +02:00
|
|
|
if (vertex->N.ip.sr.present
|
|
|
|
&& vertex->N.ip.sr.sid.value != psid->value)
|
|
|
|
zlog_warn(
|
|
|
|
"ISIS-SPF: ignoring different Prefix-SID for route %pFX",
|
|
|
|
&vertex->N.ip.p.dest);
|
|
|
|
else {
|
|
|
|
vadj->sr.sid = *psid;
|
|
|
|
vadj->sr.label = sr_prefix_out_label(
|
|
|
|
spftree->lspdb, vertex->N.ip.p.dest.family,
|
|
|
|
psid, sadj->id, last_hop);
|
|
|
|
if (vadj->sr.label != MPLS_INVALID_LABEL)
|
|
|
|
vadj->sr.present = true;
|
|
|
|
}
|
|
|
|
}
|
2020-11-07 01:15:39 +01:00
|
|
|
listnode_add(vadj_list, vadj);
|
2020-08-23 05:22:32 +02:00
|
|
|
|
|
|
|
return vadj;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static void isis_vertex_adj_del(struct isis_vertex *vertex,
|
|
|
|
struct isis_adjacency *adj)
|
|
|
|
{
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_vertex_adj *vadj;
|
2012-03-24 16:35:20 +01:00
|
|
|
struct listnode *node, *nextnode;
|
2020-08-23 05:22:32 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!vertex)
|
|
|
|
return;
|
2020-08-23 05:22:32 +02:00
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(vertex->Adj_N, node, nextnode, vadj)) {
|
|
|
|
if (vadj->sadj->adj == adj) {
|
|
|
|
listnode_delete(vertex->Adj_N, vadj);
|
|
|
|
isis_vertex_adj_free(vadj);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
|
|
|
|
const struct isis_vertex *vertex,
|
|
|
|
const struct isis_spf_adj *sadj)
|
|
|
|
{
|
|
|
|
struct isis_vertex_adj *tmp;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, tmp)) {
|
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
|
|
|
|
if (memcmp(sadj->id, tmp->sadj->id, sizeof(sadj->id))
|
|
|
|
== 0)
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (sadj->adj == tmp->sadj->adj)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void isis_spf_adj_free(void *arg)
|
|
|
|
{
|
|
|
|
struct isis_spf_adj *sadj = arg;
|
|
|
|
|
|
|
|
XFREE(MTYPE_ISIS_SPF_ADJ, sadj);
|
|
|
|
}
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
static void _isis_spftree_init(struct isis_spftree *tree)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2017-09-22 21:20:03 +02:00
|
|
|
isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
|
|
|
|
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
|
2018-07-26 22:53:08 +02:00
|
|
|
tree->route_table = srcdest_table_init();
|
2020-08-21 00:55:42 +02:00
|
|
|
tree->route_table->cleanup = isis_route_node_cleanup;
|
2022-01-21 15:54:15 +01:00
|
|
|
tree->route_table->info = isis_route_table_info_alloc(tree->algorithm);
|
2020-08-21 00:55:42 +02:00
|
|
|
tree->route_table_backup = srcdest_table_init();
|
2022-01-21 15:54:15 +01:00
|
|
|
tree->route_table_backup->info =
|
|
|
|
isis_route_table_info_alloc(tree->algorithm);
|
2020-08-21 00:55:42 +02:00
|
|
|
tree->route_table_backup->cleanup = isis_route_node_cleanup;
|
2020-10-24 02:05:30 +02:00
|
|
|
tree->prefix_sids = hash_create(prefix_sid_key_make, prefix_sid_cmp,
|
|
|
|
"SR Prefix-SID Entries");
|
2020-08-23 05:22:32 +02:00
|
|
|
tree->sadj_list = list_new();
|
|
|
|
tree->sadj_list->del = isis_spf_adj_free;
|
2022-01-21 15:54:15 +01:00
|
|
|
isis_rlfa_list_init(tree);
|
|
|
|
tree->lfa.remote.pc_spftrees = list_new();
|
|
|
|
tree->lfa.remote.pc_spftrees->del = (void (*)(void *))isis_spftree_del;
|
|
|
|
if (tree->type == SPF_TYPE_RLFA || tree->type == SPF_TYPE_TI_LFA) {
|
|
|
|
isis_spf_node_list_init(&tree->lfa.p_space);
|
|
|
|
isis_spf_node_list_init(&tree->lfa.q_space);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_spftree *
|
|
|
|
isis_spftree_new(struct isis_area *area, struct lspdb_head *lspdb,
|
|
|
|
const uint8_t *sysid, int level, enum spf_tree_id tree_id,
|
|
|
|
enum spf_type type, uint8_t flags, uint8_t algorithm)
|
|
|
|
{
|
|
|
|
struct isis_spftree *tree;
|
|
|
|
|
|
|
|
tree = XCALLOC(MTYPE_ISIS_SPFTREE, sizeof(struct isis_spftree));
|
|
|
|
|
|
|
|
tree->area = area;
|
|
|
|
tree->lspdb = lspdb;
|
2012-03-28 08:48:05 +02:00
|
|
|
tree->last_run_timestamp = 0;
|
2017-09-23 19:28:48 +02:00
|
|
|
tree->last_run_monotime = 0;
|
2012-03-28 08:48:05 +02:00
|
|
|
tree->last_run_duration = 0;
|
2012-03-24 16:35:20 +01:00
|
|
|
tree->runcount = 0;
|
2020-08-24 20:27:15 +02:00
|
|
|
tree->type = type;
|
2020-08-23 05:22:32 +02:00
|
|
|
memcpy(tree->sysid, sysid, ISIS_SYS_ID_LEN);
|
|
|
|
tree->level = level;
|
|
|
|
tree->tree_id = tree_id;
|
|
|
|
tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
|
|
|
|
tree->flags = flags;
|
2021-12-11 03:09:23 +01:00
|
|
|
tree->algorithm = algorithm;
|
2020-08-23 05:22:32 +02:00
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
_isis_spftree_init(tree);
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
static void _isis_spftree_del(struct isis_spftree *spftree)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2024-01-03 16:13:02 +01:00
|
|
|
void *info, *backup_info;
|
|
|
|
|
2023-03-21 13:54:21 +01:00
|
|
|
hash_clean_and_free(&spftree->prefix_sids, NULL);
|
2020-11-26 03:39:09 +01:00
|
|
|
isis_zebra_rlfa_unregister_all(spftree);
|
|
|
|
isis_rlfa_list_clear(spftree);
|
|
|
|
list_delete(&spftree->lfa.remote.pc_spftrees);
|
|
|
|
if (spftree->type == SPF_TYPE_RLFA
|
|
|
|
|| spftree->type == SPF_TYPE_TI_LFA) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_spf_node_list_clear(&spftree->lfa.q_space);
|
|
|
|
isis_spf_node_list_clear(&spftree->lfa.p_space);
|
|
|
|
}
|
|
|
|
isis_spf_node_list_clear(&spftree->adj_nodes);
|
2020-08-23 05:22:32 +02:00
|
|
|
list_delete(&spftree->sadj_list);
|
2017-08-03 14:30:32 +02:00
|
|
|
isis_vertex_queue_free(&spftree->tents);
|
|
|
|
isis_vertex_queue_free(&spftree->paths);
|
2024-01-03 16:13:02 +01:00
|
|
|
info = spftree->route_table->info;
|
|
|
|
backup_info = spftree->route_table_backup->info;
|
2023-04-27 14:50:47 +02:00
|
|
|
route_table_finish(spftree->route_table);
|
|
|
|
route_table_finish(spftree->route_table_backup);
|
2024-01-03 16:13:02 +01:00
|
|
|
isis_route_table_info_free(info);
|
|
|
|
isis_route_table_info_free(backup_info);
|
2022-01-21 15:54:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void isis_spftree_del(struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
_isis_spftree_del(spftree);
|
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
spftree->route_table = NULL;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
XFREE(MTYPE_ISIS_SPFTREE, spftree);
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
static void isis_spftree_clear(struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
_isis_spftree_del(spftree);
|
|
|
|
_isis_spftree_init(spftree);
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
static void isis_spftree_adj_del(struct isis_spftree *spftree,
|
|
|
|
struct isis_adjacency *adj)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
2017-08-03 14:30:32 +02:00
|
|
|
struct isis_vertex *v;
|
2012-03-24 16:35:20 +01:00
|
|
|
if (!adj)
|
|
|
|
return;
|
2017-09-22 21:20:03 +02:00
|
|
|
assert(!isis_vertex_queue_count(&spftree->tents));
|
2017-08-03 14:30:32 +02:00
|
|
|
for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v))
|
|
|
|
isis_vertex_adj_del(v, adj);
|
2012-03-24 16:35:20 +01:00
|
|
|
return;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
void spftree_area_init(struct isis_area *area)
|
|
|
|
{
|
2018-07-26 12:57:38 +02:00
|
|
|
for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
|
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
|
|
|
|
if (!(area->is_type & level))
|
|
|
|
continue;
|
|
|
|
if (area->spftree[tree][level - 1])
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-12-11 03:09:23 +01:00
|
|
|
area->spftree[tree][level - 1] = isis_spftree_new(
|
|
|
|
area, &area->lspdb[level - 1],
|
|
|
|
area->isis->sysid, level, tree,
|
|
|
|
SPF_TYPE_FORWARD, 0, SR_ALGORITHM_SPF);
|
2018-07-26 12:57:38 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
void spftree_area_del(struct isis_area *area)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2018-07-26 12:57:38 +02:00
|
|
|
for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
|
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
|
|
|
|
if (!(area->is_type & level))
|
|
|
|
continue;
|
|
|
|
if (!area->spftree[tree][level - 1])
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-07-26 12:57:38 +02:00
|
|
|
isis_spftree_del(area->spftree[tree][level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-08-21 02:36:59 +02:00
|
|
|
static int spf_adj_state_change(struct isis_adjacency *adj)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2020-08-21 02:36:59 +02:00
|
|
|
struct isis_area *area = adj->circuit->area;
|
|
|
|
|
|
|
|
if (adj->adj_state == ISIS_ADJ_UP)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Remove adjacency from all SPF trees. */
|
2018-07-26 12:57:38 +02:00
|
|
|
for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
|
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
|
|
|
|
if (!(area->is_type & level))
|
|
|
|
continue;
|
|
|
|
if (!area->spftree[tree][level - 1])
|
|
|
|
continue;
|
|
|
|
isis_spftree_adj_del(area->spftree[tree][level - 1],
|
|
|
|
adj);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
2018-04-02 18:39:46 +02:00
|
|
|
|
|
|
|
if (fabricd_spftree(area) != NULL)
|
|
|
|
isis_spftree_adj_del(fabricd_spftree(area), adj);
|
2020-08-21 02:36:59 +02:00
|
|
|
|
|
|
|
return 0;
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the system LSP: returns the LSP in our LSP database
|
|
|
|
* associated with the given system ID.
|
|
|
|
*/
|
2020-08-21 00:55:42 +02:00
|
|
|
struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb,
|
|
|
|
const uint8_t *sysid)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
2012-03-28 08:48:05 +02:00
|
|
|
struct isis_lsp *lsp;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
memcpy(lspid, sysid, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID(lspid) = 0;
|
|
|
|
LSP_FRAGMENT(lspid) = 0;
|
2020-08-23 05:22:32 +02:00
|
|
|
lsp = lsp_search(lspdb, lspid);
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp && lsp->hdr.rem_lifetime != 0)
|
2012-03-28 08:48:05 +02:00
|
|
|
return lsp;
|
|
|
|
return NULL;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add this IS to the root of SPT
|
|
|
|
*/
|
2020-08-23 05:22:32 +02:00
|
|
|
static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_vertex *vertex;
|
|
|
|
#ifdef EXTREME_DEBUG
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
vertex = isis_vertex_new(spftree, spftree->sysid,
|
2017-07-22 14:52:33 +02:00
|
|
|
spftree->area->oldmetric
|
|
|
|
? VTYPE_NONPSEUDO_IS
|
|
|
|
: VTYPE_NONPSEUDO_TE_IS);
|
2017-09-22 21:20:03 +02:00
|
|
|
isis_vertex_queue_append(&spftree->paths, vertex);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2022-08-30 11:21:20 +02:00
|
|
|
"ISIS-SPF: A:%hhu added this IS %s %s depth %d dist %d to PATHS",
|
|
|
|
spftree->algorithm, vtype2string(vertex->type),
|
2022-02-16 15:35:40 +01:00
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
|
|
|
vertex->d_N);
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return vertex;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-19 16:46:52 +01:00
|
|
|
static void vertex_add_parent_firsthop(struct hash_bucket *bucket, void *arg)
|
2018-05-10 20:02:04 +02:00
|
|
|
{
|
|
|
|
struct isis_vertex *vertex = arg;
|
2019-02-19 16:46:52 +01:00
|
|
|
struct isis_vertex *hop = bucket->data;
|
2018-05-10 20:02:04 +02:00
|
|
|
|
*: remove the checking returned value for hash_get()
Firstly, *keep no change* for `hash_get()` with NULL
`alloc_func`.
Only focus on cases with non-NULL `alloc_func` of
`hash_get()`.
Since `hash_get()` with non-NULL `alloc_func` parameter
shall not fail, just ignore the returned value of it.
The returned value must not be NULL.
So in this case, remove the unnecessary checking NULL
or not for the returned value and add `void` in front
of it.
Importantly, also *keep no change* for the two cases with
non-NULL `alloc_func` -
1) Use `assert(<returned_data> == <searching_data>)` to
ensure it is a created node, not a found node.
Refer to `isis_vertex_queue_insert()` of isisd, there
are many examples of this case in isid.
2) Use `<returned_data> != <searching_data>` to judge it
is a found node, then free <searching_data>.
Refer to `aspath_intern()` of bgpd, there are many
examples of this case in bgpd.
Here, <returned_data> is the returned value from `hash_get()`,
and <searching_data> is the data, which is to be put into
hash table.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-04-21 08:37:12 +02:00
|
|
|
(void)hash_get(vertex->firsthops, hop, hash_alloc_intern);
|
2018-05-10 20:02:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void vertex_update_firsthops(struct isis_vertex *vertex,
|
|
|
|
struct isis_vertex *parent)
|
|
|
|
{
|
|
|
|
if (vertex->d_N <= 2)
|
*: remove the checking returned value for hash_get()
Firstly, *keep no change* for `hash_get()` with NULL
`alloc_func`.
Only focus on cases with non-NULL `alloc_func` of
`hash_get()`.
Since `hash_get()` with non-NULL `alloc_func` parameter
shall not fail, just ignore the returned value of it.
The returned value must not be NULL.
So in this case, remove the unnecessary checking NULL
or not for the returned value and add `void` in front
of it.
Importantly, also *keep no change* for the two cases with
non-NULL `alloc_func` -
1) Use `assert(<returned_data> == <searching_data>)` to
ensure it is a created node, not a found node.
Refer to `isis_vertex_queue_insert()` of isisd, there
are many examples of this case in isid.
2) Use `<returned_data> != <searching_data>` to judge it
is a found node, then free <searching_data>.
Refer to `aspath_intern()` of bgpd, there are many
examples of this case in bgpd.
Here, <returned_data> is the returned value from `hash_get()`,
and <searching_data> is the data, which is to be put into
hash table.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-04-21 08:37:12 +02:00
|
|
|
(void)hash_get(vertex->firsthops, vertex, hash_alloc_intern);
|
2018-05-10 20:02:04 +02:00
|
|
|
|
|
|
|
if (vertex->d_N < 2 || !parent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hash_iterate(parent->firsthops, vertex_add_parent_firsthop, vertex);
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* Add a vertex to TENT sorted by cost and by vertextype on tie break situation
|
|
|
|
*/
|
2020-09-20 07:39:28 +02:00
|
|
|
static struct isis_vertex *
|
|
|
|
isis_spf_add2tent(struct isis_spftree *spftree, enum vertextype vtype, void *id,
|
|
|
|
uint32_t cost, int depth, struct isis_spf_adj *sadj,
|
|
|
|
struct isis_prefix_sid *psid, struct isis_vertex *parent)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-08-03 14:30:32 +02:00
|
|
|
struct isis_vertex *vertex;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct listnode *node;
|
2020-11-07 01:15:39 +01:00
|
|
|
bool last_hop;
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2020-07-03 16:55:28 +02:00
|
|
|
vertex = isis_find_vertex(&spftree->paths, id, vtype);
|
|
|
|
if (vertex != NULL) {
|
|
|
|
zlog_err(
|
|
|
|
"%s: vertex %s of type %s already in PATH; check for sysId collisions with established neighbors",
|
|
|
|
__func__, vid2string(vertex, buff, sizeof(buff)),
|
|
|
|
vtype2string(vertex->type));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vertex = isis_find_vertex(&spftree->tents, id, vtype);
|
|
|
|
if (vertex != NULL) {
|
|
|
|
zlog_err(
|
|
|
|
"%s: vertex %s of type %s already in TENT; check for sysId collisions with established neighbors",
|
|
|
|
__func__, vid2string(vertex, buff, sizeof(buff)),
|
|
|
|
vtype2string(vertex->type));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-05-10 20:02:04 +02:00
|
|
|
vertex = isis_vertex_new(spftree, id, vtype);
|
2003-12-23 09:09:43 +01:00
|
|
|
vertex->d_N = cost;
|
|
|
|
vertex->depth = depth;
|
2022-04-08 17:10:25 +02:00
|
|
|
if (VTYPE_IP(vtype) && spftree->area->srdb.enabled && psid) {
|
2020-10-24 02:05:30 +02:00
|
|
|
struct isis_area *area = spftree->area;
|
|
|
|
struct isis_vertex *vertex_psid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the Prefix-SID is already in use by another prefix.
|
|
|
|
*/
|
|
|
|
vertex_psid = isis_spf_prefix_sid_lookup(spftree, psid);
|
|
|
|
if (vertex_psid
|
|
|
|
&& !prefix_same(&vertex_psid->N.ip.p.dest,
|
|
|
|
&vertex->N.ip.p.dest)) {
|
|
|
|
flog_warn(
|
|
|
|
EC_ISIS_SID_COLLISION,
|
|
|
|
"ISIS-Sr (%s): collision detected, prefixes %pFX and %pFX share the same SID %s (%u)",
|
|
|
|
area->area_tag, &vertex->N.ip.p.dest,
|
|
|
|
&vertex_psid->N.ip.p.dest,
|
|
|
|
CHECK_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE)
|
|
|
|
? "label"
|
|
|
|
: "index",
|
|
|
|
psid->value);
|
|
|
|
psid = NULL;
|
|
|
|
} else {
|
|
|
|
bool local;
|
|
|
|
|
|
|
|
local = (vertex->depth == 1);
|
|
|
|
vertex->N.ip.sr.sid = *psid;
|
|
|
|
vertex->N.ip.sr.label =
|
|
|
|
sr_prefix_in_label(area, psid, local);
|
2021-12-11 04:01:07 +01:00
|
|
|
vertex->N.ip.sr.algorithm = psid->algorithm;
|
|
|
|
|
2020-10-24 02:05:30 +02:00
|
|
|
if (vertex->N.ip.sr.label != MPLS_INVALID_LABEL)
|
|
|
|
vertex->N.ip.sr.present = true;
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(spftree->algorithm) &&
|
|
|
|
!isis_flex_algo_elected_supported(
|
|
|
|
spftree->algorithm, spftree->area)) {
|
|
|
|
vertex->N.ip.sr.present = false;
|
|
|
|
vertex->N.ip.sr.label = MPLS_INVALID_LABEL;
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
*: remove the checking returned value for hash_get()
Firstly, *keep no change* for `hash_get()` with NULL
`alloc_func`.
Only focus on cases with non-NULL `alloc_func` of
`hash_get()`.
Since `hash_get()` with non-NULL `alloc_func` parameter
shall not fail, just ignore the returned value of it.
The returned value must not be NULL.
So in this case, remove the unnecessary checking NULL
or not for the returned value and add `void` in front
of it.
Importantly, also *keep no change* for the two cases with
non-NULL `alloc_func` -
1) Use `assert(<returned_data> == <searching_data>)` to
ensure it is a created node, not a found node.
Refer to `isis_vertex_queue_insert()` of isisd, there
are many examples of this case in isid.
2) Use `<returned_data> != <searching_data>` to judge it
is a found node, then free <searching_data>.
Refer to `aspath_intern()` of bgpd, there are many
examples of this case in bgpd.
Here, <returned_data> is the returned value from `hash_get()`,
and <searching_data> is the data, which is to be put into
hash table.
Signed-off-by: anlan_cs <vic.lan@pica8.com>
2022-04-21 08:37:12 +02:00
|
|
|
(void)hash_get(spftree->prefix_sids, vertex,
|
|
|
|
hash_alloc_intern);
|
2020-10-24 02:05:30 +02:00
|
|
|
}
|
2020-09-20 07:39:28 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (parent) {
|
|
|
|
listnode_add(vertex->parents, parent);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC))
|
2018-05-10 20:02:04 +02:00
|
|
|
vertex_update_firsthops(vertex, parent);
|
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
last_hop = (vertex->depth == 2);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_vertex_adj *parent_vadj;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj))
|
2020-11-07 01:15:39 +01:00
|
|
|
isis_vertex_adj_add(spftree, vertex, vertex->Adj_N,
|
|
|
|
parent_vadj->sadj, psid, last_hop);
|
2020-08-23 05:22:32 +02:00
|
|
|
} else if (sadj) {
|
2020-11-07 01:15:39 +01:00
|
|
|
isis_vertex_adj_add(spftree, vertex, vertex->Adj_N, sadj, psid,
|
|
|
|
last_hop);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2022-08-30 11:21:20 +02:00
|
|
|
"ISIS-SPF: A:%hhu add to TENT %s %s %s depth %d dist %d adjcount %d",
|
|
|
|
spftree->algorithm, print_sys_hostname(vertex->N.id),
|
2022-02-16 15:35:40 +01:00
|
|
|
vtype2string(vertex->type),
|
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
|
|
|
vertex->d_N, listcount(vertex->Adj_N));
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
isis_vertex_queue_insert(&spftree->tents, vertex);
|
2004-09-10 22:48:21 +02:00
|
|
|
return vertex;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
static void isis_spf_add_local(struct isis_spftree *spftree,
|
|
|
|
enum vertextype vtype, void *id,
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_spf_adj *sadj, uint32_t cost,
|
2020-09-20 07:39:28 +02:00
|
|
|
struct isis_prefix_sid *psid,
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_vertex *parent)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_vertex *vertex;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
vertex = isis_find_vertex(&spftree->tents, id, vtype);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (vertex) {
|
|
|
|
/* C.2.5 c) */
|
|
|
|
if (vertex->d_N == cost) {
|
2020-11-07 01:15:39 +01:00
|
|
|
if (sadj) {
|
|
|
|
bool last_hop = (vertex->depth == 2);
|
|
|
|
|
|
|
|
isis_vertex_adj_add(spftree, vertex,
|
|
|
|
vertex->Adj_N, sadj, psid,
|
|
|
|
last_hop);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
/* d) */
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_NO_ADJACENCIES)
|
|
|
|
&& listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
|
2004-09-10 22:48:21 +02:00
|
|
|
remove_excess_adjs(vertex->Adj_N);
|
2017-07-22 14:52:33 +02:00
|
|
|
if (parent && (listnode_lookup(vertex->parents, parent)
|
|
|
|
== NULL))
|
2012-03-24 16:35:20 +01:00
|
|
|
listnode_add(vertex->parents, parent);
|
|
|
|
return;
|
|
|
|
} else if (vertex->d_N < cost) {
|
|
|
|
/* e) do nothing */
|
|
|
|
return;
|
|
|
|
} else { /* vertex->d_N > cost */
|
2017-07-17 14:03:14 +02:00
|
|
|
/* f) */
|
2017-08-03 14:30:32 +02:00
|
|
|
isis_vertex_queue_delete(&spftree->tents, vertex);
|
2024-05-16 16:44:03 +02:00
|
|
|
hash_release(spftree->prefix_sids, vertex);
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_vertex_del(vertex);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, psid, parent);
|
2012-03-24 16:35:20 +01:00
|
|
|
return;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
|
2017-04-27 12:54:21 +02:00
|
|
|
void *id, uint32_t dist, uint16_t depth,
|
2020-09-20 07:39:28 +02:00
|
|
|
struct isis_prefix_sid *psid, struct isis_vertex *parent)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_vertex *vertex;
|
|
|
|
#ifdef EXTREME_DEBUG
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
assert(spftree && parent);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)
|
2018-04-02 18:39:46 +02:00
|
|
|
&& !VTYPE_IS(vtype))
|
|
|
|
return;
|
|
|
|
|
2018-07-26 22:53:08 +02:00
|
|
|
struct prefix_pair p;
|
2017-07-05 18:37:36 +02:00
|
|
|
if (vtype >= VTYPE_IPREACH_INTERNAL) {
|
2018-07-26 22:53:08 +02:00
|
|
|
memcpy(&p, id, sizeof(p));
|
|
|
|
apply_mask(&p.dest);
|
2022-05-08 15:07:42 +02:00
|
|
|
apply_mask(&p.src);
|
2017-07-05 18:37:36 +02:00
|
|
|
id = &p;
|
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* RFC3787 section 5.1 */
|
|
|
|
if (spftree->area->newmetric == 1) {
|
|
|
|
if (dist > MAX_WIDE_PATH_METRIC)
|
|
|
|
return;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
/* C.2.6 b) */
|
2012-03-24 16:35:20 +01:00
|
|
|
else if (spftree->area->oldmetric == 1) {
|
|
|
|
if (dist > MAX_NARROW_PATH_METRIC)
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/* c) */
|
2017-08-03 14:30:32 +02:00
|
|
|
vertex = isis_find_vertex(&spftree->paths, id, vtype);
|
2004-09-10 22:48:21 +02:00
|
|
|
if (vertex) {
|
2003-12-23 09:09:43 +01:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2022-08-30 11:21:20 +02:00
|
|
|
"ISIS-SPF: A:%hhu process_N %s %s %s dist %d already found from PATH",
|
|
|
|
spftree->algorithm,
|
2022-02-16 15:35:40 +01:00
|
|
|
print_sys_hostname(vertex->N.id),
|
|
|
|
vtype2string(vtype),
|
|
|
|
vid2string(vertex, buff, sizeof(buff)), dist);
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2004-09-10 22:48:21 +02:00
|
|
|
assert(dist >= vertex->d_N);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
vertex = isis_find_vertex(&spftree->tents, id, vtype);
|
2004-09-10 22:48:21 +02:00
|
|
|
/* d) */
|
|
|
|
if (vertex) {
|
|
|
|
/* 1) */
|
2003-12-23 09:09:43 +01:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2022-08-30 11:21:20 +02:00
|
|
|
"ISIS-SPF: A:%hhu process_N %s %s %s dist %d parent %s adjcount %d",
|
|
|
|
spftree->algorithm,
|
2022-02-16 15:35:40 +01:00
|
|
|
print_sys_hostname(vertex->N.id),
|
|
|
|
vtype2string(vtype),
|
|
|
|
vid2string(vertex, buff, sizeof(buff)), dist,
|
|
|
|
(parent ? print_sys_hostname(parent->N.id)
|
|
|
|
: "null"),
|
|
|
|
(parent ? listcount(parent->Adj_N) : 0));
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2004-09-10 22:48:21 +02:00
|
|
|
if (vertex->d_N == dist) {
|
2012-03-24 16:35:20 +01:00
|
|
|
struct listnode *node;
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_vertex_adj *parent_vadj;
|
2012-03-24 16:35:20 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node,
|
2020-08-23 05:22:32 +02:00
|
|
|
parent_vadj))
|
2020-11-07 01:15:39 +01:00
|
|
|
if (!isis_vertex_adj_exists(
|
|
|
|
spftree, vertex,
|
|
|
|
parent_vadj->sadj)) {
|
|
|
|
bool last_hop = (vertex->depth == 2);
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
isis_vertex_adj_add(spftree, vertex,
|
2020-11-07 01:15:39 +01:00
|
|
|
vertex->Adj_N,
|
2020-09-20 07:39:28 +02:00
|
|
|
parent_vadj->sadj,
|
2020-11-07 01:15:39 +01:00
|
|
|
psid, last_hop);
|
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
if (CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_HOPCOUNT_METRIC))
|
2018-05-10 20:02:04 +02:00
|
|
|
vertex_update_firsthops(vertex, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
/* 2) */
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_NO_ADJACENCIES)
|
|
|
|
&& listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
|
2004-09-10 22:48:21 +02:00
|
|
|
remove_excess_adjs(vertex->Adj_N);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (listnode_lookup(vertex->parents, parent) == NULL)
|
|
|
|
listnode_add(vertex->parents, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
return;
|
|
|
|
} else if (vertex->d_N < dist) {
|
|
|
|
return;
|
|
|
|
/* 4) */
|
|
|
|
} else {
|
2017-08-03 14:30:32 +02:00
|
|
|
isis_vertex_queue_delete(&spftree->tents, vertex);
|
2024-05-16 16:44:03 +02:00
|
|
|
hash_release(spftree->prefix_sids, vertex);
|
2012-03-24 16:35:20 +01:00
|
|
|
isis_vertex_del(vertex);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2022-08-30 11:21:20 +02:00
|
|
|
"ISIS-SPF: A:%hhu process_N add2tent %s %s dist %d parent %s",
|
|
|
|
spftree->algorithm, print_sys_hostname(id),
|
|
|
|
vtype2string(vtype), dist,
|
2022-02-16 15:35:40 +01:00
|
|
|
(parent ? print_sys_hostname(parent->N.id) : "null"));
|
2012-03-24 16:35:20 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
isis_spf_add2tent(spftree, vtype, id, dist, depth, NULL, psid, parent);
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* C.2.6 Step 1
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
static int isis_spf_process_lsp(struct isis_spftree *spftree,
|
|
|
|
struct isis_lsp *lsp, uint32_t cost,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint16_t depth, uint8_t *root_sysid,
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_vertex *parent)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-07-05 18:37:36 +02:00
|
|
|
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
|
|
|
|
struct listnode *fragnode = NULL;
|
2012-03-24 16:35:20 +01:00
|
|
|
uint32_t dist;
|
2003-12-23 09:09:43 +01:00
|
|
|
enum vertextype vtype;
|
2018-03-27 21:13:34 +02:00
|
|
|
static const uint8_t null_sysid[ISIS_SYS_ID_LEN];
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_mt_router_info *mt_router_info = NULL;
|
2018-07-26 22:53:08 +02:00
|
|
|
struct prefix_pair ip_info;
|
2020-09-20 07:39:28 +02:00
|
|
|
bool has_valid_psid;
|
2023-02-22 10:27:15 +01:00
|
|
|
bool loc_is_in_ipv6_reach = false;
|
2017-07-05 18:37:36 +02:00
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (isis_lfa_excise_node_check(spftree, lsp->hdr.lsp_id)) {
|
2020-11-20 22:59:35 +01:00
|
|
|
if (IS_DEBUG_LFA)
|
2020-08-21 00:55:42 +02:00
|
|
|
zlog_debug("ISIS-LFA: excising node %s",
|
|
|
|
print_sys_hostname(lsp->hdr.lsp_id));
|
|
|
|
return ISIS_OK;
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (!lsp->tlvs)
|
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 13:56:47 +02:00
|
|
|
if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
|
2017-07-05 18:37:36 +02:00
|
|
|
mt_router_info = isis_tlvs_lookup_mt_router_info(lsp->tlvs,
|
|
|
|
spftree->mtid);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-22 14:52:33 +02:00
|
|
|
if (!pseudo_lsp && (spftree->mtid == ISIS_MT_IPV4_UNICAST
|
2017-07-05 18:37:36 +02:00
|
|
|
&& !speaks(lsp->tlvs->protocols_supported.protocols,
|
|
|
|
lsp->tlvs->protocols_supported.count,
|
|
|
|
spftree->family))
|
2017-04-27 13:56:47 +02:00
|
|
|
&& !mt_router_info)
|
2003-12-23 09:09:43 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
|
2017-07-30 19:27:25 +02:00
|
|
|
/* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
|
2018-03-10 18:16:34 +01:00
|
|
|
bool no_overload = (pseudo_lsp
|
|
|
|
|| (spftree->mtid == ISIS_MT_IPV4_UNICAST
|
2017-07-30 19:27:25 +02:00
|
|
|
&& !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits))
|
2018-03-10 18:16:34 +01:00
|
|
|
|| (mt_router_info && !mt_router_info->overload));
|
2017-07-30 19:27:25 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
lspfragloop:
|
isisd: fix crash when calculating the neighbor spanning tree based on the fragmented LSP
1. When the root IS regenerates an LSP, it calls lsp_build() -> lsp_clear_data() to free the TLV memory of the first fragment and all other fragments. If the number of fragments in the regenerated LSP decreases or if no fragmentation is needed, the extra LSP fragments are not immediately deleted. Instead, lsp_seqno_update() -> lsp_purge() is called to set the remaining time to zero and start aging, while also notifying other IS nodes to age these fragments. lsp_purge() usually does not reset lsp->hdr.seqno to zero because the LSP might recover during the aging process.
2. When other IS nodes receive an LSP, they always call process_lsp() -> isis_unpack_tlvs() to allocate TLV memory for the LSP. This does not differentiate whether the received LSP has a remaining lifetime of zero. Therefore, it is rare for an LSP of a non-root IS to have empty TLVs. Of course, if an LSP with a remaining time of zero and already corrupted is received, lsp_update() -> lsp_purge() will be called to free the TLV memory of the LSP, but this scenario is rare.
3. In LFA calculations, neighbors of the root IS are traversed, and each neighbor is taken as a new root to compute the neighbor SPT. During this process, the old root IS will serve as a neighbor of the new root IS, triggering a call to isis_spf_process_lsp() to parse the LSP of the old root IS and obtain its IP vertices and neighboring IS vertices. However, isis_spf_process_lsp() only checks whether the TLVs in the first fragment of the LSP exist, and does not check the TLVs in the fragmented LSP. If the TLV memory of the fragmented LSP of the old root IS has been freed, it can lead to a null pointer access, causing the current crash.
Additionally, for the base SPT, there are only two places where the LSP of the root IS is parsed:
1. When obtaining the UP neighbors of the root IS via spf_adj_list_parse_lsp().
2. When preloading the IP vertices of the root IS via isis_lsp_iterate_ip_reach().
Both of these checks ensure that frag->tlvs is not null, and they do not subsequently call isis_spf_process_lsp() to parse the root IS's LSP. It is very rare for non-root IS LSPs to have empty TLVs unless they are corrupted LSPs awaiting deletion. If it happens, a crash will occur.
The backtrace is as follows:
(gdb) bt
#0 0x00007f3097281fe1 in raise () from /lib/x86_64-linux-gnu/libpthread.so.0
#1 0x00007f30973a2972 in core_handler (signo=11, siginfo=0x7ffce66c2870, context=0x7ffce66c2740) at ../lib/sigevent.c:261
#2 <signal handler called>
#3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0)
at ../isisd/isis_spf.c:898
#4 0x000055dfa805743b in isis_spf_loop (spftree=0x55dfa950eee0, root_sysid=0x55dfa950ef6c "") at ../isisd/isis_spf.c:1688
#5 0x000055dfa805784f in isis_run_spf (spftree=0x55dfa950eee0) at ../isisd/isis_spf.c:1808
#6 0x000055dfa8037ff5 in isis_spf_run_neighbors (spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:1259
#7 0x000055dfa803ac17 in isis_spf_run_lfa (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_lfa.c:2300
#8 0x000055dfa8057964 in isis_run_spf_with_protection (area=0x55dfa9477510, spftree=0x55dfa9474440) at ../isisd/isis_spf.c:1827
#9 0x000055dfa8057c15 in isis_run_spf_cb (thread=0x7ffce66c38e0) at ../isisd/isis_spf.c:1889
#10 0x00007f30973bbf04 in thread_call (thread=0x7ffce66c38e0) at ../lib/thread.c:1990
#11 0x00007f309735497b in frr_run (master=0x55dfa91733c0) at ../lib/libfrr.c:1198
#12 0x000055dfa8029d5d in main (argc=5, argv=0x7ffce66c3b08, envp=0x7ffce66c3b38) at ../isisd/isis_main.c:273
(gdb) f 3
#3 0x000055dfa805512b in isis_spf_process_lsp (spftree=0x55dfa950eee0, lsp=0x55dfa94cb590, cost=10, depth=1, root_sysid=0x55dfa950ef6c "", parent=0x55dfa952fca0)
at ../isisd/isis_spf.c:898
898 ../isisd/isis_spf.c: No such file or directory.
(gdb) p te_neighs
$1 = (struct isis_item_list *) 0x120
(gdb) p lsp->tlvs
$2 = (struct isis_tlvs *) 0x0
(gdb) p lsp->hdr
$3 = {pdu_len = 27, rem_lifetime = 0, lsp_id = "\000\000\000\000\000\001\000\001", seqno = 4, checksum = 59918, lsp_bits = 1 '\001'}
The backtrace provided above pertains to version 8.5.4, but it seems that the same issue exists in the code of the master branch as well.
I have reviewed the process for calculating the SPT based on the LSP, and isis_spf_process_lsp() is the only function that does not check whether the TLVs in the fragments are empty. Therefore, I believe that modifying this function alone should be sufficient. If the TLVs of the current fragment are already empty, we do not need to continue processing subsequent fragments. This is consistent with the behavior where we do not process fragments if the TLVs of the first fragment are empty.
Of course, one could argue that lsp_purge() should still retain the TLV memory, freeing it and then reallocating it if needed. However, this is a debatable point because in some scenarios, it is permissible for the LSP to have empty TLVs. For example, after receiving an SNP (Sequence Number PDU) message, an empty LSP (with lsp->hdr.seqno = 0) might be created by calling lsp_new. If the corresponding LSP message is discarded due to domain or area authentication failure, the TLV memory wouldn't be allocated.
Test scenario:
In an LFA network, importing a sufficient number of static routes to cause LSP fragmentation, and then rolling back the imported static routes so that the LSP is no longer fragmented, can easily result in this issue.
Signed-off-by: zhou-run <zhou.run@h3c.com>
2024-07-11 05:35:34 +02:00
|
|
|
if (!lsp->tlvs)
|
|
|
|
return ISIS_OK;
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp->hdr.seqno == 0) {
|
2022-08-29 15:35:24 +02:00
|
|
|
zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
|
2004-09-10 22:48:21 +02:00
|
|
|
return ISIS_WARNING;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
2022-08-30 11:21:20 +02:00
|
|
|
zlog_debug("ISIS-SPF: A:%hhu process_lsp %s",
|
|
|
|
spftree->algorithm,
|
2022-02-16 15:35:40 +01:00
|
|
|
print_sys_hostname(lsp->hdr.lsp_id));
|
2012-03-24 16:35:20 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
|
2017-07-30 19:27:25 +02:00
|
|
|
if (no_overload) {
|
2021-01-08 15:55:37 +01:00
|
|
|
if ((pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
&& spftree->area->oldmetric) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_oldstyle_reach *r;
|
|
|
|
for (r = (struct isis_oldstyle_reach *)
|
|
|
|
lsp->tlvs->oldstyle_reach.head;
|
|
|
|
r; r = r->next) {
|
2018-06-05 20:50:59 +02:00
|
|
|
if (fabricd)
|
|
|
|
continue;
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* C.2.6 a) */
|
2005-09-28 20:45:54 +02:00
|
|
|
/* Two way connectivity */
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!LSP_PSEUDO_ID(r->id)
|
|
|
|
&& !memcmp(r->id, root_sysid,
|
|
|
|
ISIS_SYS_ID_LEN))
|
2004-09-10 22:48:21 +02:00
|
|
|
continue;
|
2017-04-27 13:56:47 +02:00
|
|
|
if (!pseudo_lsp
|
2017-07-05 18:37:36 +02:00
|
|
|
&& !memcmp(r->id, null_sysid,
|
2004-09-10 22:48:21 +02:00
|
|
|
ISIS_SYS_ID_LEN))
|
2012-03-24 16:35:20 +01:00
|
|
|
continue;
|
2017-07-05 18:37:36 +02:00
|
|
|
dist = cost + r->metric;
|
2004-09-10 22:48:21 +02:00
|
|
|
process_N(spftree,
|
2017-07-05 18:37:36 +02:00
|
|
|
LSP_PSEUDO_ID(r->id)
|
2017-04-27 12:54:21 +02:00
|
|
|
? VTYPE_PSEUDO_IS
|
2004-09-10 22:48:21 +02:00
|
|
|
: VTYPE_NONPSEUDO_IS,
|
2020-09-20 07:39:28 +02:00
|
|
|
(void *)r->id, dist, depth + 1, NULL,
|
2017-07-05 18:37:36 +02:00
|
|
|
parent);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-08 15:55:37 +01:00
|
|
|
if (spftree->area->newmetric) {
|
|
|
|
struct isis_item_list *te_neighs = NULL;
|
|
|
|
if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
te_neighs = &lsp->tlvs->extended_reach;
|
|
|
|
else
|
|
|
|
te_neighs = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->mt_reach, spftree->mtid);
|
|
|
|
|
|
|
|
struct isis_extended_reach *er;
|
|
|
|
for (er = te_neighs ? (struct isis_extended_reach *)
|
|
|
|
te_neighs->head
|
|
|
|
: NULL;
|
|
|
|
er; er = er->next) {
|
|
|
|
/* C.2.6 a) */
|
|
|
|
/* Two way connectivity */
|
|
|
|
if (!LSP_PSEUDO_ID(er->id)
|
|
|
|
&& !memcmp(er->id, root_sysid,
|
|
|
|
ISIS_SYS_ID_LEN))
|
|
|
|
continue;
|
|
|
|
if (!pseudo_lsp
|
|
|
|
&& !memcmp(er->id, null_sysid,
|
|
|
|
ISIS_SYS_ID_LEN))
|
|
|
|
continue;
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
|
|
|
|
if (flex_algo_id_valid(spftree->algorithm) &&
|
|
|
|
(!sr_algorithm_participated(
|
|
|
|
lsp, spftree->algorithm) ||
|
|
|
|
isis_flex_algo_constraint_drop(spftree,
|
|
|
|
lsp, er)))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2021-01-08 15:55:37 +01:00
|
|
|
dist = cost
|
|
|
|
+ (CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_HOPCOUNT_METRIC)
|
|
|
|
? 1
|
|
|
|
: er->metric);
|
|
|
|
process_N(spftree,
|
|
|
|
LSP_PSEUDO_ID(er->id)
|
|
|
|
? VTYPE_PSEUDO_TE_IS
|
|
|
|
: VTYPE_NONPSEUDO_TE_IS,
|
|
|
|
(void *)er->id, dist, depth + 1, NULL,
|
|
|
|
parent);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-09-08 18:25:45 +02:00
|
|
|
if (!fabricd && !pseudo_lsp && spftree->family == AF_INET
|
2021-01-08 15:55:37 +01:00
|
|
|
&& spftree->mtid == ISIS_MT_IPV4_UNICAST
|
|
|
|
&& spftree->area->oldmetric) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_item_list *reachs[] = {
|
|
|
|
&lsp->tlvs->oldstyle_ip_reach,
|
|
|
|
&lsp->tlvs->oldstyle_ip_reach_ext};
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-28 20:45:54 +02:00
|
|
|
for (unsigned int i = 0; i < array_size(reachs); i++) {
|
2017-07-05 18:37:36 +02:00
|
|
|
vtype = i ? VTYPE_IPREACH_EXTERNAL
|
|
|
|
: VTYPE_IPREACH_INTERNAL;
|
|
|
|
|
2018-07-26 22:53:08 +02:00
|
|
|
memset(&ip_info, 0, sizeof(ip_info));
|
|
|
|
ip_info.dest.family = AF_INET;
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_oldstyle_ip_reach *r;
|
|
|
|
for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
|
|
|
|
->head;
|
|
|
|
r; r = r->next) {
|
|
|
|
dist = cost + r->metric;
|
2018-07-26 22:53:08 +02:00
|
|
|
ip_info.dest.u.prefix4 = r->prefix.prefix;
|
|
|
|
ip_info.dest.prefixlen = r->prefix.prefixlen;
|
|
|
|
process_N(spftree, vtype, &ip_info,
|
2020-09-20 07:39:28 +02:00
|
|
|
dist, depth + 1, NULL, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-01-08 15:55:37 +01:00
|
|
|
/* we can skip all the rest if we're using metric style narrow */
|
|
|
|
if (!spftree->area->newmetric)
|
|
|
|
goto end;
|
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
if (!pseudo_lsp && spftree->family == AF_INET) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_item_list *ipv4_reachs;
|
|
|
|
if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
ipv4_reachs = &lsp->tlvs->extended_ip_reach;
|
|
|
|
else
|
|
|
|
ipv4_reachs = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->mt_ip_reach, spftree->mtid);
|
|
|
|
|
2018-07-26 22:53:08 +02:00
|
|
|
memset(&ip_info, 0, sizeof(ip_info));
|
|
|
|
ip_info.dest.family = AF_INET;
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_extended_ip_reach *r;
|
|
|
|
for (r = ipv4_reachs
|
|
|
|
? (struct isis_extended_ip_reach *)
|
|
|
|
ipv4_reachs->head
|
|
|
|
: NULL;
|
|
|
|
r; r = r->next) {
|
|
|
|
dist = cost + r->metric;
|
2018-07-26 22:53:08 +02:00
|
|
|
ip_info.dest.u.prefix4 = r->prefix.prefix;
|
|
|
|
ip_info.dest.prefixlen = r->prefix.prefixlen;
|
2020-09-20 07:39:28 +02:00
|
|
|
|
2022-04-08 17:10:25 +02:00
|
|
|
/* Parse list of Prefix-SID subTLVs if SR is enabled */
|
2020-09-20 07:39:28 +02:00
|
|
|
has_valid_psid = false;
|
2022-04-08 17:10:25 +02:00
|
|
|
if (spftree->area->srdb.enabled && r->subtlvs) {
|
2020-09-20 07:39:28 +02:00
|
|
|
for (struct isis_item *i =
|
|
|
|
r->subtlvs->prefix_sids.head;
|
|
|
|
i; i = i->next) {
|
|
|
|
struct isis_prefix_sid *psid =
|
|
|
|
(struct isis_prefix_sid *)i;
|
|
|
|
|
2021-12-11 04:01:07 +01:00
|
|
|
if (psid->algorithm !=
|
|
|
|
spftree->algorithm)
|
2020-09-20 07:39:28 +02:00
|
|
|
continue;
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(
|
|
|
|
spftree->algorithm) &&
|
|
|
|
(!sr_algorithm_participated(
|
|
|
|
lsp, spftree->algorithm) ||
|
|
|
|
!isis_flex_algo_elected_supported(
|
|
|
|
spftree->algorithm,
|
|
|
|
spftree->area)))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
has_valid_psid = true;
|
|
|
|
process_N(spftree, VTYPE_IPREACH_TE,
|
|
|
|
&ip_info, dist, depth + 1,
|
|
|
|
psid, parent);
|
|
|
|
/*
|
|
|
|
* Stop the Prefix-SID iteration since
|
|
|
|
* we only support the SPF algorithm for
|
|
|
|
* now.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_valid_psid)
|
|
|
|
process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
|
|
|
|
dist, depth + 1, NULL, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (!pseudo_lsp && spftree->family == AF_INET6) {
|
2017-07-05 18:37:36 +02:00
|
|
|
struct isis_item_list *ipv6_reachs;
|
|
|
|
if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
ipv6_reachs = &lsp->tlvs->ipv6_reach;
|
|
|
|
else
|
|
|
|
ipv6_reachs = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->mt_ipv6_reach, spftree->mtid);
|
|
|
|
|
|
|
|
struct isis_ipv6_reach *r;
|
|
|
|
for (r = ipv6_reachs
|
|
|
|
? (struct isis_ipv6_reach *)ipv6_reachs->head
|
|
|
|
: NULL;
|
|
|
|
r; r = r->next) {
|
|
|
|
dist = cost + r->metric;
|
|
|
|
vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
|
|
|
|
: VTYPE_IP6REACH_INTERNAL;
|
2018-07-26 22:53:08 +02:00
|
|
|
memset(&ip_info, 0, sizeof(ip_info));
|
|
|
|
ip_info.dest.family = AF_INET6;
|
|
|
|
ip_info.dest.u.prefix6 = r->prefix.prefix;
|
|
|
|
ip_info.dest.prefixlen = r->prefix.prefixlen;
|
|
|
|
|
2022-04-08 17:10:25 +02:00
|
|
|
if (spftree->area->srdb.enabled && r->subtlvs &&
|
|
|
|
r->subtlvs->source_prefix &&
|
|
|
|
r->subtlvs->source_prefix->prefixlen) {
|
2018-07-26 22:53:08 +02:00
|
|
|
if (spftree->tree_id != SPFTREE_DSTSRC) {
|
|
|
|
char buff[VID2STR_BUFFER];
|
|
|
|
zlog_warn("Ignoring dest-src route %s in non dest-src topology",
|
|
|
|
srcdest2str(
|
|
|
|
&ip_info.dest,
|
|
|
|
r->subtlvs->source_prefix,
|
|
|
|
buff, sizeof(buff)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ip_info.src = *r->subtlvs->source_prefix;
|
|
|
|
}
|
2020-09-20 07:39:28 +02:00
|
|
|
|
|
|
|
/* Parse list of Prefix-SID subTLVs */
|
|
|
|
has_valid_psid = false;
|
|
|
|
if (r->subtlvs) {
|
|
|
|
for (struct isis_item *i =
|
|
|
|
r->subtlvs->prefix_sids.head;
|
|
|
|
i; i = i->next) {
|
|
|
|
struct isis_prefix_sid *psid =
|
|
|
|
(struct isis_prefix_sid *)i;
|
|
|
|
|
2021-12-11 04:01:07 +01:00
|
|
|
if (psid->algorithm !=
|
|
|
|
spftree->algorithm)
|
2020-09-20 07:39:28 +02:00
|
|
|
continue;
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (flex_algo_id_valid(
|
|
|
|
spftree->algorithm) &&
|
|
|
|
(!sr_algorithm_participated(
|
|
|
|
lsp, spftree->algorithm) ||
|
|
|
|
!isis_flex_algo_elected_supported(
|
|
|
|
spftree->algorithm,
|
|
|
|
spftree->area)))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
has_valid_psid = true;
|
|
|
|
process_N(spftree, vtype, &ip_info,
|
|
|
|
dist, depth + 1, psid,
|
|
|
|
parent);
|
|
|
|
/*
|
|
|
|
* Stop the Prefix-SID iteration since
|
|
|
|
* we only support the SPF algorithm for
|
|
|
|
* now.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_valid_psid)
|
|
|
|
process_N(spftree, vtype, &ip_info, dist,
|
|
|
|
depth + 1, NULL, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2023-02-22 10:27:15 +01:00
|
|
|
|
|
|
|
/* Process SRv6 Locator TLVs */
|
|
|
|
|
|
|
|
struct isis_item_list *srv6_locators = isis_lookup_mt_items(
|
|
|
|
&lsp->tlvs->srv6_locator, spftree->mtid);
|
|
|
|
|
|
|
|
struct isis_srv6_locator_tlv *loc;
|
|
|
|
for (loc = srv6_locators ? (struct isis_srv6_locator_tlv *)
|
|
|
|
srv6_locators->head
|
|
|
|
: NULL;
|
|
|
|
loc; loc = loc->next) {
|
|
|
|
|
|
|
|
if (loc->algorithm != SR_ALGORITHM_SPF)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dist = cost + loc->metric;
|
|
|
|
vtype = VTYPE_IP6REACH_INTERNAL;
|
|
|
|
memset(&ip_info, 0, sizeof(ip_info));
|
|
|
|
ip_info.dest.family = AF_INET6;
|
|
|
|
ip_info.dest.u.prefix6 = loc->prefix.prefix;
|
|
|
|
ip_info.dest.prefixlen = loc->prefix.prefixlen;
|
|
|
|
|
|
|
|
/* An SRv6 Locator can be received in both a Prefix
|
|
|
|
Reachability TLV and an SRv6 Locator TLV (as per RFC
|
|
|
|
9352 section #5). We go through the Prefix Reachability
|
|
|
|
TLVs and check if the SRv6 Locator is present in some of
|
|
|
|
them. If we find the SRv6 Locator in some Prefix
|
|
|
|
Reachbility TLV then it means that we have already
|
|
|
|
processed it before and we can skip it. */
|
|
|
|
for (r = ipv6_reachs ? (struct isis_ipv6_reach *)
|
|
|
|
ipv6_reachs->head
|
|
|
|
: NULL;
|
|
|
|
r; r = r->next) {
|
|
|
|
if (prefix_same((struct prefix *)&r->prefix,
|
|
|
|
(struct prefix *)&loc->prefix))
|
|
|
|
loc_is_in_ipv6_reach = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SRv6 locator not present in Prefix Reachability TLV,
|
|
|
|
* let's process it */
|
|
|
|
if (!loc_is_in_ipv6_reach)
|
|
|
|
process_N(spftree, vtype, &ip_info, dist,
|
|
|
|
depth + 1, NULL, parent);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-01-08 15:55:37 +01:00
|
|
|
end:
|
2020-12-24 19:29:42 +01:00
|
|
|
|
2021-01-30 01:36:22 +01:00
|
|
|
/* if attach bit set in LSP, attached-bit receive ignore is
|
|
|
|
* not configured, we are a level-1 area and we have no other
|
|
|
|
* level-2 | level1-2 areas then add a default route toward
|
|
|
|
* this neighbor
|
2020-12-24 19:29:42 +01:00
|
|
|
*/
|
|
|
|
if ((lsp->hdr.lsp_bits & LSPBIT_ATT) == LSPBIT_ATT
|
|
|
|
&& !spftree->area->attached_bit_rcv_ignore
|
2021-07-12 22:56:04 +02:00
|
|
|
&& (spftree->area->is_type & IS_LEVEL_1)
|
|
|
|
&& !isis_level2_adj_up(spftree->area)) {
|
2020-12-24 19:29:42 +01:00
|
|
|
struct prefix_pair ip_info = { {0} };
|
2021-01-30 01:36:22 +01:00
|
|
|
if (IS_DEBUG_RTE_EVENTS)
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug("ISIS-Spf (%pLS): add default %s route",
|
|
|
|
lsp->hdr.lsp_id,
|
2020-12-24 19:29:42 +01:00
|
|
|
spftree->family == AF_INET ? "ipv4"
|
|
|
|
: "ipv6");
|
|
|
|
|
|
|
|
if (spftree->family == AF_INET) {
|
|
|
|
ip_info.dest.family = AF_INET;
|
|
|
|
vtype = VTYPE_IPREACH_INTERNAL;
|
|
|
|
} else {
|
|
|
|
ip_info.dest.family = AF_INET6;
|
|
|
|
vtype = VTYPE_IP6REACH_INTERNAL;
|
|
|
|
}
|
|
|
|
process_N(spftree, vtype, &ip_info, cost, depth + 1, NULL,
|
|
|
|
parent);
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (fragnode == NULL)
|
|
|
|
fragnode = listhead(lsp->lspu.frags);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
fragnode = listnextnode(fragnode);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
if (fragnode) {
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
lsp = listgetdata(fragnode);
|
2004-09-10 22:48:21 +02:00
|
|
|
goto lspfragloop;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
static struct isis_adjacency *adj_find(struct list *adj_list, const uint8_t *id,
|
|
|
|
int level, uint16_t mtid, int family)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_adjacency *adj;
|
2020-08-23 05:22:32 +02:00
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
|
|
|
|
if (!(adj->level & level))
|
2017-04-27 13:56:47 +02:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
if (memcmp(adj->sysid, id, ISIS_SYS_ID_LEN) != 0)
|
2017-04-27 13:56:47 +02:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
if (adj->adj_state != ISIS_ADJ_UP)
|
2017-04-27 13:56:47 +02:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!adj_has_mt(adj, mtid))
|
2017-04-27 13:56:47 +02:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
if (mtid == ISIS_MT_IPV4_UNICAST
|
|
|
|
&& !speaks(adj->nlpids.nlpids, adj->nlpids.count, family))
|
2017-04-27 13:56:47 +02:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
return adj;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spf_preload_tent_ip_reach_args {
|
|
|
|
struct isis_spftree *spftree;
|
|
|
|
struct isis_vertex *parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int isis_spf_preload_tent_ip_reach_cb(const struct prefix *prefix,
|
|
|
|
uint32_t metric, bool external,
|
|
|
|
struct isis_subtlvs *subtlvs,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct spf_preload_tent_ip_reach_args *args = arg;
|
|
|
|
struct isis_spftree *spftree = args->spftree;
|
|
|
|
struct isis_vertex *parent = args->parent;
|
|
|
|
struct prefix_pair ip_info;
|
|
|
|
enum vertextype vtype;
|
2024-06-04 16:31:40 +02:00
|
|
|
bool has_valid_psid = false;
|
2020-08-23 05:22:32 +02:00
|
|
|
|
|
|
|
if (external)
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
|
|
|
|
assert(spftree->family == prefix->family);
|
|
|
|
memset(&ip_info, 0, sizeof(ip_info));
|
|
|
|
prefix_copy(&ip_info.dest, prefix);
|
|
|
|
apply_mask(&ip_info.dest);
|
|
|
|
|
2024-06-04 16:31:40 +02:00
|
|
|
if (prefix->family == AF_INET)
|
2020-08-23 05:22:32 +02:00
|
|
|
vtype = VTYPE_IPREACH_INTERNAL;
|
2024-06-04 16:31:40 +02:00
|
|
|
else
|
2020-08-23 05:22:32 +02:00
|
|
|
vtype = VTYPE_IP6REACH_INTERNAL;
|
|
|
|
|
2022-04-08 17:10:25 +02:00
|
|
|
/* Parse list of Prefix-SID subTLVs if SR is enabled */
|
|
|
|
if (spftree->area->srdb.enabled && subtlvs) {
|
2020-09-20 07:39:28 +02:00
|
|
|
for (struct isis_item *i = subtlvs->prefix_sids.head; i;
|
|
|
|
i = i->next) {
|
|
|
|
struct isis_prefix_sid *psid =
|
|
|
|
(struct isis_prefix_sid *)i;
|
|
|
|
|
2021-12-11 04:01:07 +01:00
|
|
|
if (psid->algorithm != spftree->algorithm)
|
2020-09-20 07:39:28 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
has_valid_psid = true;
|
|
|
|
isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0,
|
|
|
|
psid, parent);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop the Prefix-SID iteration since we only support
|
|
|
|
* the SPF algorithm for now.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-06-04 16:31:40 +02:00
|
|
|
if (!has_valid_psid)
|
2020-09-20 07:39:28 +02:00
|
|
|
isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, NULL,
|
|
|
|
parent);
|
2020-08-23 05:22:32 +02:00
|
|
|
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void isis_spf_preload_tent(struct isis_spftree *spftree,
|
|
|
|
uint8_t *root_sysid,
|
|
|
|
struct isis_lsp *root_lsp,
|
|
|
|
struct isis_vertex *parent)
|
|
|
|
{
|
|
|
|
struct spf_preload_tent_ip_reach_args ip_reach_args;
|
|
|
|
struct isis_spf_adj *sadj;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) {
|
|
|
|
ip_reach_args.spftree = spftree;
|
|
|
|
ip_reach_args.parent = parent;
|
|
|
|
isis_lsp_iterate_ip_reach(
|
|
|
|
root_lsp, spftree->family, spftree->mtid,
|
|
|
|
isis_spf_preload_tent_ip_reach_cb, &ip_reach_args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate over adjacencies. */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, node, sadj)) {
|
2020-08-21 00:55:42 +02:00
|
|
|
const uint8_t *adj_id;
|
2020-08-23 05:22:32 +02:00
|
|
|
uint32_t metric;
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST))
|
|
|
|
adj_id = sadj->lan.desig_is_id;
|
|
|
|
else
|
|
|
|
adj_id = sadj->id;
|
|
|
|
|
|
|
|
if (isis_lfa_excise_adj_check(spftree, adj_id)) {
|
2020-11-20 22:59:35 +01:00
|
|
|
if (IS_DEBUG_LFA)
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_debug("ISIS-SPF: excising adjacency %pPN",
|
|
|
|
sadj->id);
|
2020-08-21 00:55:42 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
metric = CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)
|
|
|
|
? 1
|
|
|
|
: sadj->metric;
|
|
|
|
if (!LSP_PSEUDO_ID(sadj->id)) {
|
|
|
|
isis_spf_add_local(spftree,
|
|
|
|
CHECK_FLAG(sadj->flags,
|
|
|
|
F_ISIS_SPF_ADJ_OLDMETRIC)
|
|
|
|
? VTYPE_NONPSEUDO_IS
|
|
|
|
: VTYPE_NONPSEUDO_TE_IS,
|
2020-09-20 07:39:28 +02:00
|
|
|
sadj->id, sadj, metric, NULL,
|
|
|
|
parent);
|
2020-11-24 23:38:11 +01:00
|
|
|
} else if (sadj->lsp) {
|
|
|
|
isis_spf_process_lsp(spftree, sadj->lsp, metric, 0,
|
|
|
|
spftree->sysid, parent);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-24 20:27:15 +02:00
|
|
|
struct spf_adj_find_reverse_metric_args {
|
|
|
|
const uint8_t *id_self;
|
|
|
|
uint32_t reverse_metric;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int spf_adj_find_reverse_metric_cb(const uint8_t *id, uint32_t metric,
|
|
|
|
bool oldmetric,
|
|
|
|
struct isis_ext_subtlvs *subtlvs,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
struct spf_adj_find_reverse_metric_args *args = arg;
|
|
|
|
|
|
|
|
if (memcmp(id, args->id_self, ISIS_SYS_ID_LEN))
|
|
|
|
return LSP_ITER_CONTINUE;
|
|
|
|
|
|
|
|
args->reverse_metric = metric;
|
|
|
|
|
|
|
|
return LSP_ITER_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change all SPF adjacencies to use the link cost in the direction from the
|
|
|
|
* next hop back towards root in place of the link cost in the direction away
|
|
|
|
* from root towards the next hop.
|
|
|
|
*/
|
|
|
|
static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
struct isis_spf_adj *sadj;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS(spftree->sadj_list, node, nnode, sadj)) {
|
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
struct isis_lsp *lsp_adj;
|
|
|
|
const uint8_t *id_self;
|
|
|
|
struct spf_adj_find_reverse_metric_args args;
|
|
|
|
|
|
|
|
/* Skip pseudonodes. */
|
|
|
|
if (LSP_PSEUDO_ID(sadj->id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Find LSP of the corresponding adjacency. */
|
|
|
|
memcpy(lspid, sadj->id, ISIS_SYS_ID_LEN);
|
|
|
|
LSP_PSEUDO_ID(lspid) = 0;
|
|
|
|
LSP_FRAGMENT(lspid) = 0;
|
|
|
|
lsp_adj = lsp_search(spftree->lspdb, lspid);
|
|
|
|
if (lsp_adj == NULL || lsp_adj->hdr.rem_lifetime == 0) {
|
|
|
|
/* Delete one-way adjacency. */
|
|
|
|
listnode_delete(spftree->sadj_list, sadj);
|
2022-12-09 13:44:26 +01:00
|
|
|
isis_spf_adj_free(sadj);
|
2020-08-24 20:27:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find root node in the LSP of the adjacent router. */
|
|
|
|
if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST))
|
|
|
|
id_self = sadj->lan.desig_is_id;
|
|
|
|
else
|
|
|
|
id_self = spftree->sysid;
|
|
|
|
args.id_self = id_self;
|
|
|
|
args.reverse_metric = UINT32_MAX;
|
|
|
|
isis_lsp_iterate_is_reach(lsp_adj, spftree->mtid,
|
|
|
|
spf_adj_find_reverse_metric_cb,
|
|
|
|
&args);
|
|
|
|
if (args.reverse_metric == UINT32_MAX) {
|
|
|
|
/* Delete one-way adjacency. */
|
|
|
|
listnode_delete(spftree->sadj_list, sadj);
|
2022-12-09 13:44:26 +01:00
|
|
|
isis_spf_adj_free(sadj);
|
2020-08-24 20:27:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sadj->metric = args.reverse_metric;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
|
|
|
|
struct list *adj_list, const uint8_t *id,
|
|
|
|
const uint8_t *desig_is_id,
|
|
|
|
uint32_t pseudo_metric, uint32_t metric,
|
|
|
|
bool oldmetric,
|
|
|
|
struct isis_ext_subtlvs *subtlvs)
|
|
|
|
{
|
|
|
|
struct isis_spf_adj *sadj;
|
2020-11-24 23:38:11 +01:00
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
struct isis_lsp *lsp;
|
2020-08-23 05:22:32 +02:00
|
|
|
uint8_t flags = 0;
|
|
|
|
|
|
|
|
/* Skip self in the pseudonode. */
|
|
|
|
if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN))
|
|
|
|
return;
|
|
|
|
|
2020-11-24 23:38:11 +01:00
|
|
|
/* Find LSP from the adjacency. */
|
|
|
|
memcpy(lspid, id, ISIS_SYS_ID_LEN + 1);
|
|
|
|
LSP_FRAGMENT(lspid) = 0;
|
|
|
|
lsp = lsp_search(spftree->lspdb, lspid);
|
|
|
|
if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_warn("ISIS-SPF: No LSP found from root to L%d %pLS",
|
|
|
|
spftree->level, lspid);
|
2020-11-24 23:38:11 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
sadj = XCALLOC(MTYPE_ISIS_SPF_ADJ, sizeof(*sadj));
|
|
|
|
memcpy(sadj->id, id, sizeof(sadj->id));
|
|
|
|
if (desig_is_id) {
|
|
|
|
memcpy(sadj->lan.desig_is_id, desig_is_id,
|
|
|
|
sizeof(sadj->lan.desig_is_id));
|
|
|
|
SET_FLAG(flags, F_ISIS_SPF_ADJ_BROADCAST);
|
|
|
|
sadj->metric = pseudo_metric;
|
|
|
|
} else
|
|
|
|
sadj->metric = metric;
|
|
|
|
if (oldmetric)
|
|
|
|
SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC);
|
2020-11-24 23:38:11 +01:00
|
|
|
sadj->lsp = lsp;
|
2020-08-23 05:22:32 +02:00
|
|
|
sadj->subtlvs = subtlvs;
|
|
|
|
sadj->flags = flags;
|
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
if ((oldmetric && metric == ISIS_NARROW_METRIC_INFINITY)
|
|
|
|
|| (!oldmetric && metric == ISIS_WIDE_METRIC_INFINITY))
|
|
|
|
SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY);
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
/* Set real adjacency. */
|
|
|
|
if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)
|
|
|
|
&& !LSP_PSEUDO_ID(id)) {
|
|
|
|
struct isis_adjacency *adj;
|
|
|
|
|
|
|
|
adj = adj_find(adj_list, id, spftree->level, spftree->mtid,
|
|
|
|
spftree->family);
|
|
|
|
if (!adj) {
|
|
|
|
XFREE(MTYPE_ISIS_SPF_ADJ, sadj);
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
|
|
|
|
listnode_delete(adj_list, adj);
|
|
|
|
sadj->adj = adj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add adjacency to the list. */
|
|
|
|
listnode_add(spftree->sadj_list, sadj);
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (!LSP_PSEUDO_ID(id)) {
|
|
|
|
struct isis_spf_node *node;
|
|
|
|
|
|
|
|
node = isis_spf_node_find(&spftree->adj_nodes, id);
|
|
|
|
if (!node)
|
|
|
|
node = isis_spf_node_new(&spftree->adj_nodes, id);
|
|
|
|
if (node->best_metric == 0 || sadj->metric < node->best_metric)
|
|
|
|
node->best_metric = sadj->metric;
|
|
|
|
listnode_add(node->adjacencies, sadj);
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
/* Parse pseudonode LSP too. */
|
2020-11-24 23:38:11 +01:00
|
|
|
if (LSP_PSEUDO_ID(id))
|
|
|
|
spf_adj_list_parse_lsp(spftree, adj_list, lsp, id, metric);
|
2020-08-23 05:22:32 +02:00
|
|
|
}
|
|
|
|
|
2022-05-27 10:37:08 +02:00
|
|
|
static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
|
|
|
|
struct list *adj_list, struct isis_lsp *lsp,
|
|
|
|
const uint8_t *pseudo_nodeid,
|
|
|
|
uint32_t pseudo_metric)
|
2020-08-23 05:22:32 +02:00
|
|
|
{
|
|
|
|
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
|
2022-05-27 10:37:08 +02:00
|
|
|
struct isis_lsp *frag;
|
|
|
|
struct listnode *node;
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_item *head;
|
|
|
|
struct isis_item_list *te_neighs;
|
|
|
|
|
|
|
|
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
|
|
|
|
return;
|
|
|
|
|
isisd: fix infinite loop when parsing LSPs
Fixing the crash:
> #0 0x0000560aa80f8e30 in lspdb_const_find (h=<error reading variable: Cannot access memory at address 0x7fff5e95efe8>, item=<error reading variable: Cannot access memory at address 0x7fff5e95efe0>) at ./isisd/isis_lsp.h:64
> #1 0x0000560aa80f8e9d in lspdb_find (h=0x560aaa1ed3b8, item=0x7fff5e95f050) at ./isisd/isis_lsp.h:64
> #2 0x0000560aa80f92f9 in lsp_search (head=0x560aaa1ed3b8, id=0x7fff5e95f200 "") at isisd/isis_lsp.c:100
> #3 0x0000560aa8113d69 in spf_adj_list_parse_tlv (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, id=0x560aad331a78 "", desig_is_id=0x0, pseudo_metric=0, metric=3, oldmetric=false, subtlvs=0x0) at isisd/isis_spf.c:1330
> #4 0x0000560aa811419d in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1429
> #5 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #6 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> (...)
> #65507 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65508 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65509 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65510 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65511 0x0000560aa8114313 in isis_spf_build_adj_list (spftree=0x560aaa1f09d0, lsp=0x560aaa1f4e50) at isisd/isis_spf.c:1455
> #65512 0x0000560aa8114f09 in isis_run_spf (spftree=0x560aaa1f09d0) at isisd/isis_spf.c:1775
> #65513 0x0000560aa8115057 in isis_run_spf_with_protection (area=0x560aaa1ed3b0, spftree=0x560aaa1f09d0) at isisd/isis_spf.c:1801
> #65514 0x0000560aa8115311 in isis_run_spf_cb (thread=0x7fff5f15e5a0) at isisd/isis_spf.c:1859
> #65515 0x00007f90bac66dcc in thread_call (thread=0x7fff5f15e5a0) at lib/thread.c:2002
> #65516 0x00007f90bac013ee in frr_run (master=0x560aa9f5cb40) at lib/libfrr.c:1196
> #65517 0x0000560aa80e7da2 in main (argc=2, argv=0x7fff5f15e7b8, envp=0x7fff5f15e7d0) at isisd/isis_main.c:273
The fix is similar to the crash fix included in d9884a758c
("isisd: Prepare IS-IS for Link State support"). The fix was:
> diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
> index 94353a5bc8..92d329f035 100644
> --- a/isisd/isis_lsp.c
> +++ b/isisd/isis_lsp.c
> @@ -2166,7 +2178,7 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
> if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
> return LSP_ITER_CONTINUE;
>
> - /* Parse main LSP. */
> + /* Parse LSP */
> if (lsp->tlvs) {
> if (!fabricd && !pseudo_lsp && family == AF_INET
> && mtid == ISIS_MT_IPV4_UNICAST) {
> @@ -2236,13 +2248,17 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
> }
> }
>
> - /* Parse LSP fragments. */
> - for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
> - if (!frag->tlvs)
> - continue;
> + /* Parse LSP fragments if it is not a fragment itself */
> + if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
> + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
> + if (!frag->tlvs)
> + continue;
>
> - isis_lsp_iterate_ip_reach(frag, family, mtid, cb, arg);
> - }
> + if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
> + arg)
> + == LSP_ITER_STOP)
> + return LSP_ITER_STOP;
> + }
>
> return LSP_ITER_CONTINUE;
> }
Fixes: 7b36d36e0e ("isisd: make the SPF code more modular")
Fixes: 5e56a50559 ("isisd: fix infinite loop when parsing LSPs")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2022-05-27 10:42:53 +02:00
|
|
|
/* Parse LSP. */
|
2020-08-23 05:22:32 +02:00
|
|
|
if (lsp->tlvs) {
|
|
|
|
if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
|
|
|
|
head = lsp->tlvs->oldstyle_reach.head;
|
|
|
|
for (struct isis_oldstyle_reach *reach =
|
|
|
|
(struct isis_oldstyle_reach *)head;
|
|
|
|
reach; reach = reach->next) {
|
|
|
|
spf_adj_list_parse_tlv(
|
|
|
|
spftree, adj_list, reach->id,
|
|
|
|
pseudo_nodeid, pseudo_metric,
|
|
|
|
reach->metric, true, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
|
|
|
|
te_neighs = &lsp->tlvs->extended_reach;
|
|
|
|
else
|
|
|
|
te_neighs = isis_get_mt_items(&lsp->tlvs->mt_reach,
|
|
|
|
spftree->mtid);
|
|
|
|
if (te_neighs) {
|
|
|
|
head = te_neighs->head;
|
|
|
|
for (struct isis_extended_reach *reach =
|
|
|
|
(struct isis_extended_reach *)head;
|
|
|
|
reach; reach = reach->next) {
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
/*
|
|
|
|
* cutting out adjacency by flex-algo link
|
|
|
|
* affinity attribute
|
|
|
|
*/
|
|
|
|
if (flex_algo_id_valid(spftree->algorithm) &&
|
|
|
|
(!sr_algorithm_participated(
|
|
|
|
lsp, spftree->algorithm) ||
|
|
|
|
isis_flex_algo_constraint_drop(
|
|
|
|
spftree, lsp, reach)))
|
|
|
|
continue;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
spf_adj_list_parse_tlv(
|
|
|
|
spftree, adj_list, reach->id,
|
|
|
|
pseudo_nodeid, pseudo_metric,
|
|
|
|
reach->metric, false, reach->subtlvs);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
isisd: fix infinite loop when parsing LSPs
Fixing the crash:
> #0 0x0000560aa80f8e30 in lspdb_const_find (h=<error reading variable: Cannot access memory at address 0x7fff5e95efe8>, item=<error reading variable: Cannot access memory at address 0x7fff5e95efe0>) at ./isisd/isis_lsp.h:64
> #1 0x0000560aa80f8e9d in lspdb_find (h=0x560aaa1ed3b8, item=0x7fff5e95f050) at ./isisd/isis_lsp.h:64
> #2 0x0000560aa80f92f9 in lsp_search (head=0x560aaa1ed3b8, id=0x7fff5e95f200 "") at isisd/isis_lsp.c:100
> #3 0x0000560aa8113d69 in spf_adj_list_parse_tlv (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, id=0x560aad331a78 "", desig_is_id=0x0, pseudo_metric=0, metric=3, oldmetric=false, subtlvs=0x0) at isisd/isis_spf.c:1330
> #4 0x0000560aa811419d in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1429
> #5 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #6 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> (...)
> #65507 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65508 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65509 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1ff8e0, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65510 0x0000560aa81141fe in spf_adj_list_parse_lsp (spftree=0x560aaa1f09d0, adj_list=0x560aaa214480, lsp=0x560aaa1f4e50, pseudo_nodeid=0x0, pseudo_metric=0) at isisd/isis_spf.c:1442
> #65511 0x0000560aa8114313 in isis_spf_build_adj_list (spftree=0x560aaa1f09d0, lsp=0x560aaa1f4e50) at isisd/isis_spf.c:1455
> #65512 0x0000560aa8114f09 in isis_run_spf (spftree=0x560aaa1f09d0) at isisd/isis_spf.c:1775
> #65513 0x0000560aa8115057 in isis_run_spf_with_protection (area=0x560aaa1ed3b0, spftree=0x560aaa1f09d0) at isisd/isis_spf.c:1801
> #65514 0x0000560aa8115311 in isis_run_spf_cb (thread=0x7fff5f15e5a0) at isisd/isis_spf.c:1859
> #65515 0x00007f90bac66dcc in thread_call (thread=0x7fff5f15e5a0) at lib/thread.c:2002
> #65516 0x00007f90bac013ee in frr_run (master=0x560aa9f5cb40) at lib/libfrr.c:1196
> #65517 0x0000560aa80e7da2 in main (argc=2, argv=0x7fff5f15e7b8, envp=0x7fff5f15e7d0) at isisd/isis_main.c:273
The fix is similar to the crash fix included in d9884a758c
("isisd: Prepare IS-IS for Link State support"). The fix was:
> diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
> index 94353a5bc8..92d329f035 100644
> --- a/isisd/isis_lsp.c
> +++ b/isisd/isis_lsp.c
> @@ -2166,7 +2178,7 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
> if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
> return LSP_ITER_CONTINUE;
>
> - /* Parse main LSP. */
> + /* Parse LSP */
> if (lsp->tlvs) {
> if (!fabricd && !pseudo_lsp && family == AF_INET
> && mtid == ISIS_MT_IPV4_UNICAST) {
> @@ -2236,13 +2248,17 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid,
> }
> }
>
> - /* Parse LSP fragments. */
> - for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
> - if (!frag->tlvs)
> - continue;
> + /* Parse LSP fragments if it is not a fragment itself */
> + if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
> + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
> + if (!frag->tlvs)
> + continue;
>
> - isis_lsp_iterate_ip_reach(frag, family, mtid, cb, arg);
> - }
> + if (isis_lsp_iterate_ip_reach(frag, family, mtid, cb,
> + arg)
> + == LSP_ITER_STOP)
> + return LSP_ITER_STOP;
> + }
>
> return LSP_ITER_CONTINUE;
> }
Fixes: 7b36d36e0e ("isisd: make the SPF code more modular")
Fixes: 5e56a50559 ("isisd: fix infinite loop when parsing LSPs")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
2022-05-27 10:42:53 +02:00
|
|
|
if (LSP_FRAGMENT(lsp->hdr.lsp_id))
|
|
|
|
return;
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
/* Parse LSP fragments. */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
|
|
|
|
if (!frag->tlvs)
|
|
|
|
continue;
|
|
|
|
|
2022-05-27 10:37:08 +02:00
|
|
|
spf_adj_list_parse_lsp(spftree, adj_list, frag, pseudo_nodeid,
|
|
|
|
pseudo_metric);
|
2020-08-23 05:22:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void isis_spf_build_adj_list(struct isis_spftree *spftree,
|
|
|
|
struct isis_lsp *lsp)
|
|
|
|
{
|
|
|
|
struct list *adj_list = NULL;
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
|
|
|
adj_list = list_dup(spftree->area->adjacency_list);
|
|
|
|
|
|
|
|
spf_adj_list_parse_lsp(spftree, adj_list, lsp, NULL, 0);
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
|
|
|
list_delete(&adj_list);
|
2020-08-24 20:27:15 +02:00
|
|
|
|
|
|
|
if (spftree->type == SPF_TYPE_REVERSE)
|
|
|
|
spf_adj_get_reverse_metrics(spftree);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The parent(s) for vertex is set when added to TENT list
|
|
|
|
* now we just put the child pointer(s) in place
|
|
|
|
*/
|
2017-04-27 12:54:21 +02:00
|
|
|
static void add_to_paths(struct isis_spftree *spftree,
|
|
|
|
struct isis_vertex *vertex)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2020-09-25 23:37:48 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2020-09-25 23:37:48 +02:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2018-06-25 12:16:32 +02:00
|
|
|
if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
|
2012-03-24 16:35:20 +01:00
|
|
|
return;
|
2017-09-22 21:20:03 +02:00
|
|
|
isis_vertex_queue_append(&spftree->paths, vertex);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2022-02-16 15:35:40 +01:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
2022-08-30 11:21:20 +02:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-SPF: A:%hhu S:%p added %s %s %s depth %d dist %d to PATHS",
|
|
|
|
spftree->algorithm, spftree,
|
|
|
|
print_sys_hostname(vertex->N.id),
|
|
|
|
vtype2string(vertex->type),
|
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
|
|
|
vertex->d_N);
|
2004-09-10 22:48:21 +02:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2020-09-25 23:37:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void init_spt(struct isis_spftree *spftree, int mtid)
|
|
|
|
{
|
|
|
|
/* Clear data from previous run. */
|
2020-10-24 02:05:30 +02:00
|
|
|
hash_clean(spftree->prefix_sids, NULL);
|
2020-09-25 23:37:48 +02:00
|
|
|
isis_spf_node_list_clear(&spftree->adj_nodes);
|
|
|
|
list_delete_all_node(spftree->sadj_list);
|
|
|
|
isis_vertex_queue_clear(&spftree->tents);
|
|
|
|
isis_vertex_queue_clear(&spftree->paths);
|
2020-11-26 03:39:09 +01:00
|
|
|
isis_zebra_rlfa_unregister_all(spftree);
|
|
|
|
isis_rlfa_list_clear(spftree);
|
|
|
|
list_delete_all_node(spftree->lfa.remote.pc_spftrees);
|
2020-11-20 23:55:42 +01:00
|
|
|
memset(&spftree->lfa.protection_counters, 0,
|
|
|
|
sizeof(spftree->lfa.protection_counters));
|
2020-09-25 23:37:48 +02:00
|
|
|
|
|
|
|
spftree->mtid = mtid;
|
|
|
|
}
|
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
static enum spf_prefix_priority
|
|
|
|
spf_prefix_priority(struct isis_spftree *spftree, struct isis_vertex *vertex)
|
|
|
|
{
|
|
|
|
struct isis_area *area = spftree->area;
|
|
|
|
struct prefix *prefix = &vertex->N.ip.p.dest;
|
|
|
|
|
|
|
|
for (int priority = SPF_PREFIX_PRIO_CRITICAL;
|
|
|
|
priority <= SPF_PREFIX_PRIO_MEDIUM; priority++) {
|
|
|
|
struct spf_prefix_priority_acl *ppa;
|
|
|
|
enum filter_type ret = FILTER_PERMIT;
|
|
|
|
|
|
|
|
ppa = &area->spf_prefix_priorities[priority];
|
|
|
|
switch (spftree->family) {
|
|
|
|
case AF_INET:
|
|
|
|
ret = access_list_apply(ppa->list_v4, prefix);
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
ret = access_list_apply(ppa->list_v6, prefix);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == FILTER_PERMIT)
|
|
|
|
return priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign medium priority to loopback prefixes by default. */
|
|
|
|
if (is_host_route(prefix))
|
|
|
|
return SPF_PREFIX_PRIO_MEDIUM;
|
|
|
|
|
|
|
|
return SPF_PREFIX_PRIO_LOW;
|
|
|
|
}
|
|
|
|
|
2020-09-25 23:37:48 +02:00
|
|
|
static void spf_path_process(struct isis_spftree *spftree,
|
|
|
|
struct isis_vertex *vertex)
|
|
|
|
{
|
|
|
|
struct isis_area *area = spftree->area;
|
2020-11-07 01:15:39 +01:00
|
|
|
int level = spftree->level;
|
2020-09-25 23:37:48 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
if (spftree->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type)
|
2020-08-31 20:24:02 +02:00
|
|
|
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
|
|
|
|
if (listcount(vertex->Adj_N) > 0) {
|
2020-11-07 01:15:39 +01:00
|
|
|
struct isis_adjacency *adj;
|
2020-08-31 20:24:02 +02:00
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
if (isis_tilfa_check(spftree, vertex) != 0)
|
|
|
|
return;
|
2020-08-31 20:24:02 +02:00
|
|
|
|
2020-11-07 01:15:39 +01:00
|
|
|
adj = isis_adj_find(area, level, vertex->N.id);
|
|
|
|
if (adj)
|
|
|
|
sr_adj_sid_add_single(adj, spftree->family,
|
|
|
|
true, vertex->Adj_N);
|
2020-08-31 20:24:02 +02:00
|
|
|
} else if (IS_DEBUG_SPF_EVENTS)
|
|
|
|
zlog_debug(
|
2020-09-20 18:21:53 +02:00
|
|
|
"ISIS-SPF: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d",
|
2020-08-31 20:24:02 +02:00
|
|
|
vid2string(vertex, buff, sizeof(buff)),
|
|
|
|
vertex->depth, vertex->d_N);
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (VTYPE_IP(vertex->type)
|
|
|
|
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
|
2020-11-07 01:15:39 +01:00
|
|
|
enum spf_prefix_priority priority;
|
|
|
|
|
|
|
|
priority = spf_prefix_priority(spftree, vertex);
|
|
|
|
vertex->N.ip.priority = priority;
|
2020-10-17 01:57:37 +02:00
|
|
|
if (vertex->depth == 1 || listcount(vertex->Adj_N) > 0) {
|
2020-11-26 03:39:09 +01:00
|
|
|
struct isis_spftree *pre_spftree;
|
2023-01-30 16:08:47 +01:00
|
|
|
struct route_table *route_table = NULL;
|
|
|
|
bool allow_ecmp = false;
|
2020-08-21 00:55:42 +02:00
|
|
|
|
2020-11-26 03:39:09 +01:00
|
|
|
switch (spftree->type) {
|
|
|
|
case SPF_TYPE_RLFA:
|
|
|
|
case SPF_TYPE_TI_LFA:
|
2020-11-07 01:15:39 +01:00
|
|
|
if (priority
|
|
|
|
> area->lfa_priority_limit[level - 1]) {
|
|
|
|
if (IS_DEBUG_LFA)
|
|
|
|
zlog_debug(
|
|
|
|
"ISIS-LFA: skipping %s %s (low prefix priority)",
|
|
|
|
vtype2string(
|
|
|
|
vertex->type),
|
|
|
|
vid2string(
|
|
|
|
vertex, buff,
|
|
|
|
sizeof(buff)));
|
2020-08-21 00:55:42 +02:00
|
|
|
return;
|
2020-11-07 01:15:39 +01:00
|
|
|
}
|
2020-11-26 03:39:09 +01:00
|
|
|
break;
|
2023-01-30 16:08:47 +01:00
|
|
|
case SPF_TYPE_FORWARD:
|
|
|
|
case SPF_TYPE_REVERSE:
|
2020-11-26 03:39:09 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-11-07 01:15:39 +01:00
|
|
|
|
2020-11-26 03:39:09 +01:00
|
|
|
switch (spftree->type) {
|
|
|
|
case SPF_TYPE_RLFA:
|
|
|
|
isis_rlfa_check(spftree, vertex);
|
|
|
|
return;
|
|
|
|
case SPF_TYPE_TI_LFA:
|
2020-11-07 01:15:39 +01:00
|
|
|
if (isis_tilfa_check(spftree, vertex) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pre_spftree = spftree->lfa.old.spftree;
|
|
|
|
route_table = pre_spftree->route_table_backup;
|
|
|
|
allow_ecmp = area->lfa_load_sharing[level - 1];
|
2020-11-20 23:55:42 +01:00
|
|
|
pre_spftree->lfa.protection_counters
|
|
|
|
.tilfa[vertex->N.ip.priority] += 1;
|
2020-11-26 03:39:09 +01:00
|
|
|
break;
|
2023-01-30 16:08:47 +01:00
|
|
|
case SPF_TYPE_FORWARD:
|
|
|
|
case SPF_TYPE_REVERSE:
|
2020-08-21 00:55:42 +02:00
|
|
|
route_table = spftree->route_table;
|
2020-11-07 01:15:39 +01:00
|
|
|
allow_ecmp = true;
|
2020-11-20 23:55:42 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Update LFA protection counters (ignore local
|
|
|
|
* routes).
|
|
|
|
*/
|
|
|
|
if (vertex->depth > 1) {
|
|
|
|
spftree->lfa.protection_counters
|
|
|
|
.total[priority] += 1;
|
|
|
|
if (listcount(vertex->Adj_N) > 1)
|
|
|
|
spftree->lfa.protection_counters
|
|
|
|
.ecmp[priority] += 1;
|
|
|
|
}
|
2020-11-26 03:39:09 +01:00
|
|
|
break;
|
2020-11-07 01:15:39 +01:00
|
|
|
}
|
2020-08-21 00:55:42 +02:00
|
|
|
|
2022-08-30 11:21:20 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
|
|
|
struct isis_route_info *ri =
|
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
isis_route_create(&vertex->N.ip.p.dest,
|
|
|
|
&vertex->N.ip.p.src,
|
|
|
|
vertex->d_N, vertex->depth,
|
|
|
|
&vertex->N.ip.sr,
|
|
|
|
vertex->Adj_N, allow_ecmp,
|
|
|
|
area, route_table);
|
|
|
|
|
|
|
|
#ifdef EXTREME_DEBUG
|
|
|
|
zlog_debug(
|
|
|
|
"ISIS-SPF: A:%hhu create route pfx %pFX dist %d, sr.algo %d, table %p, rv %p",
|
|
|
|
spftree->algorithm, &vertex->N.ip.p.dest,
|
|
|
|
vertex->d_N, vertex->N.ip.sr.algorithm,
|
|
|
|
route_table, ri);
|
|
|
|
#endif /* EXTREME_DEBUG */
|
2020-08-21 00:55:42 +02:00
|
|
|
} else if (IS_DEBUG_SPF_EVENTS)
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2020-09-20 18:21:53 +02:00
|
|
|
"ISIS-SPF: no adjacencies, do not install route for %s depth %d dist %d",
|
2015-11-23 21:44:34 +01:00
|
|
|
vid2string(vertex, buff, sizeof(buff)),
|
2012-03-24 16:35:20 +01:00
|
|
|
vertex->depth, vertex->d_N);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void isis_spf_loop(struct isis_spftree *spftree,
|
|
|
|
uint8_t *root_sysid)
|
|
|
|
{
|
|
|
|
struct isis_vertex *vertex;
|
|
|
|
struct isis_lsp *lsp;
|
2020-09-25 23:37:48 +02:00
|
|
|
struct listnode *node;
|
2018-04-02 18:39:46 +02:00
|
|
|
|
|
|
|
while (isis_vertex_queue_count(&spftree->tents)) {
|
|
|
|
vertex = isis_vertex_queue_pop(&spftree->tents);
|
|
|
|
|
|
|
|
#ifdef EXTREME_DEBUG
|
2022-08-30 11:21:20 +02:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-SPF: A:%hhu get TENT node %s %s depth %d dist %d to PATHS",
|
|
|
|
spftree->algorithm, print_sys_hostname(vertex->N.id),
|
|
|
|
vtype2string(vertex->type), vertex->depth, vertex->d_N);
|
2018-04-02 18:39:46 +02:00
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
|
|
|
|
add_to_paths(spftree, vertex);
|
2018-05-10 18:52:17 +02:00
|
|
|
if (!VTYPE_IS(vertex->type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
lsp = lsp_for_vertex(spftree, vertex);
|
|
|
|
if (!lsp) {
|
2023-01-26 17:47:04 +01:00
|
|
|
zlog_warn("ISIS-SPF: No LSP found for %pPN",
|
|
|
|
vertex->N.id);
|
2018-05-10 18:52:17 +02:00
|
|
|
continue;
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
2018-05-10 18:52:17 +02:00
|
|
|
|
|
|
|
isis_spf_process_lsp(spftree, lsp, vertex->d_N, vertex->depth,
|
|
|
|
root_sysid, vertex);
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
2020-09-25 23:37:48 +02:00
|
|
|
|
|
|
|
/* Generate routes once the SPT is formed. */
|
|
|
|
for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, vertex)) {
|
|
|
|
/* New-style TLVs take precedence over the old-style TLVs. */
|
|
|
|
switch (vertex->type) {
|
|
|
|
case VTYPE_IPREACH_INTERNAL:
|
|
|
|
case VTYPE_IPREACH_EXTERNAL:
|
|
|
|
if (isis_find_vertex(&spftree->paths, &vertex->N,
|
|
|
|
VTYPE_IPREACH_TE))
|
|
|
|
continue;
|
|
|
|
break;
|
2023-01-30 16:08:47 +01:00
|
|
|
case VTYPE_PSEUDO_IS:
|
|
|
|
case VTYPE_PSEUDO_TE_IS:
|
|
|
|
case VTYPE_NONPSEUDO_IS:
|
|
|
|
case VTYPE_NONPSEUDO_TE_IS:
|
|
|
|
case VTYPE_ES:
|
|
|
|
case VTYPE_IPREACH_TE:
|
|
|
|
case VTYPE_IP6REACH_INTERNAL:
|
|
|
|
case VTYPE_IP6REACH_EXTERNAL:
|
2020-09-25 23:37:48 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
spf_path_process(spftree, vertex);
|
|
|
|
}
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
|
|
|
|
uint8_t *sysid,
|
|
|
|
struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
if (!spftree)
|
2021-12-11 03:09:23 +01:00
|
|
|
spftree = isis_spftree_new(
|
|
|
|
area, &area->lspdb[IS_LEVEL_2 - 1], sysid, ISIS_LEVEL2,
|
|
|
|
SPFTREE_IPV4, SPF_TYPE_FORWARD,
|
|
|
|
F_SPFTREE_HOPCOUNT_METRIC, SR_ALGORITHM_SPF);
|
2020-07-13 14:37:59 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
init_spt(spftree, ISIS_MT_IPV4_UNICAST);
|
2020-07-13 14:37:59 +02:00
|
|
|
if (!memcmp(sysid, area->isis->sysid, ISIS_SYS_ID_LEN)) {
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_lsp *root_lsp;
|
|
|
|
struct isis_vertex *root_vertex;
|
|
|
|
|
|
|
|
root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid);
|
|
|
|
if (root_lsp) {
|
|
|
|
/*
|
|
|
|
* If we are running locally, initialize with
|
|
|
|
* information from adjacencies
|
|
|
|
*/
|
|
|
|
root_vertex = isis_spf_add_root(spftree);
|
|
|
|
|
|
|
|
isis_spf_preload_tent(spftree, sysid, root_lsp,
|
|
|
|
root_vertex);
|
|
|
|
}
|
2018-04-02 18:39:46 +02:00
|
|
|
} else {
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_vertex_queue_insert(
|
|
|
|
&spftree->tents,
|
|
|
|
isis_vertex_new(spftree, sysid, VTYPE_NONPSEUDO_TE_IS));
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
isis_spf_loop(spftree, sysid);
|
|
|
|
|
|
|
|
return spftree;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
void isis_run_spf(struct isis_spftree *spftree)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_lsp *root_lsp;
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_vertex *root_vertex;
|
2020-08-11 04:20:05 +02:00
|
|
|
struct timeval time_start;
|
|
|
|
struct timeval time_end;
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_mt_router_info *mt_router_info;
|
2018-07-26 15:08:11 +02:00
|
|
|
uint16_t mtid = 0;
|
2023-05-31 16:53:58 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
bool flex_algo_enabled;
|
|
|
|
#endif /* ifndef FABRICD */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-28 08:48:05 +02:00
|
|
|
/* Get time that can't roll backwards. */
|
2020-08-11 04:20:05 +02:00
|
|
|
monotime(&time_start);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid);
|
|
|
|
if (root_lsp == NULL) {
|
2020-09-20 18:21:53 +02:00
|
|
|
zlog_err("ISIS-SPF: could not find own l%d LSP!",
|
2020-08-23 05:22:32 +02:00
|
|
|
spftree->level);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get Multi-Topology ID. */
|
|
|
|
switch (spftree->tree_id) {
|
2018-07-26 15:08:11 +02:00
|
|
|
case SPFTREE_IPV4:
|
|
|
|
mtid = ISIS_MT_IPV4_UNICAST;
|
|
|
|
break;
|
|
|
|
case SPFTREE_IPV6:
|
2020-08-23 05:22:32 +02:00
|
|
|
mt_router_info = isis_tlvs_lookup_mt_router_info(
|
|
|
|
root_lsp->tlvs, ISIS_MT_IPV6_UNICAST);
|
|
|
|
if (mt_router_info)
|
|
|
|
mtid = ISIS_MT_IPV6_UNICAST;
|
|
|
|
else
|
|
|
|
mtid = ISIS_MT_IPV4_UNICAST;
|
2018-07-26 15:08:11 +02:00
|
|
|
break;
|
2018-07-26 22:53:08 +02:00
|
|
|
case SPFTREE_DSTSRC:
|
|
|
|
mtid = ISIS_MT_IPV6_DSTSRC;
|
|
|
|
break;
|
2018-07-26 15:08:11 +02:00
|
|
|
case SPFTREE_COUNT:
|
2020-08-23 05:22:32 +02:00
|
|
|
zlog_err(
|
2022-08-29 15:35:24 +02:00
|
|
|
"%s should never be called with SPFTREE_COUNT as argument!",
|
|
|
|
__func__);
|
2020-08-23 05:22:32 +02:00
|
|
|
exit(1);
|
2018-07-26 15:08:11 +02:00
|
|
|
}
|
|
|
|
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
/* If a node is configured to participate in a particular Flexible-
|
|
|
|
* Algorithm, but there is no valid Flex-Algorithm definition available
|
|
|
|
* for it, or the selected Flex-Algorithm definition includes
|
|
|
|
* calculation-type, metric-type, constraint, flag, or Sub-TLV that is
|
|
|
|
* not supported by the node, it MUST stop participating in such
|
|
|
|
* Flexible-Algorithm.
|
|
|
|
*/
|
2023-05-31 16:53:58 +02:00
|
|
|
if (flex_algo_id_valid(spftree->algorithm)) {
|
|
|
|
flex_algo_enabled = isis_flex_algo_elected_supported(
|
|
|
|
spftree->algorithm, spftree->area);
|
|
|
|
if (flex_algo_enabled !=
|
|
|
|
flex_algo_get_state(spftree->area->flex_algos,
|
|
|
|
spftree->algorithm)) {
|
|
|
|
/* actual state is inconsistent with local LSP */
|
2022-01-21 15:54:15 +01:00
|
|
|
lsp_regenerate_schedule(spftree->area,
|
|
|
|
spftree->area->is_type, 0);
|
2023-05-31 16:53:58 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (!flex_algo_enabled) {
|
|
|
|
if (!CHECK_FLAG(spftree->flags, F_SPFTREE_DISABLED)) {
|
|
|
|
isis_spftree_clear(spftree);
|
|
|
|
SET_FLAG(spftree->flags, F_SPFTREE_DISABLED);
|
|
|
|
lsp_regenerate_schedule(spftree->area,
|
|
|
|
spftree->area->is_type,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
goto out;
|
2022-01-21 15:54:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* C.2.5 Step 0
|
|
|
|
*/
|
2020-08-23 05:22:32 +02:00
|
|
|
init_spt(spftree, mtid);
|
2003-12-23 09:09:43 +01:00
|
|
|
/* a) */
|
2020-08-23 05:22:32 +02:00
|
|
|
root_vertex = isis_spf_add_root(spftree);
|
2003-12-23 09:09:43 +01:00
|
|
|
/* b) */
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_spf_build_adj_list(spftree, root_lsp);
|
|
|
|
isis_spf_preload_tent(spftree, spftree->sysid, root_lsp, root_vertex);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* C.2.7 Step 2
|
|
|
|
*/
|
2017-08-29 00:23:53 +02:00
|
|
|
if (!isis_vertex_queue_count(&spftree->tents)
|
2020-06-19 21:04:33 +02:00
|
|
|
&& (IS_DEBUG_SPF_EVENTS)) {
|
2020-09-20 18:21:53 +02:00
|
|
|
zlog_warn("ISIS-SPF: TENT is empty SPF-root:%s",
|
2020-08-23 05:22:32 +02:00
|
|
|
print_sys_hostname(spftree->sysid));
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_spf_loop(spftree, spftree->sysid);
|
2022-01-21 15:54:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
#ifndef FABRICD
|
|
|
|
/* flex-algo */
|
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_DISABLED)) {
|
|
|
|
UNSET_FLAG(spftree->flags, F_SPFTREE_DISABLED);
|
|
|
|
lsp_regenerate_schedule(spftree->area, spftree->area->is_type,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
#endif /* ifndef FABRICD */
|
2012-03-28 08:48:05 +02:00
|
|
|
spftree->runcount++;
|
|
|
|
spftree->last_run_timestamp = time(NULL);
|
2020-08-11 04:20:05 +02:00
|
|
|
spftree->last_run_monotime = monotime(&time_end);
|
|
|
|
spftree->last_run_duration =
|
|
|
|
((time_end.tv_sec - time_start.tv_sec) * 1000000)
|
|
|
|
+ (time_end.tv_usec - time_start.tv_usec);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
static void isis_run_spf_with_protection(struct isis_area *area,
|
|
|
|
struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
/* Run forward SPF locally. */
|
|
|
|
memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
|
|
|
|
isis_run_spf(spftree);
|
|
|
|
|
|
|
|
/* Run LFA protection if configured. */
|
2020-11-07 01:15:39 +01:00
|
|
|
if (area->lfa_protected_links[spftree->level - 1] > 0
|
|
|
|
|| area->tilfa_protected_links[spftree->level - 1] > 0)
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_spf_run_lfa(area, spftree);
|
|
|
|
}
|
|
|
|
|
2022-01-21 17:02:54 +01:00
|
|
|
void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees,
|
|
|
|
int tree)
|
2018-07-24 17:40:24 +02:00
|
|
|
{
|
|
|
|
if (area->is_type == IS_LEVEL_1) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_route_verify_table(area, trees[0]->route_table,
|
2022-01-21 17:02:54 +01:00
|
|
|
trees[0]->route_table_backup, tree);
|
2018-07-24 17:40:24 +02:00
|
|
|
} else if (area->is_type == IS_LEVEL_2) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_route_verify_table(area, trees[1]->route_table,
|
2022-01-21 17:02:54 +01:00
|
|
|
trees[1]->route_table_backup, tree);
|
2018-07-24 17:40:24 +02:00
|
|
|
} else {
|
|
|
|
isis_route_verify_merge(area, trees[0]->route_table,
|
2020-08-21 00:55:42 +02:00
|
|
|
trees[0]->route_table_backup,
|
|
|
|
trees[1]->route_table,
|
2022-01-21 17:02:54 +01:00
|
|
|
trees[1]->route_table_backup, tree);
|
2018-07-24 17:40:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void isis_spf_invalidate_routes(struct isis_spftree *tree)
|
|
|
|
{
|
2021-12-12 10:20:21 +01:00
|
|
|
struct isis_route_table_info *backup_info;
|
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
isis_route_invalidate_table(tree->area, tree->route_table);
|
2020-08-21 00:55:42 +02:00
|
|
|
|
|
|
|
/* Delete backup routes. */
|
2021-12-12 10:20:21 +01:00
|
|
|
|
|
|
|
backup_info = tree->route_table_backup->info;
|
2020-08-21 00:55:42 +02:00
|
|
|
route_table_finish(tree->route_table_backup);
|
2021-12-12 10:20:21 +01:00
|
|
|
isis_route_table_info_free(backup_info);
|
2020-08-21 00:55:42 +02:00
|
|
|
tree->route_table_backup = srcdest_table_init();
|
2021-12-12 10:20:21 +01:00
|
|
|
tree->route_table_backup->info =
|
|
|
|
isis_route_table_info_alloc(tree->algorithm);
|
2020-08-21 00:55:42 +02:00
|
|
|
tree->route_table_backup->cleanup = isis_route_node_cleanup;
|
2018-07-24 17:40:24 +02:00
|
|
|
}
|
|
|
|
|
2022-03-21 17:59:27 +01:00
|
|
|
void isis_spf_switchover_routes(struct isis_area *area,
|
|
|
|
struct isis_spftree **trees, int family,
|
|
|
|
union g_addr *nexthop_ip, ifindex_t ifindex,
|
|
|
|
int level)
|
|
|
|
{
|
|
|
|
isis_route_switchover_nexthop(area, trees[level - 1]->route_table,
|
|
|
|
family, nexthop_ip, ifindex);
|
|
|
|
}
|
|
|
|
|
2022-03-01 22:18:12 +01:00
|
|
|
static void isis_run_spf_cb(struct event *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct isis_spf_run *run = EVENT_ARG(thread);
|
2017-04-27 12:54:21 +02:00
|
|
|
struct isis_area *area = run->area;
|
|
|
|
int level = run->level;
|
2020-09-15 22:46:15 +02:00
|
|
|
int have_run = 0;
|
2022-01-21 15:54:15 +01:00
|
|
|
struct listnode *node;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
#ifndef FABRICD
|
|
|
|
struct flex_algo *fa;
|
|
|
|
struct isis_flex_algo_data *data;
|
|
|
|
#endif /* ifndef FABRICD */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
XFREE(MTYPE_ISIS_SPF_RUN, run);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
if (!(area->is_type & level)) {
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
2004-09-19 21:39:26 +02:00
|
|
|
zlog_warn("ISIS-SPF (%s) area does not share level",
|
|
|
|
area->area_tag);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-08-31 20:24:02 +02:00
|
|
|
isis_area_delete_backup_adj_sids(area, level);
|
2018-07-24 17:40:24 +02:00
|
|
|
isis_area_invalidate_routes(area, level);
|
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
2020-09-20 18:21:53 +02:00
|
|
|
zlog_debug("ISIS-SPF (%s) L%d SPF needed, periodic SPF",
|
2017-04-27 12:54:21 +02:00
|
|
|
area->area_tag, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-09-15 22:46:15 +02:00
|
|
|
if (area->ip_circuits) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_IPV4][level - 1]);
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node,
|
|
|
|
fa)) {
|
|
|
|
data = fa->data;
|
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, data->spftree[SPFTREE_IPV4][level - 1]);
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
2020-09-15 22:46:15 +02:00
|
|
|
have_run = 1;
|
|
|
|
}
|
|
|
|
if (area->ipv6_circuits) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_IPV6][level - 1]);
|
2022-01-21 15:54:15 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node,
|
|
|
|
fa)) {
|
|
|
|
data = fa->data;
|
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, data->spftree[SPFTREE_IPV6][level - 1]);
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
2020-09-15 22:46:15 +02:00
|
|
|
have_run = 1;
|
|
|
|
}
|
|
|
|
if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_DSTSRC][level - 1]);
|
2020-09-15 22:46:15 +02:00
|
|
|
have_run = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (have_run)
|
|
|
|
area->spf_run_count[level]++;
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
isis_area_verify_routes(area);
|
|
|
|
|
|
|
|
/* walk all circuits and reset any spf specific flags */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
|
|
|
|
UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
|
|
|
|
|
2018-04-02 18:39:46 +02:00
|
|
|
fabricd_run_spf(area);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
|
|
|
|
{
|
|
|
|
struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-21 23:52:29 +01:00
|
|
|
run->area = area;
|
2017-02-20 10:51:47 +01:00
|
|
|
run->level = level;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-20 10:51:47 +01:00
|
|
|
return run;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-11-14 23:32:01 +01:00
|
|
|
void isis_spf_timer_free(void *run)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_ISIS_SPF_RUN, run);
|
|
|
|
}
|
|
|
|
|
2018-10-24 05:28:12 +02:00
|
|
|
int _isis_spf_schedule(struct isis_area *area, int level,
|
|
|
|
const char *func, const char *file, int line)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-05-17 12:13:50 +02:00
|
|
|
struct isis_spftree *spftree;
|
|
|
|
time_t now;
|
|
|
|
long tree_diff, diff;
|
|
|
|
int tree;
|
|
|
|
|
|
|
|
now = monotime(NULL);
|
|
|
|
diff = 0;
|
|
|
|
for (tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
|
|
|
|
spftree = area->spftree[tree][level - 1];
|
|
|
|
tree_diff = difftime(now - spftree->last_run_monotime, 0);
|
|
|
|
if (tree_diff != now && (diff == 0 || tree_diff < diff))
|
|
|
|
diff = tree_diff;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-08-24 19:46:36 +02:00
|
|
|
if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
|
|
|
|
return 0;
|
|
|
|
|
2015-11-23 21:44:34 +01:00
|
|
|
assert(diff >= 0);
|
2017-07-13 18:50:29 +02:00
|
|
|
assert(area->is_type & level);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SPF_EVENTS) {
|
2015-11-23 21:44:34 +01:00
|
|
|
zlog_debug(
|
2022-05-17 12:13:50 +02:00
|
|
|
"ISIS-SPF (%s) L%d SPF schedule called, lastrun %ld sec ago Caller: %s %s:%d",
|
2018-10-24 05:28:12 +02:00
|
|
|
area->area_tag, level, diff, func, file, line);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(area->t_rlfa_rib_update);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area->spf_delay_ietf[level - 1]) {
|
|
|
|
/* Need to call schedule function also if spf delay is running
|
2017-07-17 14:03:14 +02:00
|
|
|
* to
|
2012-03-24 16:35:20 +01:00
|
|
|
* restart holdoff timer - compare
|
2017-02-21 23:52:29 +01:00
|
|
|
* draft-ietf-rtgwg-backoff-algo-04 */
|
|
|
|
long delay =
|
|
|
|
spf_backoff_schedule(area->spf_delay_ietf[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area->spf_timer[level - 1])
|
2017-02-21 23:52:29 +01:00
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer_msec(master, isis_run_spf_cb,
|
|
|
|
isis_run_spf_arg(area, level), delay,
|
|
|
|
&area->spf_timer[level - 1]);
|
2012-03-24 16:35:20 +01:00
|
|
|
return ISIS_OK;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
if (area->spf_timer[level - 1])
|
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
/* wait configured min_spf_interval before doing the SPF */
|
2017-09-23 19:28:48 +02:00
|
|
|
long timer;
|
2020-05-19 13:52:04 +02:00
|
|
|
if (diff >= area->min_spf_interval[level - 1]
|
|
|
|
|| area->bfd_force_spf_refresh) {
|
|
|
|
/*
|
|
|
|
* Last run is more than min interval ago or BFD signalled a
|
|
|
|
* 'down' message, schedule immediate run
|
|
|
|
*/
|
2017-09-23 19:28:48 +02:00
|
|
|
timer = 0;
|
2020-05-19 13:52:04 +02:00
|
|
|
|
|
|
|
if (area->bfd_force_spf_refresh) {
|
|
|
|
zlog_debug(
|
2020-09-20 18:21:53 +02:00
|
|
|
"ISIS-SPF (%s) L%d SPF scheduled immediately due to BFD 'down' message",
|
2020-05-19 13:52:04 +02:00
|
|
|
area->area_tag, level);
|
|
|
|
area->bfd_force_spf_refresh = false;
|
|
|
|
}
|
2017-09-23 19:28:48 +02:00
|
|
|
} else {
|
|
|
|
timer = area->min_spf_interval[level - 1] - diff;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, isis_run_spf_cb, isis_run_spf_arg(area, level),
|
|
|
|
timer, &area->spf_timer[level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-19 21:04:33 +02:00
|
|
|
if (IS_DEBUG_SPF_EVENTS)
|
2020-09-20 18:21:53 +02:00
|
|
|
zlog_debug("ISIS-SPF (%s) L%d SPF scheduled %ld sec from now",
|
2017-12-06 22:23:55 +01:00
|
|
|
area->area_tag, level, timer);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return ISIS_OK;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
uint8_t *root_sysid, struct json_object **json)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
struct listnode *node;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct isis_vertex *vertex;
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
2024-06-06 18:03:24 +02:00
|
|
|
char vertex_name[VID2STR_BUFFER];
|
|
|
|
char vertex_typestr[VID2STR_BUFFER];
|
|
|
|
char vertex_interface[VID2STR_BUFFER];
|
|
|
|
char vertex_parent[VID2STR_BUFFER + 11];
|
|
|
|
char vertex_nexthop[VID2STR_BUFFER];
|
|
|
|
char vertex_metricstr[20];
|
|
|
|
struct ttable *tt;
|
|
|
|
char *table;
|
|
|
|
|
|
|
|
/* Prepare table. */
|
|
|
|
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
|
|
|
|
ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent");
|
|
|
|
tt->style.cell.rpad = 2;
|
|
|
|
tt->style.corner = '+';
|
|
|
|
ttable_restyle(tt);
|
|
|
|
ttable_rowseps(tt, 0, BOTTOM, true, '-');
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
|
2020-11-20 23:26:45 +01:00
|
|
|
if (VTYPE_IS(vertex->type)
|
|
|
|
&& memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
|
2024-06-06 18:03:24 +02:00
|
|
|
/* display here */
|
|
|
|
ttable_add_row(tt, "%s|%s|%s|%s|%s|%s",
|
|
|
|
print_sys_hostname(root_sysid), "", "",
|
|
|
|
"", "", "");
|
2017-09-01 00:57:57 +02:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 00:57:57 +02:00
|
|
|
int rows = 0;
|
|
|
|
struct listnode *anode = listhead(vertex->Adj_N);
|
|
|
|
struct listnode *pnode = listhead(vertex->parents);
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_vertex_adj *vadj;
|
2017-09-01 00:57:57 +02:00
|
|
|
struct isis_vertex *pvertex;
|
|
|
|
|
2024-06-06 18:03:24 +02:00
|
|
|
snprintf(vertex_name, sizeof(vertex_name), "%s",
|
|
|
|
vid2string(vertex, buff, sizeof(buff)));
|
|
|
|
snprintf(vertex_typestr, sizeof(vertex_typestr), "%s",
|
|
|
|
vtype2string(vertex->type));
|
|
|
|
snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u",
|
|
|
|
vertex->d_N);
|
2018-06-29 17:14:23 +02:00
|
|
|
for (unsigned int i = 0;
|
|
|
|
i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0,
|
|
|
|
vertex->parents ? listcount(vertex->parents) : 0);
|
2017-09-01 00:57:57 +02:00
|
|
|
i++) {
|
|
|
|
if (anode) {
|
2020-08-23 05:22:32 +02:00
|
|
|
vadj = listgetdata(anode);
|
2017-09-01 00:57:57 +02:00
|
|
|
anode = anode->next;
|
|
|
|
} else {
|
2020-08-23 05:22:32 +02:00
|
|
|
vadj = NULL;
|
2017-09-01 00:57:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pnode) {
|
|
|
|
pvertex = listgetdata(pnode);
|
|
|
|
pnode = pnode->next;
|
|
|
|
} else {
|
|
|
|
pvertex = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rows) {
|
2024-06-06 18:03:24 +02:00
|
|
|
/* display here */
|
|
|
|
ttable_add_row(tt, "%s|%s|%s|%s|%s|%s",
|
|
|
|
vertex_name, vertex_typestr,
|
|
|
|
vertex_metricstr, vertex_nexthop,
|
|
|
|
vertex_interface, vertex_parent);
|
|
|
|
|
|
|
|
/* store the first 3 elements */
|
|
|
|
vertex_name[0] = '\0';
|
|
|
|
vertex_typestr[0] = '\0';
|
|
|
|
vertex_metricstr[0] = '\0';
|
2017-09-01 00:57:57 +02:00
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (vadj) {
|
|
|
|
struct isis_spf_adj *sadj = vadj->sadj;
|
|
|
|
|
2024-06-06 18:03:24 +02:00
|
|
|
snprintf(vertex_nexthop, sizeof(vertex_nexthop),
|
|
|
|
"%s", print_sys_hostname(sadj->id));
|
|
|
|
snprintf(vertex_interface,
|
|
|
|
sizeof(vertex_interface), "%s",
|
|
|
|
sadj->adj ? sadj->adj->circuit
|
|
|
|
->interface->name
|
|
|
|
: "-");
|
2017-09-01 00:57:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pvertex) {
|
2024-06-06 18:03:24 +02:00
|
|
|
if (!vadj) {
|
|
|
|
vertex_nexthop[0] = '\0';
|
|
|
|
vertex_interface[0] = '\0';
|
|
|
|
}
|
|
|
|
snprintf(vertex_parent, sizeof(vertex_parent),
|
|
|
|
"%s(%d)",
|
|
|
|
vid2string(pvertex, buff, sizeof(buff)),
|
|
|
|
pvertex->type);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 00:57:57 +02:00
|
|
|
++rows;
|
|
|
|
}
|
2024-06-06 18:03:24 +02:00
|
|
|
ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name,
|
|
|
|
vertex_typestr, vertex_metricstr, vertex_nexthop,
|
|
|
|
vertex_interface, vertex_parent);
|
|
|
|
}
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
if (json == NULL) {
|
|
|
|
table = ttable_dump(tt, "\n");
|
|
|
|
vty_out(vty, "%s\n", table);
|
|
|
|
XFREE(MTYPE_TMP, table);
|
|
|
|
} else
|
2024-06-19 16:05:33 +02:00
|
|
|
*json = ttable_json_with_json_text(
|
|
|
|
tt, "ssdsss",
|
|
|
|
"vertex|type|metric|nextHop|interface|parent");
|
2024-06-06 18:03:24 +02:00
|
|
|
ttable_del(tt);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree,
|
|
|
|
struct json_object **json)
|
2018-07-26 22:53:08 +02:00
|
|
|
{
|
|
|
|
const char *tree_id_text = NULL;
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!spftree || !isis_vertex_queue_count(&spftree->paths))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (spftree->tree_id) {
|
2018-07-26 22:53:08 +02:00
|
|
|
case SPFTREE_IPV4:
|
|
|
|
tree_id_text = "that speak IP";
|
|
|
|
break;
|
|
|
|
case SPFTREE_IPV6:
|
|
|
|
tree_id_text = "that speak IPv6";
|
|
|
|
break;
|
|
|
|
case SPFTREE_DSTSRC:
|
|
|
|
tree_id_text = "that support IPv6 dst-src routing";
|
|
|
|
break;
|
|
|
|
case SPFTREE_COUNT:
|
|
|
|
assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
if (!json)
|
|
|
|
vty_out(vty, "IS-IS paths to level-%d routers %s\n",
|
|
|
|
spftree->level, tree_id_text);
|
|
|
|
|
|
|
|
isis_print_paths(vty, &spftree->paths, spftree->sysid, json);
|
|
|
|
if (!json)
|
|
|
|
vty_out(vty, "\n");
|
2018-07-26 22:53:08 +02:00
|
|
|
}
|
|
|
|
|
2020-07-13 14:37:59 +02:00
|
|
|
static void show_isis_topology_common(struct vty *vty, int levels,
|
2024-06-14 08:57:16 +02:00
|
|
|
struct isis *isis, uint8_t algo,
|
|
|
|
json_object **json)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
struct isis_flex_algo_data *fa_data;
|
|
|
|
struct flex_algo *fa;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
struct isis_spftree *spftree;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct listnode *node;
|
|
|
|
struct isis_area *area;
|
2024-06-14 08:57:16 +02:00
|
|
|
json_object *json_level = NULL, *jstr = NULL, *json_val;
|
|
|
|
char key[18];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (!isis->area_list || isis->area_list->count == 0)
|
2020-07-13 14:37:59 +02:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-06-14 08:57:16 +02:00
|
|
|
if (json)
|
|
|
|
*json = json_object_new_object();
|
|
|
|
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
/*
|
|
|
|
* The shapes of the flex algo spftree 2-dimensional array
|
|
|
|
* and the area spftree 2-dimensional array are not guaranteed
|
|
|
|
* to be identical.
|
|
|
|
*/
|
|
|
|
fa = NULL;
|
|
|
|
if (flex_algo_id_valid(algo)) {
|
|
|
|
fa = flex_algo_lookup(area->flex_algos, algo);
|
|
|
|
if (!fa)
|
|
|
|
continue;
|
|
|
|
fa_data = (struct isis_flex_algo_data *)fa->data;
|
|
|
|
} else
|
|
|
|
fa_data = NULL;
|
2024-05-22 13:30:05 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2022-09-06 17:06:55 +02:00
|
|
|
|
2024-06-14 08:57:16 +02:00
|
|
|
if (json) {
|
|
|
|
jstr = json_object_new_string(
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
|
|
|
json_object_object_add(*json, "area", jstr);
|
|
|
|
json_object_int_add(*json, "algorithm", algo);
|
|
|
|
} else {
|
|
|
|
vty_out(vty, "Area %s:",
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
2024-05-07 03:08:05 +02:00
|
|
|
|
2024-05-22 13:30:05 +02:00
|
|
|
#ifndef FABRICD
|
2024-06-14 08:57:16 +02:00
|
|
|
if (algo != SR_ALGORITHM_SPF)
|
|
|
|
vty_out(vty, " Algorithm %hhu\n", algo);
|
|
|
|
else
|
2022-09-06 17:06:55 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2024-06-14 08:57:16 +02:00
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
|
2017-04-27 12:54:21 +02:00
|
|
|
if ((level & levels) == 0)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-06-14 08:57:16 +02:00
|
|
|
if (json) {
|
|
|
|
json_level = json_object_new_object();
|
|
|
|
jstr = json_object_new_string(
|
|
|
|
area->area_tag ? area->area_tag
|
|
|
|
: "null");
|
|
|
|
json_object_object_add(json_level, "area", jstr);
|
|
|
|
}
|
|
|
|
|
2018-07-26 22:53:08 +02:00
|
|
|
if (area->ip_circuits > 0) {
|
2024-06-14 08:57:16 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree = fa_data->spftree[SPFTREE_IPV4]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_IPV4]
|
|
|
|
[level - 1];
|
|
|
|
|
2024-06-14 08:57:16 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv4-paths",
|
|
|
|
json_val);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2018-07-26 22:53:08 +02:00
|
|
|
if (area->ipv6_circuits > 0) {
|
2024-06-14 08:57:16 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree = fa_data->spftree[SPFTREE_IPV6]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_IPV6]
|
|
|
|
[level - 1];
|
2024-06-14 08:57:16 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv6-paths",
|
|
|
|
json_val);
|
|
|
|
}
|
2018-07-26 22:53:08 +02:00
|
|
|
}
|
|
|
|
if (isis_area_ipv6_dstsrc_enabled(area)) {
|
2024-06-14 08:57:16 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree =
|
|
|
|
fa_data->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1];
|
2024-06-14 08:57:16 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv6-dstsrc-paths",
|
|
|
|
json_val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json) {
|
|
|
|
snprintf(key, sizeof(key), "level-%d", level);
|
|
|
|
json_object_object_add(*json, key, json_level);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2018-04-02 18:39:46 +02:00
|
|
|
if (fabricd_spftree(area)) {
|
2024-06-14 08:57:16 +02:00
|
|
|
json_val = NULL;
|
|
|
|
|
2018-04-02 18:39:46 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"IS-IS paths to level-2 routers with hop-by-hop metric\n");
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
isis_print_paths(vty, &fabricd_spftree(area)->paths,
|
2024-06-14 08:57:16 +02:00
|
|
|
isis->sysid, json ? &json_val : NULL);
|
|
|
|
if (json && json_val)
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"fabricd-paths",
|
|
|
|
json_val);
|
|
|
|
else
|
|
|
|
vty_out(vty, "\n");
|
2018-04-02 18:39:46 +02:00
|
|
|
}
|
2024-06-14 08:57:16 +02:00
|
|
|
if (!json)
|
|
|
|
vty_out(vty, "\n");
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2020-07-13 14:37:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN(show_isis_topology, show_isis_topology_cmd,
|
|
|
|
"show " PROTO_NAME
|
|
|
|
" [vrf <NAME|all>] topology"
|
|
|
|
#ifndef FABRICD
|
|
|
|
" [<level-1|level-2>]"
|
2022-12-15 09:28:19 +01:00
|
|
|
" [algorithm [(128-255)]]"
|
2022-09-06 17:06:55 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2024-06-14 08:57:16 +02:00
|
|
|
" [json$uj]"
|
2020-07-13 14:37:59 +02:00
|
|
|
,
|
|
|
|
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
|
|
|
|
"All VRFs\n"
|
|
|
|
"IS-IS paths to Intermediate Systems\n"
|
|
|
|
#ifndef FABRICD
|
|
|
|
"Paths to all level-1 routers in the area\n"
|
|
|
|
"Paths to all level-2 routers in the domain\n"
|
2022-09-06 17:06:55 +02:00
|
|
|
"Show Flex-algo routes\n"
|
|
|
|
"Algorithm number\n"
|
|
|
|
#endif /* ifndef FABRICD */
|
2024-06-14 08:57:16 +02:00
|
|
|
JSON_STR
|
2020-07-13 14:37:59 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
int levels = ISIS_LEVELS;
|
2020-08-21 02:44:27 +02:00
|
|
|
struct listnode *node;
|
2020-07-13 14:37:59 +02:00
|
|
|
struct isis *isis = NULL;
|
|
|
|
const char *vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
bool all_vrf = false;
|
2022-12-15 09:28:19 +01:00
|
|
|
bool all_algorithm = false;
|
2020-07-13 14:37:59 +02:00
|
|
|
int idx_vrf = 0;
|
2022-12-15 09:28:19 +01:00
|
|
|
uint16_t algorithm = SR_ALGORITHM_SPF;
|
2024-06-14 08:57:16 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
|
|
|
json_object *json = NULL, *json_vrf = NULL;
|
2022-12-15 09:28:19 +01:00
|
|
|
|
2022-09-06 17:06:55 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
int idx = 0;
|
2020-07-13 14:37:59 +02:00
|
|
|
|
2022-09-06 17:06:55 +02:00
|
|
|
levels = ISIS_LEVEL1 | ISIS_LEVEL2;
|
|
|
|
if (argv_find(argv, argc, "level-1", &idx))
|
|
|
|
levels = ISIS_LEVEL1;
|
|
|
|
if (argv_find(argv, argc, "level-2", &idx))
|
|
|
|
levels = ISIS_LEVEL2;
|
2022-12-15 09:28:19 +01:00
|
|
|
if (argv_find(argv, argc, "algorithm", &idx)) {
|
|
|
|
if (argv_find(argv, argc, "(128-255)", &idx))
|
|
|
|
algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10);
|
|
|
|
else
|
|
|
|
all_algorithm = true;
|
|
|
|
}
|
2022-09-06 17:06:55 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2020-07-13 14:37:59 +02:00
|
|
|
|
|
|
|
if (!im) {
|
|
|
|
vty_out(vty, "IS-IS Routing Process not enabled\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
|
|
|
|
|
2024-06-14 08:57:16 +02:00
|
|
|
if (uj)
|
|
|
|
json = json_object_new_array();
|
|
|
|
|
2024-05-04 16:56:21 +02:00
|
|
|
if (all_vrf) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
|
|
|
|
if (all_algorithm) {
|
|
|
|
for (algorithm = SR_ALGORITHM_FLEX_MIN;
|
|
|
|
algorithm <= SR_ALGORITHM_FLEX_MAX;
|
|
|
|
algorithm++)
|
2024-06-14 08:57:16 +02:00
|
|
|
show_isis_topology_common(vty, levels,
|
|
|
|
isis,
|
|
|
|
(uint8_t)algorithm,
|
|
|
|
uj ? &json_vrf
|
|
|
|
: NULL);
|
2024-05-04 16:56:21 +02:00
|
|
|
} else {
|
2022-12-15 09:28:19 +01:00
|
|
|
show_isis_topology_common(vty, levels, isis,
|
2024-06-14 08:57:16 +02:00
|
|
|
(uint8_t)algorithm,
|
|
|
|
uj ? &json_vrf : NULL);
|
|
|
|
}
|
|
|
|
if (uj) {
|
|
|
|
json_object_object_add(json_vrf, "vrf_id",
|
|
|
|
json_object_new_int(
|
|
|
|
isis->vrf_id));
|
|
|
|
json_object_array_add(json, json_vrf);
|
2022-12-15 09:28:19 +01:00
|
|
|
}
|
2024-05-04 16:56:21 +02:00
|
|
|
}
|
2024-06-14 08:57:16 +02:00
|
|
|
goto out;
|
2024-05-04 16:56:21 +02:00
|
|
|
}
|
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis == NULL)
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
if (all_algorithm) {
|
|
|
|
for (algorithm = SR_ALGORITHM_FLEX_MIN;
|
|
|
|
algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) {
|
2022-12-15 09:28:19 +01:00
|
|
|
show_isis_topology_common(vty, levels, isis,
|
2024-06-14 08:57:16 +02:00
|
|
|
(uint8_t)algorithm,
|
|
|
|
uj ? &json_vrf : NULL);
|
2024-05-04 16:56:21 +02:00
|
|
|
}
|
|
|
|
} else
|
2024-06-14 08:57:16 +02:00
|
|
|
show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm,
|
|
|
|
uj ? &json_vrf : NULL);
|
|
|
|
if (uj) {
|
|
|
|
json_object_object_add(json_vrf, "vrf_id",
|
|
|
|
json_object_new_int(isis->vrf_id));
|
|
|
|
json_object_array_add(json, json_vrf);
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
if (uj) {
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string_ext(json,
|
|
|
|
JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
|
|
|
}
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return CMD_SUCCESS;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2022-12-12 16:12:41 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
static void show_isis_flex_algo_display_eag(struct vty *vty, char *buf,
|
|
|
|
int indent,
|
|
|
|
struct admin_group *admin_group)
|
|
|
|
{
|
|
|
|
if (admin_group_zero(admin_group))
|
|
|
|
vty_out(vty, "not-set\n");
|
|
|
|
else {
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
admin_group_string(buf, ADMIN_GROUP_PRINT_MAX_SIZE,
|
|
|
|
indent, admin_group));
|
|
|
|
admin_group_print(buf, indent, admin_group);
|
|
|
|
if (buf[0] != '\0')
|
|
|
|
vty_out(vty, " Bit positions: %s\n", buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_isis_flex_algo_common(struct vty *vty, struct isis *isis,
|
|
|
|
uint8_t algorithm)
|
|
|
|
{
|
|
|
|
struct isis_router_cap_fad *router_fad;
|
|
|
|
char buf[ADMIN_GROUP_PRINT_MAX_SIZE];
|
|
|
|
struct admin_group *admin_group;
|
|
|
|
struct isis_area *area;
|
|
|
|
struct listnode *node;
|
|
|
|
struct flex_algo *fa;
|
|
|
|
int indent, algo;
|
|
|
|
bool fad_identical, fad_supported;
|
|
|
|
|
|
|
|
if (!isis->area_list || isis->area_list->count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
|
|
|
/*
|
|
|
|
* The shapes of the flex algo spftree 2-dimensional array
|
|
|
|
* and the area spftree 2-dimensional array are not guaranteed
|
|
|
|
* to be identical.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (algo = 0; algo < SR_ALGORITHM_COUNT; algo++) {
|
|
|
|
if (algorithm != SR_ALGORITHM_UNSET &&
|
|
|
|
algorithm != algo)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fa = flex_algo_lookup(area->flex_algos, algo);
|
|
|
|
if (!fa)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vty_out(vty, "Area %s:",
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
|
|
|
|
|
|
|
vty_out(vty, " Algorithm %d\n", algo);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
|
|
|
vty_out(vty, " Enabled Data-Planes:");
|
|
|
|
if (fa->dataplanes == 0) {
|
|
|
|
vty_out(vty, " None\n\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (CHECK_FLAG(fa->dataplanes, FLEX_ALGO_SR_MPLS))
|
|
|
|
vty_out(vty, " SR-MPLS");
|
|
|
|
if (CHECK_FLAG(fa->dataplanes, FLEX_ALGO_SRV6))
|
|
|
|
vty_out(vty, " SRv6");
|
|
|
|
if (CHECK_FLAG(fa->dataplanes, FLEX_ALGO_IP))
|
|
|
|
vty_out(vty, " IP");
|
|
|
|
vty_out(vty, "\n\n");
|
|
|
|
|
|
|
|
|
|
|
|
router_fad = isis_flex_algo_elected(algo, area);
|
|
|
|
vty_out(vty,
|
|
|
|
" Elected and running Flexible-Algorithm Definition:\n");
|
|
|
|
if (router_fad)
|
|
|
|
vty_out(vty, " Source: %pSY\n",
|
|
|
|
router_fad->sysid);
|
|
|
|
else
|
|
|
|
vty_out(vty, " Source: Not found\n");
|
|
|
|
|
|
|
|
if (!router_fad) {
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fad_identical =
|
|
|
|
flex_algo_definition_cmp(fa, &router_fad->fad);
|
|
|
|
fad_supported =
|
|
|
|
isis_flex_algo_supported(&router_fad->fad);
|
|
|
|
vty_out(vty, " Priority: %d\n",
|
|
|
|
router_fad->fad.priority);
|
|
|
|
vty_out(vty, " Equal to local: %s\n",
|
|
|
|
fad_identical ? "yes" : "no");
|
|
|
|
vty_out(vty, " Local state: %s\n",
|
|
|
|
fad_supported
|
|
|
|
? "enabled"
|
|
|
|
: "disabled (unsupported definition)");
|
|
|
|
vty_out(vty, " Calculation type: ");
|
|
|
|
if (router_fad->fad.calc_type == 0)
|
|
|
|
vty_out(vty, "spf\n");
|
|
|
|
else
|
|
|
|
vty_out(vty, "%d\n", router_fad->fad.calc_type);
|
|
|
|
vty_out(vty, " Metric type: %s\n",
|
|
|
|
flex_algo_metric_type_print(
|
|
|
|
buf, sizeof(buf),
|
|
|
|
router_fad->fad.metric_type));
|
|
|
|
vty_out(vty, " Prefix-metric: %s\n",
|
|
|
|
CHECK_FLAG(router_fad->fad.flags, FAD_FLAG_M)
|
|
|
|
? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
if (router_fad->fad.flags != 0 &&
|
|
|
|
router_fad->fad.flags != FAD_FLAG_M)
|
|
|
|
vty_out(vty, " Flags: 0x%x\n",
|
|
|
|
router_fad->fad.flags);
|
|
|
|
vty_out(vty, " Exclude SRLG: %s\n",
|
|
|
|
router_fad->fad.exclude_srlg ? "enabled"
|
|
|
|
: "disabled");
|
|
|
|
|
|
|
|
admin_group = &router_fad->fad.admin_group_exclude_any;
|
|
|
|
indent = vty_out(vty, " Exclude-any admin-group: ");
|
|
|
|
show_isis_flex_algo_display_eag(vty, buf, indent,
|
|
|
|
admin_group);
|
|
|
|
|
|
|
|
admin_group = &router_fad->fad.admin_group_include_all;
|
|
|
|
indent = vty_out(vty, " Include-all admin-group: ");
|
|
|
|
show_isis_flex_algo_display_eag(vty, buf, indent,
|
|
|
|
admin_group);
|
|
|
|
|
|
|
|
admin_group = &router_fad->fad.admin_group_include_any;
|
|
|
|
indent = vty_out(vty, " Include-any admin-group: ");
|
|
|
|
show_isis_flex_algo_display_eag(vty, buf, indent,
|
|
|
|
admin_group);
|
|
|
|
|
|
|
|
if (router_fad->fad.unsupported_subtlv)
|
|
|
|
vty_out(vty,
|
|
|
|
" Unsupported sub-TLV: Present (see logs)");
|
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN(show_isis_flex_algo, show_isis_flex_algo_cmd,
|
|
|
|
"show " PROTO_NAME
|
|
|
|
" [vrf <NAME|all>] flex-algo"
|
|
|
|
" [(128-255)]",
|
|
|
|
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
|
|
|
|
"All VRFs\n"
|
|
|
|
"IS-IS Flex-algo information\n"
|
|
|
|
"Algorithm number\n")
|
|
|
|
{
|
|
|
|
struct isis *isis;
|
|
|
|
struct listnode *node;
|
|
|
|
const char *vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
bool all_vrf = false;
|
|
|
|
int idx = 0;
|
|
|
|
int idx_vrf = 0;
|
|
|
|
uint8_t flex_algo;
|
|
|
|
|
|
|
|
if (!im) {
|
|
|
|
vty_out(vty, "IS-IS Routing Process not enabled\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argv_find(argv, argc, "flex-algo", &idx) && (idx + 1) < argc)
|
|
|
|
flex_algo = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10);
|
|
|
|
else
|
|
|
|
flex_algo = SR_ALGORITHM_UNSET;
|
|
|
|
|
|
|
|
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
|
|
|
|
|
2024-05-04 16:56:21 +02:00
|
|
|
if (all_vrf) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
|
2022-12-12 16:12:41 +01:00
|
|
|
show_isis_flex_algo_common(vty, isis, flex_algo);
|
2024-05-04 16:56:21 +02:00
|
|
|
return CMD_SUCCESS;
|
2022-12-12 16:12:41 +01:00
|
|
|
}
|
2024-05-04 16:56:21 +02:00
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis != NULL)
|
|
|
|
show_isis_flex_algo_common(vty, isis, flex_algo);
|
2022-12-12 16:12:41 +01:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
|
|
|
|
struct isis_route_info *rinfo, bool prefix_sid,
|
2022-09-02 16:33:52 +02:00
|
|
|
bool no_adjacencies, bool json)
|
2020-09-20 07:39:28 +02:00
|
|
|
{
|
|
|
|
struct isis_nexthop *nexthop;
|
|
|
|
struct listnode *node;
|
|
|
|
bool first = true;
|
|
|
|
char buf_prefix[BUFSIZ];
|
|
|
|
|
|
|
|
(void)prefix2str(prefix, buf_prefix, sizeof(buf_prefix));
|
2022-09-02 16:33:43 +02:00
|
|
|
for (int alg = 0; alg < SR_ALGORITHM_COUNT; alg++) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(rinfo->sr_algo[alg].nexthops, node,
|
|
|
|
nexthop)) {
|
2022-09-12 14:57:51 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
char buf_iface[BUFSIZ];
|
|
|
|
char buf_nhop[BUFSIZ];
|
|
|
|
|
|
|
|
if (!no_adjacencies) {
|
2022-09-02 16:33:43 +02:00
|
|
|
inet_ntop(nexthop->family, &nexthop->ip,
|
|
|
|
buf_nhop, sizeof(buf_nhop));
|
|
|
|
ifp = if_lookup_by_index(nexthop->ifindex,
|
|
|
|
VRF_DEFAULT);
|
2022-09-12 14:57:51 +02:00
|
|
|
if (ifp)
|
|
|
|
strlcpy(buf_iface, ifp->name,
|
|
|
|
sizeof(buf_iface));
|
|
|
|
else
|
|
|
|
snprintf(buf_iface, sizeof(buf_iface),
|
2022-09-02 16:33:43 +02:00
|
|
|
"ifindex %u",
|
|
|
|
nexthop->ifindex);
|
2020-09-20 07:39:28 +02:00
|
|
|
} else {
|
2022-09-02 16:33:43 +02:00
|
|
|
strlcpy(buf_nhop,
|
|
|
|
print_sys_hostname(nexthop->sysid),
|
2022-09-12 14:57:51 +02:00
|
|
|
sizeof(buf_nhop));
|
|
|
|
strlcpy(buf_iface, "-", sizeof(buf_iface));
|
2020-09-20 07:39:28 +02:00
|
|
|
}
|
|
|
|
|
2022-09-12 14:57:51 +02:00
|
|
|
if (prefix_sid) {
|
|
|
|
char buf_sid[BUFSIZ] = {};
|
|
|
|
char buf_lblop[BUFSIZ] = {};
|
|
|
|
|
2022-09-02 16:33:43 +02:00
|
|
|
if (rinfo->sr_algo[alg].present) {
|
2022-09-12 14:57:51 +02:00
|
|
|
snprintf(buf_sid, sizeof(buf_sid), "%u",
|
2022-09-02 16:33:43 +02:00
|
|
|
rinfo->sr_algo[alg].sid.value);
|
|
|
|
sr_op2str(buf_lblop, sizeof(buf_lblop),
|
|
|
|
rinfo->sr_algo[alg].label,
|
|
|
|
nexthop->sr.label);
|
|
|
|
} else if (alg == SR_ALGORITHM_SPF) {
|
2022-09-12 14:57:51 +02:00
|
|
|
strlcpy(buf_sid, "-", sizeof(buf_sid));
|
2022-09-02 16:33:43 +02:00
|
|
|
strlcpy(buf_lblop, "-",
|
|
|
|
sizeof(buf_lblop));
|
|
|
|
} else {
|
|
|
|
continue;
|
2020-09-20 07:39:28 +02:00
|
|
|
}
|
2022-09-12 14:57:51 +02:00
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (first || json) {
|
2022-09-02 16:33:43 +02:00
|
|
|
ttable_add_row(tt,
|
|
|
|
"%s|%u|%s|%s|%s|%s|%d",
|
|
|
|
buf_prefix, rinfo->cost,
|
|
|
|
buf_iface, buf_nhop,
|
|
|
|
buf_sid, buf_lblop, alg);
|
2022-09-12 14:57:51 +02:00
|
|
|
first = false;
|
|
|
|
} else
|
2022-09-02 16:33:43 +02:00
|
|
|
ttable_add_row(tt, "||%s|%s|%s|%s|%d",
|
|
|
|
buf_iface, buf_nhop,
|
|
|
|
buf_sid, buf_lblop, alg);
|
2022-09-12 14:57:51 +02:00
|
|
|
} else {
|
|
|
|
char buf_labels[BUFSIZ] = {};
|
|
|
|
|
|
|
|
if (nexthop->label_stack) {
|
|
|
|
for (int i = 0;
|
2022-09-02 16:33:43 +02:00
|
|
|
i <
|
|
|
|
nexthop->label_stack->num_labels;
|
|
|
|
i++) {
|
2022-09-12 14:57:51 +02:00
|
|
|
char buf_label[BUFSIZ];
|
|
|
|
|
2022-09-02 16:33:43 +02:00
|
|
|
label2str(nexthop->label_stack
|
|
|
|
->label[i],
|
|
|
|
0, buf_label,
|
|
|
|
sizeof(buf_label));
|
2022-09-12 14:57:51 +02:00
|
|
|
if (i != 0)
|
|
|
|
strlcat(buf_labels, "/",
|
|
|
|
sizeof(buf_labels));
|
|
|
|
strlcat(buf_labels, buf_label,
|
|
|
|
sizeof(buf_labels));
|
|
|
|
}
|
|
|
|
} else if (nexthop->sr.present)
|
2022-09-02 16:33:43 +02:00
|
|
|
label2str(nexthop->sr.label, 0,
|
|
|
|
buf_labels,
|
2022-09-12 14:57:51 +02:00
|
|
|
sizeof(buf_labels));
|
|
|
|
else
|
2022-09-02 16:33:43 +02:00
|
|
|
strlcpy(buf_labels, "-",
|
|
|
|
sizeof(buf_labels));
|
2022-09-12 14:57:51 +02:00
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (first || json) {
|
2022-09-02 16:33:43 +02:00
|
|
|
ttable_add_row(tt, "%s|%u|%s|%s|%s",
|
|
|
|
buf_prefix, rinfo->cost,
|
|
|
|
buf_iface, buf_nhop,
|
|
|
|
buf_labels);
|
2022-09-12 14:57:51 +02:00
|
|
|
first = false;
|
|
|
|
} else
|
2022-09-02 16:33:43 +02:00
|
|
|
ttable_add_row(tt, "||%s|%s|%s",
|
|
|
|
buf_iface, buf_nhop,
|
|
|
|
buf_labels);
|
2022-09-12 14:57:51 +02:00
|
|
|
}
|
2020-09-20 07:39:28 +02:00
|
|
|
}
|
2022-09-02 16:33:43 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
if (list_isempty(rinfo->nexthops)) {
|
|
|
|
if (prefix_sid) {
|
|
|
|
char buf_sid[BUFSIZ] = {};
|
|
|
|
char buf_lblop[BUFSIZ] = {};
|
|
|
|
|
2021-12-12 10:20:21 +01:00
|
|
|
if (rinfo->sr_algo[SR_ALGORITHM_SPF].present) {
|
2020-09-20 07:39:28 +02:00
|
|
|
snprintf(buf_sid, sizeof(buf_sid), "%u",
|
2021-12-12 10:20:21 +01:00
|
|
|
rinfo->sr_algo[SR_ALGORITHM_SPF]
|
|
|
|
.sid.value);
|
|
|
|
sr_op2str(
|
|
|
|
buf_lblop, sizeof(buf_lblop),
|
|
|
|
rinfo->sr_algo[SR_ALGORITHM_SPF].label,
|
|
|
|
MPLS_LABEL_IMPLICIT_NULL);
|
2020-09-20 07:39:28 +02:00
|
|
|
} else {
|
|
|
|
strlcpy(buf_sid, "-", sizeof(buf_sid));
|
|
|
|
strlcpy(buf_lblop, "-", sizeof(buf_lblop));
|
|
|
|
}
|
|
|
|
|
|
|
|
ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", buf_prefix,
|
|
|
|
rinfo->cost, "-", "-", buf_sid,
|
|
|
|
buf_lblop);
|
|
|
|
} else
|
|
|
|
ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
|
|
|
|
rinfo->cost, "-", "-", "-");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
|
2022-09-02 16:33:52 +02:00
|
|
|
struct json_object **json, bool prefix_sid, bool backup)
|
2020-08-23 04:24:06 +02:00
|
|
|
{
|
2020-08-21 00:55:42 +02:00
|
|
|
struct route_table *route_table;
|
2020-08-23 04:24:06 +02:00
|
|
|
struct ttable *tt;
|
|
|
|
struct route_node *rn;
|
2020-09-20 07:39:28 +02:00
|
|
|
bool no_adjacencies = false;
|
2020-08-23 04:24:06 +02:00
|
|
|
const char *tree_id_text = NULL;
|
|
|
|
|
|
|
|
if (!spftree)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (spftree->tree_id) {
|
|
|
|
case SPFTREE_IPV4:
|
|
|
|
tree_id_text = "IPv4";
|
|
|
|
break;
|
|
|
|
case SPFTREE_IPV6:
|
|
|
|
tree_id_text = "IPv6";
|
|
|
|
break;
|
|
|
|
case SPFTREE_DSTSRC:
|
|
|
|
tree_id_text = "IPv6 (dst-src routing)";
|
|
|
|
break;
|
|
|
|
case SPFTREE_COUNT:
|
|
|
|
assert(!"isis_print_routes shouldn't be called with SPFTREE_COUNT as type");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json == NULL)
|
|
|
|
vty_out(vty, "IS-IS %s %s routing table:\n\n",
|
|
|
|
circuit_t2string(spftree->level), tree_id_text);
|
2020-08-23 04:24:06 +02:00
|
|
|
|
|
|
|
/* Prepare table. */
|
|
|
|
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
|
2020-09-20 07:39:28 +02:00
|
|
|
if (prefix_sid)
|
2022-09-02 16:33:43 +02:00
|
|
|
ttable_add_row(
|
|
|
|
tt,
|
|
|
|
"Prefix|Metric|Interface|Nexthop|SID|Label Op.|Algo");
|
2020-09-20 07:39:28 +02:00
|
|
|
else
|
|
|
|
ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
|
2020-08-23 04:24:06 +02:00
|
|
|
tt->style.cell.rpad = 2;
|
|
|
|
tt->style.corner = '+';
|
|
|
|
ttable_restyle(tt);
|
|
|
|
ttable_rowseps(tt, 0, BOTTOM, true, '-');
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
|
|
|
no_adjacencies = true;
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
route_table =
|
|
|
|
(backup) ? spftree->route_table_backup : spftree->route_table;
|
|
|
|
for (rn = route_top(route_table); rn; rn = route_next(rn)) {
|
2020-08-23 04:24:06 +02:00
|
|
|
struct isis_route_info *rinfo;
|
|
|
|
|
|
|
|
rinfo = rn->info;
|
|
|
|
if (!rinfo)
|
|
|
|
continue;
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
isis_print_route(tt, &rn->p, rinfo, prefix_sid, no_adjacencies,
|
|
|
|
json != NULL);
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Dump the generated table. */
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json == NULL && tt->nrows > 1) {
|
2020-08-23 04:24:06 +02:00
|
|
|
char *table;
|
|
|
|
|
|
|
|
table = ttable_dump(tt, "\n");
|
|
|
|
vty_out(vty, "%s\n", table);
|
|
|
|
XFREE(MTYPE_TMP, table);
|
2022-09-02 16:33:52 +02:00
|
|
|
} else if (json) {
|
2024-06-19 16:10:48 +02:00
|
|
|
*json = ttable_json_with_json_text(
|
|
|
|
tt, prefix_sid ? "sdssdsdd" : "sdsss",
|
|
|
|
prefix_sid
|
|
|
|
? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm"
|
|
|
|
: "prefix|metric|interface|nextHop|label(s)");
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
ttable_del(tt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_isis_route_common(struct vty *vty, int levels,
|
2020-09-20 07:39:28 +02:00
|
|
|
struct isis *isis, bool prefix_sid,
|
2022-09-06 17:08:57 +02:00
|
|
|
bool backup, uint8_t algo,
|
|
|
|
json_object **json)
|
2020-08-23 04:24:06 +02:00
|
|
|
{
|
2022-09-02 16:33:52 +02:00
|
|
|
json_object *json_level = NULL, *jstr = NULL, *json_val;
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
struct isis_flex_algo_data *fa_data;
|
|
|
|
struct flex_algo *fa;
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
struct isis_spftree *spftree;
|
2020-08-23 04:24:06 +02:00
|
|
|
struct listnode *node;
|
|
|
|
struct isis_area *area;
|
2024-04-13 21:40:46 +02:00
|
|
|
char key[18];
|
2020-08-23 04:24:06 +02:00
|
|
|
|
|
|
|
if (!isis->area_list || isis->area_list->count == 0)
|
|
|
|
return;
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json)
|
|
|
|
*json = json_object_new_object();
|
|
|
|
|
2020-08-23 04:24:06 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
/*
|
|
|
|
* The shapes of the flex algo spftree 2-dimensional array
|
|
|
|
* and the area spftree 2-dimensional array are not guaranteed
|
|
|
|
* to be identical.
|
|
|
|
*/
|
|
|
|
fa = NULL;
|
|
|
|
if (flex_algo_id_valid(algo)) {
|
|
|
|
fa = flex_algo_lookup(area->flex_algos, algo);
|
|
|
|
if (!fa)
|
|
|
|
continue;
|
|
|
|
fa_data = (struct isis_flex_algo_data *)fa->data;
|
|
|
|
} else {
|
|
|
|
fa_data = NULL;
|
|
|
|
}
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json) {
|
|
|
|
jstr = json_object_new_string(
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
|
|
|
json_object_object_add(*json, "area", jstr);
|
2022-12-19 15:39:00 +01:00
|
|
|
json_object_int_add(*json, "algorithm", algo);
|
2022-09-02 16:33:52 +02:00
|
|
|
} else {
|
2022-09-06 17:08:57 +02:00
|
|
|
vty_out(vty, "Area %s:",
|
2022-09-02 16:33:52 +02:00
|
|
|
area->area_tag ? area->area_tag : "null");
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (algo != SR_ALGORITHM_SPF)
|
|
|
|
vty_out(vty, " Algorithm %hhu\n", algo);
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
vty_out(vty, "\n");
|
2022-09-02 16:33:52 +02:00
|
|
|
}
|
2020-08-23 04:24:06 +02:00
|
|
|
|
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
|
|
|
|
if ((level & levels) == 0)
|
|
|
|
continue;
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json) {
|
|
|
|
json_level = json_object_new_object();
|
|
|
|
jstr = json_object_new_string(
|
|
|
|
area->area_tag ? area->area_tag
|
|
|
|
: "null");
|
|
|
|
json_object_object_add(json_level, "area",
|
|
|
|
jstr);
|
|
|
|
}
|
|
|
|
|
2020-08-23 04:24:06 +02:00
|
|
|
if (area->ip_circuits > 0) {
|
2022-09-02 16:33:52 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree = fa_data->spftree[SPFTREE_IPV4]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_IPV4]
|
|
|
|
[level - 1];
|
|
|
|
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv4-paths",
|
|
|
|
json_val);
|
|
|
|
json_val = NULL;
|
|
|
|
}
|
2022-09-06 17:08:57 +02:00
|
|
|
|
|
|
|
isis_print_routes(vty, spftree,
|
|
|
|
json ? &json_val : NULL,
|
|
|
|
prefix_sid, backup);
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(
|
|
|
|
json_level, "ipv4", json_val);
|
|
|
|
}
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
if (area->ipv6_circuits > 0) {
|
2022-09-02 16:33:52 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree = fa_data->spftree[SPFTREE_IPV6]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_IPV6]
|
|
|
|
[level - 1];
|
|
|
|
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv6-paths",
|
|
|
|
json_val);
|
|
|
|
json_val = NULL;
|
|
|
|
}
|
2022-09-06 17:08:57 +02:00
|
|
|
|
|
|
|
isis_print_routes(vty, spftree,
|
|
|
|
json ? &json_val : NULL,
|
|
|
|
prefix_sid, backup);
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(
|
|
|
|
json_level, "ipv6", json_val);
|
|
|
|
}
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
if (isis_area_ipv6_dstsrc_enabled(area)) {
|
2022-09-02 16:33:52 +02:00
|
|
|
json_val = NULL;
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
|
|
|
if (fa_data)
|
|
|
|
spftree =
|
|
|
|
fa_data->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1];
|
|
|
|
else
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
spftree = area->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1];
|
|
|
|
|
isisd: add json support to display spf paths in 'show isis route'
The 'show isis route json' command never displays the list of
paths. Add the json support for this sub-part.
> # show isis route json
> [..]
> "ipv6-paths":[
> {
> "Vertex":"rt1",
> "Type":"",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":""
> },
> {
> "Vertex":"2001:db8:1000::1\/128",
> "Type":"IP6 internal",
> "Metric":0,
> "Next-Hop":"",
> "Interface":"",
> "Parent":"rt1(4)"
> },
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2024-06-06 17:08:56 +02:00
|
|
|
isis_print_spftree(vty, spftree,
|
|
|
|
json ? &json_val : NULL);
|
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv6-dstsrc-paths",
|
|
|
|
json_val);
|
|
|
|
json_val = NULL;
|
|
|
|
}
|
2022-09-06 17:08:57 +02:00
|
|
|
isis_print_routes(vty, spftree,
|
2022-09-02 16:33:52 +02:00
|
|
|
json ? &json_val : NULL,
|
2020-09-20 07:39:28 +02:00
|
|
|
prefix_sid, backup);
|
2022-09-02 16:33:52 +02:00
|
|
|
if (json && json_val) {
|
|
|
|
json_object_object_add(json_level,
|
|
|
|
"ipv6-dstsrc",
|
|
|
|
json_val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (json) {
|
|
|
|
snprintf(key, sizeof(key), "level-%d", level);
|
|
|
|
json_object_object_add(*json, key, json_level);
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-15 09:26:45 +01:00
|
|
|
static void show_isis_route_all_algos(struct vty *vty, int levels,
|
|
|
|
struct isis *isis, bool prefix_sid,
|
|
|
|
bool backup, json_object **json)
|
|
|
|
{
|
|
|
|
uint16_t algo;
|
|
|
|
|
|
|
|
json_object *json_algo = NULL, *json_algos = NULL;
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
*json = json_object_new_object();
|
|
|
|
json_algos = json_object_new_array();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (algo = SR_ALGORITHM_FLEX_MIN; algo <= SR_ALGORITHM_FLEX_MAX;
|
|
|
|
algo++) {
|
|
|
|
show_isis_route_common(vty, levels, isis, prefix_sid, backup,
|
|
|
|
(uint8_t)algo, json ? &json_algo : NULL);
|
|
|
|
if (!json)
|
|
|
|
continue;
|
|
|
|
if (json_object_object_length(json_algo) == 0) {
|
|
|
|
json_object_free(json_algo);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
json_object_object_add(json_algo, "algorithm",
|
|
|
|
json_object_new_int(algo));
|
|
|
|
json_object_array_add(json_algos, json_algo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json)
|
|
|
|
json_object_object_add(*json, "algorithms", json_algos);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-23 04:24:06 +02:00
|
|
|
DEFUN(show_isis_route, show_isis_route_cmd,
|
|
|
|
"show " PROTO_NAME
|
|
|
|
" [vrf <NAME|all>] route"
|
|
|
|
#ifndef FABRICD
|
|
|
|
" [<level-1|level-2>]"
|
2022-09-06 17:08:57 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2024-06-06 15:18:48 +02:00
|
|
|
" [prefix-sid] [backup]"
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
2022-12-15 09:26:45 +01:00
|
|
|
" [algorithm [(128-255)]]"
|
2022-09-06 17:08:57 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2022-09-02 16:33:52 +02:00
|
|
|
" [json$uj]",
|
2020-08-23 04:24:06 +02:00
|
|
|
SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
|
|
|
|
"IS-IS routing table\n"
|
|
|
|
#ifndef FABRICD
|
|
|
|
"level-1 routes\n"
|
|
|
|
"level-2 routes\n"
|
2022-09-06 17:08:57 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
2020-09-20 07:39:28 +02:00
|
|
|
"Show Prefix-SID information\n"
|
2022-09-06 17:08:57 +02:00
|
|
|
"Show backup routes\n"
|
|
|
|
#ifndef FABRICD
|
|
|
|
"Show Flex-algo routes\n"
|
|
|
|
"Algorithm number\n"
|
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
JSON_STR)
|
2020-08-23 04:24:06 +02:00
|
|
|
{
|
|
|
|
int levels;
|
|
|
|
struct isis *isis;
|
|
|
|
struct listnode *node;
|
|
|
|
const char *vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
bool all_vrf = false;
|
2022-12-15 09:26:45 +01:00
|
|
|
bool all_algorithm = false;
|
2020-09-20 07:39:28 +02:00
|
|
|
bool prefix_sid = false;
|
2020-08-21 00:55:42 +02:00
|
|
|
bool backup = false;
|
2022-09-02 16:33:52 +02:00
|
|
|
bool uj = use_json(argc, argv);
|
2020-08-23 04:24:06 +02:00
|
|
|
int idx = 0;
|
2022-09-02 16:33:52 +02:00
|
|
|
json_object *json = NULL, *json_vrf = NULL;
|
2022-09-06 17:08:57 +02:00
|
|
|
uint8_t algorithm = SR_ALGORITHM_SPF;
|
2020-08-23 04:24:06 +02:00
|
|
|
|
|
|
|
if (argv_find(argv, argc, "level-1", &idx))
|
|
|
|
levels = ISIS_LEVEL1;
|
|
|
|
else if (argv_find(argv, argc, "level-2", &idx))
|
|
|
|
levels = ISIS_LEVEL2;
|
|
|
|
else
|
|
|
|
levels = ISIS_LEVEL1 | ISIS_LEVEL2;
|
|
|
|
|
|
|
|
if (!im) {
|
|
|
|
vty_out(vty, "IS-IS Routing Process not enabled\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
|
|
|
|
|
2020-09-20 07:39:28 +02:00
|
|
|
if (argv_find(argv, argc, "prefix-sid", &idx))
|
|
|
|
prefix_sid = true;
|
2020-08-21 00:55:42 +02:00
|
|
|
if (argv_find(argv, argc, "backup", &idx))
|
|
|
|
backup = true;
|
|
|
|
|
2022-09-06 17:08:57 +02:00
|
|
|
#ifndef FABRICD
|
2022-12-15 09:26:45 +01:00
|
|
|
if (argv_find(argv, argc, "algorithm", &idx)) {
|
|
|
|
if (argv_find(argv, argc, "(128-255)", &idx))
|
2024-05-22 11:30:24 +02:00
|
|
|
algorithm = (uint8_t)strtoul(argv[idx]->arg, NULL, 10);
|
2022-12-15 09:26:45 +01:00
|
|
|
else
|
|
|
|
all_algorithm = true;
|
|
|
|
}
|
2022-09-06 17:08:57 +02:00
|
|
|
#endif /* ifndef FABRICD */
|
|
|
|
|
2022-09-02 16:33:52 +02:00
|
|
|
if (uj)
|
|
|
|
json = json_object_new_array();
|
|
|
|
|
2024-05-04 16:56:21 +02:00
|
|
|
if (all_vrf) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
|
2022-12-15 09:26:45 +01:00
|
|
|
if (all_algorithm)
|
|
|
|
show_isis_route_all_algos(vty, levels, isis,
|
|
|
|
prefix_sid, backup,
|
|
|
|
uj ? &json_vrf : NULL);
|
|
|
|
else
|
|
|
|
show_isis_route_common(vty, levels, isis,
|
|
|
|
prefix_sid, backup,
|
|
|
|
algorithm,
|
|
|
|
uj ? &json_vrf : NULL);
|
2022-09-02 16:33:52 +02:00
|
|
|
if (uj) {
|
2024-05-04 16:56:21 +02:00
|
|
|
json_object_object_add(json_vrf, "vrf_id",
|
|
|
|
json_object_new_int(
|
|
|
|
isis->vrf_id));
|
2022-09-02 16:33:52 +02:00
|
|
|
json_object_array_add(json, json_vrf);
|
|
|
|
}
|
|
|
|
}
|
2024-05-04 16:56:21 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis != NULL) {
|
|
|
|
if (all_algorithm)
|
|
|
|
show_isis_route_all_algos(vty, levels, isis, prefix_sid,
|
|
|
|
backup, uj ? &json_vrf : NULL);
|
|
|
|
else
|
|
|
|
show_isis_route_common(vty, levels, isis, prefix_sid,
|
|
|
|
backup, algorithm,
|
|
|
|
uj ? &json_vrf : NULL);
|
|
|
|
if (uj) {
|
|
|
|
json_object_object_add(json_vrf, "vrf_id",
|
|
|
|
json_object_new_int(isis->vrf_id));
|
|
|
|
json_object_array_add(json, json_vrf);
|
|
|
|
}
|
2022-09-02 16:33:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (uj) {
|
|
|
|
vty_out(vty, "%s\n",
|
|
|
|
json_object_to_json_string_ext(
|
|
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
|
|
json_object_free(json);
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-11-20 23:55:42 +01:00
|
|
|
static void isis_print_frr_summary_line(struct ttable *tt,
|
|
|
|
const char *protection,
|
|
|
|
uint32_t counters[SPF_PREFIX_PRIO_MAX])
|
|
|
|
{
|
|
|
|
uint32_t critical, high, medium, low, total;
|
|
|
|
|
|
|
|
critical = counters[SPF_PREFIX_PRIO_CRITICAL];
|
|
|
|
high = counters[SPF_PREFIX_PRIO_HIGH];
|
|
|
|
medium = counters[SPF_PREFIX_PRIO_MEDIUM];
|
|
|
|
low = counters[SPF_PREFIX_PRIO_LOW];
|
|
|
|
total = critical + high + medium + low;
|
|
|
|
|
|
|
|
ttable_add_row(tt, "%s|%u|%u|%u|%u|%u", protection, critical, high,
|
|
|
|
medium, low, total);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
isis_print_frr_summary_line_coverage(struct ttable *tt, const char *protection,
|
|
|
|
double counters[SPF_PREFIX_PRIO_MAX],
|
|
|
|
double total)
|
|
|
|
{
|
|
|
|
double critical, high, medium, low;
|
|
|
|
|
|
|
|
critical = counters[SPF_PREFIX_PRIO_CRITICAL] * 100;
|
|
|
|
high = counters[SPF_PREFIX_PRIO_HIGH] * 100;
|
|
|
|
medium = counters[SPF_PREFIX_PRIO_MEDIUM] * 100;
|
|
|
|
low = counters[SPF_PREFIX_PRIO_LOW] * 100;
|
|
|
|
total *= 100;
|
|
|
|
|
|
|
|
ttable_add_row(tt, "%s|%.2f%%|%.2f%%|%.2f%%|%.2f%%|%.2f%%", protection,
|
|
|
|
critical, high, medium, low, total);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void isis_print_frr_summary(struct vty *vty,
|
|
|
|
struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
struct ttable *tt;
|
|
|
|
char *table;
|
|
|
|
const char *tree_id_text = NULL;
|
|
|
|
uint32_t protectd[SPF_PREFIX_PRIO_MAX] = {0};
|
|
|
|
uint32_t unprotected[SPF_PREFIX_PRIO_MAX] = {0};
|
|
|
|
double coverage[SPF_PREFIX_PRIO_MAX] = {0};
|
|
|
|
uint32_t protected_total = 0, grand_total = 0;
|
|
|
|
double coverage_total;
|
|
|
|
|
|
|
|
if (!spftree)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (spftree->tree_id) {
|
|
|
|
case SPFTREE_IPV4:
|
|
|
|
tree_id_text = "IPv4";
|
|
|
|
break;
|
|
|
|
case SPFTREE_IPV6:
|
|
|
|
tree_id_text = "IPv6";
|
|
|
|
break;
|
|
|
|
case SPFTREE_DSTSRC:
|
|
|
|
tree_id_text = "IPv6 (dst-src routing)";
|
|
|
|
break;
|
|
|
|
case SPFTREE_COUNT:
|
|
|
|
assert(!"isis_print_frr_summary shouldn't be called with SPFTREE_COUNT as type");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, " IS-IS %s %s Fast ReRoute summary:\n\n",
|
|
|
|
circuit_t2string(spftree->level), tree_id_text);
|
|
|
|
|
|
|
|
/* Prepare table. */
|
|
|
|
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
|
|
|
|
ttable_add_row(
|
|
|
|
tt,
|
|
|
|
"Protection \\ Priority|Critical|High |Medium |Low |Total");
|
|
|
|
tt->style.cell.rpad = 2;
|
|
|
|
tt->style.corner = '+';
|
|
|
|
ttable_restyle(tt);
|
|
|
|
ttable_rowseps(tt, 0, BOTTOM, true, '-');
|
|
|
|
|
|
|
|
/* Compute unprotected and coverage totals. */
|
|
|
|
for (int priority = SPF_PREFIX_PRIO_CRITICAL;
|
|
|
|
priority < SPF_PREFIX_PRIO_MAX; priority++) {
|
|
|
|
uint32_t *lfa = spftree->lfa.protection_counters.lfa;
|
|
|
|
uint32_t *rlfa = spftree->lfa.protection_counters.rlfa;
|
|
|
|
uint32_t *tilfa = spftree->lfa.protection_counters.tilfa;
|
|
|
|
uint32_t *ecmp = spftree->lfa.protection_counters.ecmp;
|
|
|
|
uint32_t *total = spftree->lfa.protection_counters.total;
|
|
|
|
|
|
|
|
protectd[priority] = lfa[priority] + rlfa[priority]
|
|
|
|
+ tilfa[priority] + ecmp[priority];
|
|
|
|
/* Safeguard to protect against possible inconsistencies. */
|
|
|
|
if (protectd[priority] > total[priority])
|
|
|
|
protectd[priority] = total[priority];
|
|
|
|
unprotected[priority] = total[priority] - protectd[priority];
|
|
|
|
protected_total += protectd[priority];
|
|
|
|
grand_total += total[priority];
|
|
|
|
|
|
|
|
if (!total[priority])
|
|
|
|
coverage[priority] = 0;
|
|
|
|
else
|
|
|
|
coverage[priority] =
|
|
|
|
protectd[priority] / (double)total[priority];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!grand_total)
|
|
|
|
coverage_total = 0;
|
|
|
|
else
|
|
|
|
coverage_total = protected_total / (double)grand_total;
|
|
|
|
|
|
|
|
/* Add rows. */
|
|
|
|
isis_print_frr_summary_line(tt, "Classic LFA",
|
|
|
|
spftree->lfa.protection_counters.lfa);
|
|
|
|
isis_print_frr_summary_line(tt, "Remote LFA",
|
|
|
|
spftree->lfa.protection_counters.rlfa);
|
|
|
|
isis_print_frr_summary_line(tt, "Topology Independent LFA",
|
|
|
|
spftree->lfa.protection_counters.tilfa);
|
|
|
|
isis_print_frr_summary_line(tt, "ECMP",
|
|
|
|
spftree->lfa.protection_counters.ecmp);
|
|
|
|
isis_print_frr_summary_line(tt, "Unprotected", unprotected);
|
|
|
|
isis_print_frr_summary_line_coverage(tt, "Protection coverage",
|
|
|
|
coverage, coverage_total);
|
|
|
|
|
|
|
|
/* Dump the generated table. */
|
|
|
|
table = ttable_dump(tt, "\n");
|
|
|
|
vty_out(vty, "%s\n", table);
|
|
|
|
XFREE(MTYPE_TMP, table);
|
|
|
|
ttable_del(tt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_isis_frr_summary_common(struct vty *vty, int levels,
|
|
|
|
struct isis *isis)
|
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_area *area;
|
|
|
|
|
|
|
|
if (!isis->area_list || isis->area_list->count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
|
|
|
vty_out(vty, "Area %s:\n",
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
|
|
|
|
|
|
|
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
|
|
|
|
if ((level & levels) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (area->ip_circuits > 0) {
|
|
|
|
isis_print_frr_summary(
|
|
|
|
vty,
|
|
|
|
area->spftree[SPFTREE_IPV4][level - 1]);
|
|
|
|
}
|
|
|
|
if (area->ipv6_circuits > 0) {
|
|
|
|
isis_print_frr_summary(
|
|
|
|
vty,
|
|
|
|
area->spftree[SPFTREE_IPV6][level - 1]);
|
|
|
|
}
|
|
|
|
if (isis_area_ipv6_dstsrc_enabled(area)) {
|
|
|
|
isis_print_frr_summary(
|
|
|
|
vty, area->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd,
|
|
|
|
"show " PROTO_NAME
|
|
|
|
" [vrf <NAME|all>] fast-reroute summary"
|
|
|
|
#ifndef FABRICD
|
|
|
|
" [<level-1|level-2>]"
|
|
|
|
#endif
|
|
|
|
,
|
|
|
|
SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
|
|
|
|
"IS-IS FRR information\n"
|
|
|
|
"FRR summary\n"
|
|
|
|
#ifndef FABRICD
|
|
|
|
"level-1 routes\n"
|
|
|
|
"level-2 routes\n"
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int levels;
|
|
|
|
struct isis *isis;
|
|
|
|
struct listnode *node;
|
|
|
|
const char *vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
bool all_vrf = false;
|
|
|
|
int idx = 0;
|
|
|
|
|
|
|
|
if (argv_find(argv, argc, "level-1", &idx))
|
|
|
|
levels = ISIS_LEVEL1;
|
|
|
|
else if (argv_find(argv, argc, "level-2", &idx))
|
|
|
|
levels = ISIS_LEVEL2;
|
|
|
|
else
|
|
|
|
levels = ISIS_LEVEL1 | ISIS_LEVEL2;
|
|
|
|
|
|
|
|
if (!im) {
|
|
|
|
vty_out(vty, "IS-IS Routing Process not enabled\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
|
|
|
|
|
2024-05-04 16:56:21 +02:00
|
|
|
if (all_vrf) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
|
2020-11-20 23:55:42 +01:00
|
|
|
show_isis_frr_summary_common(vty, levels, isis);
|
2024-05-04 16:56:21 +02:00
|
|
|
return CMD_SUCCESS;
|
2020-11-20 23:55:42 +01:00
|
|
|
}
|
2024-05-04 16:56:21 +02:00
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis != NULL)
|
|
|
|
show_isis_frr_summary_common(vty, levels, isis);
|
2020-11-20 23:55:42 +01:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-08-21 02:36:59 +02:00
|
|
|
void isis_spf_init(void)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2022-12-12 16:12:41 +01:00
|
|
|
#ifndef FABRICD
|
|
|
|
install_element(VIEW_NODE, &show_isis_flex_algo_cmd);
|
|
|
|
#endif /* ifndef FABRICD */
|
2003-12-23 09:09:43 +01:00
|
|
|
install_element(VIEW_NODE, &show_isis_topology_cmd);
|
2020-08-23 04:24:06 +02:00
|
|
|
install_element(VIEW_NODE, &show_isis_route_cmd);
|
2020-11-20 23:55:42 +01:00
|
|
|
install_element(VIEW_NODE, &show_isis_frr_summary_cmd);
|
2020-08-21 02:36:59 +02:00
|
|
|
|
|
|
|
/* Register hook(s). */
|
|
|
|
hook_register(isis_adj_state_change_hook, spf_adj_state_change);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2017-08-03 11:45:58 +02:00
|
|
|
|
|
|
|
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
|
|
|
|
{
|
2023-01-23 12:16:39 +01:00
|
|
|
uint64_t last_run_duration = spftree->last_run_duration;
|
|
|
|
|
2017-08-03 11:45:58 +02:00
|
|
|
vty_out(vty, " last run elapsed : ");
|
|
|
|
vty_out_timestr(vty, spftree->last_run_timestamp);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
2023-01-23 12:16:39 +01:00
|
|
|
vty_out(vty, " last run duration : %" PRIu64 " usec\n",
|
|
|
|
last_run_duration);
|
2017-08-03 11:45:58 +02:00
|
|
|
|
|
|
|
vty_out(vty, " run count : %u\n", spftree->runcount);
|
|
|
|
}
|
2022-02-23 12:41:04 +01:00
|
|
|
void isis_spf_print_json(struct isis_spftree *spftree, struct json_object *json)
|
|
|
|
{
|
|
|
|
char uptime[MONOTIME_STRLEN];
|
|
|
|
time_t cur;
|
|
|
|
cur = time(NULL);
|
|
|
|
cur -= spftree->last_run_timestamp;
|
|
|
|
frrtime_to_interval(cur, uptime, sizeof(uptime));
|
|
|
|
json_object_string_add(json, "last-run-elapsed", uptime);
|
|
|
|
json_object_int_add(json, "last-run-duration-usec",
|
|
|
|
spftree->last_run_duration);
|
|
|
|
json_object_int_add(json, "last-run-count", spftree->runcount);
|
|
|
|
}
|