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
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public Licenseas published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
2017-05-13 10:25:29 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "thread.h"
|
|
|
|
#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"
|
|
|
|
#include "if.h"
|
|
|
|
#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"
|
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"
|
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
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
|
2020-08-23 05:22:32 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
|
|
|
|
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)) {
|
2018-07-26 22:53:08 +02:00
|
|
|
srcdest2str(&vertex->N.ip.dest,
|
|
|
|
&vertex->N.ip.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-08-23 05:22:32 +02:00
|
|
|
static void isis_vertex_adj_free(void *arg)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_vertex *vertex,
|
|
|
|
struct isis_spf_adj *sadj)
|
|
|
|
{
|
|
|
|
struct isis_vertex_adj *vadj;
|
|
|
|
|
|
|
|
vadj = XCALLOC(MTYPE_ISIS_VERTEX_ADJ, sizeof(*vadj));
|
|
|
|
vadj->sadj = sadj;
|
|
|
|
listnode_add(vertex->Adj_N, vadj);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_spftree *isis_spftree_new(struct isis_area *area,
|
|
|
|
struct lspdb_head *lspdb,
|
|
|
|
const uint8_t *sysid, int level,
|
2020-08-24 20:27:15 +02:00
|
|
|
enum spf_tree_id tree_id,
|
|
|
|
enum spf_type type, uint8_t flags)
|
2012-03-24 16:35:20 +01:00
|
|
|
{
|
|
|
|
struct isis_spftree *tree;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
tree = XCALLOC(MTYPE_ISIS_SPFTREE, sizeof(struct isis_spftree));
|
2017-07-17 14:03:14 +02: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;
|
|
|
|
tree->route_table_backup = srcdest_table_init();
|
|
|
|
tree->route_table_backup->cleanup = isis_route_node_cleanup;
|
2012-03-24 16:35:20 +01:00
|
|
|
tree->area = area;
|
2020-08-23 05:22:32 +02:00
|
|
|
tree->lspdb = lspdb;
|
|
|
|
tree->sadj_list = list_new();
|
|
|
|
tree->sadj_list->del = isis_spf_adj_free;
|
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;
|
2020-08-21 00:55:42 +02:00
|
|
|
if (tree->type == SPF_TYPE_TI_LFA) {
|
|
|
|
isis_spf_node_list_init(&tree->lfa.p_space);
|
|
|
|
isis_spf_node_list_init(&tree->lfa.q_space);
|
|
|
|
}
|
2020-08-23 05:22:32 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
void isis_spftree_del(struct isis_spftree *spftree)
|
|
|
|
{
|
2020-08-21 00:55:42 +02:00
|
|
|
if (spftree->type == SPF_TYPE_TI_LFA) {
|
|
|
|
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);
|
2018-07-24 17:40:24 +02:00
|
|
|
route_table_finish(spftree->route_table);
|
2020-08-21 00:55:42 +02:00
|
|
|
route_table_finish(spftree->route_table_backup);
|
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
|
|
|
|
|
|
|
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
|
|
|
|
2020-08-24 20:27:15 +02:00
|
|
|
area->spftree[tree][level - 1] =
|
|
|
|
isis_spftree_new(area, &area->lspdb[level - 1],
|
|
|
|
area->isis->sysid, level, tree,
|
|
|
|
SPF_TYPE_FORWARD, 0);
|
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
|
2020-08-23 05:22:32 +02:00
|
|
|
zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
|
2015-11-23 21:44:34 +01:00
|
|
|
vtype2string(vertex->type),
|
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
2004-12-24 01:14:50 +01:00
|
|
|
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
|
|
|
|
|
|
|
hash_get(vertex->firsthops, hop, hash_alloc_intern);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vertex_update_firsthops(struct isis_vertex *vertex,
|
|
|
|
struct isis_vertex *parent)
|
|
|
|
{
|
|
|
|
if (vertex->d_N <= 2)
|
|
|
|
hash_get(vertex->firsthops, vertex, hash_alloc_intern);
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2004-09-10 22:48:21 +02:00
|
|
|
static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
|
|
|
|
enum vertextype vtype, void *id,
|
2017-04-27 12:54:21 +02:00
|
|
|
uint32_t cost, int depth,
|
2020-08-23 05:22:32 +02:00
|
|
|
struct isis_spf_adj *sadj,
|
2012-03-24 16:35:20 +01:00
|
|
|
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;
|
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;
|
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);
|
|
|
|
|
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))
|
|
|
|
isis_vertex_adj_add(vertex, parent_vadj->sadj);
|
|
|
|
} else if (sadj) {
|
|
|
|
isis_vertex_adj_add(vertex, sadj);
|
2012-03-24 16:35:20 +01:00
|
|
|
}
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
|
|
|
|
print_sys_hostname(vertex->N.id), vtype2string(vertex->type),
|
2015-11-23 21:44:34 +01:00
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
2012-03-24 16:35:20 +01:00
|
|
|
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,
|
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-08-23 05:22:32 +02:00
|
|
|
if (sadj)
|
|
|
|
isis_vertex_adj_add(vertex, sadj);
|
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);
|
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-08-23 05:22:32 +02:00
|
|
|
isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, 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,
|
2012-03-24 16:35:20 +01:00
|
|
|
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);
|
|
|
|
apply_mask((struct prefix *)&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
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
|
|
|
|
print_sys_hostname(vertex->N.id), vtype2string(vtype),
|
2015-11-23 21:44:34 +01:00
|
|
|
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
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
|
|
|
|
print_sys_hostname(vertex->N.id), vtype2string(vtype),
|
2015-11-23 21:44:34 +01:00
|
|
|
vid2string(vertex, buff, sizeof(buff)), dist,
|
2012-03-24 16:35:20 +01:00
|
|
|
(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))
|
|
|
|
if (!isis_vertex_adj_exists(spftree, vertex,
|
|
|
|
parent_vadj->sadj))
|
|
|
|
isis_vertex_adj_add(vertex,
|
|
|
|
parent_vadj->sadj);
|
|
|
|
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);
|
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
|
|
|
|
zlog_debug("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
|
|
|
|
print_sys_hostname(id), vtype2string(vtype), dist,
|
|
|
|
(parent ? print_sys_hostname(parent->N.id) : "null"));
|
|
|
|
#endif /* EXTREME_DEBUG */
|
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
isis_spf_add2tent(spftree, vtype, id, dist, depth, NULL, 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;
|
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)) {
|
|
|
|
if (IS_DEBUG_TILFA)
|
|
|
|
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:
|
2017-07-05 18:37:36 +02:00
|
|
|
if (lsp->hdr.seqno == 0) {
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_warn(
|
|
|
|
"isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
|
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
|
|
|
|
zlog_debug("ISIS-Spf: process_lsp %s",
|
2017-07-05 18:37:36 +02: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) {
|
2005-09-28 20:45:54 +02:00
|
|
|
if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
|
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,
|
2017-07-05 18:37:36 +02:00
|
|
|
(void *)r->id, dist, depth + 1,
|
|
|
|
parent);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-05 18:37:36 +02:00
|
|
|
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) {
|
2020-08-23 05:22:32 +02:00
|
|
|
/* C.2.6 a) */
|
|
|
|
/* Two way connectivity */
|
|
|
|
if (!LSP_PSEUDO_ID(er->id)
|
|
|
|
&& !memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
|
2012-03-24 16:35:20 +01:00
|
|
|
continue;
|
2017-04-27 12:54:21 +02:00
|
|
|
if (!pseudo_lsp
|
2017-07-05 18:37:36 +02:00
|
|
|
&& !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
|
2012-03-24 16:35:20 +01:00
|
|
|
continue;
|
2020-08-23 05:22:32 +02:00
|
|
|
dist = cost
|
|
|
|
+ (CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_HOPCOUNT_METRIC)
|
|
|
|
? 1
|
|
|
|
: er->metric);
|
2017-04-27 12:54:21 +02:00
|
|
|
process_N(spftree,
|
2017-07-05 18:37:36 +02:00
|
|
|
LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
|
|
|
|
: VTYPE_NONPSEUDO_TE_IS,
|
|
|
|
(void *)er->id, dist, depth + 1, 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
|
2004-09-10 22:48:21 +02:00
|
|
|
&& spftree->mtid == ISIS_MT_IPV4_UNICAST) {
|
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,
|
2017-07-05 18:37:36 +02:00
|
|
|
dist, depth + 1, 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
|
|
|
|
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;
|
|
|
|
process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
|
2004-09-10 22:48:21 +02:00
|
|
|
dist, depth + 1, parent);
|
|
|
|
}
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
if (r->subtlvs
|
|
|
|
&& r->subtlvs->source_prefix
|
|
|
|
&& r->subtlvs->source_prefix->prefixlen) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
process_N(spftree, vtype, &ip_info, dist,
|
2012-03-24 16:35:20 +01:00
|
|
|
depth + 1, parent);
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (prefix->family == AF_INET)
|
|
|
|
vtype = VTYPE_IPREACH_INTERNAL;
|
|
|
|
else
|
|
|
|
vtype = VTYPE_IP6REACH_INTERNAL;
|
|
|
|
|
|
|
|
isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, parent);
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
if (IS_DEBUG_TILFA)
|
|
|
|
zlog_debug("ISIS-Spf: excising adjacency %s",
|
|
|
|
isis_format_id(sadj->id,
|
|
|
|
ISIS_SYS_ID_LEN + 1));
|
|
|
|
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,
|
|
|
|
sadj->id, sadj, metric, parent);
|
|
|
|
} else if (sadj->lan.lsp_pseudo) {
|
|
|
|
isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo,
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
uint8_t flags = 0;
|
|
|
|
|
|
|
|
/* Skip self in the pseudonode. */
|
|
|
|
if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN))
|
|
|
|
return;
|
|
|
|
|
|
|
|
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);
|
|
|
|
sadj->subtlvs = subtlvs;
|
|
|
|
sadj->flags = flags;
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
if (LSP_PSEUDO_ID(id)) {
|
|
|
|
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
|
|
|
|
struct isis_lsp *lsp_pseudo;
|
|
|
|
|
|
|
|
memcpy(lspid, id, ISIS_SYS_ID_LEN + 1);
|
|
|
|
LSP_FRAGMENT(lspid) = 0;
|
|
|
|
lsp_pseudo = lsp_search(spftree->lspdb, lspid);
|
|
|
|
if (lsp_pseudo == NULL || lsp_pseudo->hdr.rem_lifetime == 0) {
|
|
|
|
zlog_warn(
|
|
|
|
"ISIS-Spf: No LSP found from root to L%d DR %s",
|
|
|
|
spftree->level, rawlspid_print(id));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sadj->lan.lsp_pseudo = lsp_pseudo;
|
|
|
|
spf_adj_list_parse_lsp(spftree, adj_list, lsp_pseudo, id,
|
|
|
|
metric);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
|
|
|
|
struct isis_lsp *frag;
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_item *head;
|
|
|
|
struct isis_item_list *te_neighs;
|
|
|
|
|
|
|
|
if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Parse main LSP. */
|
|
|
|
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) {
|
|
|
|
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
|
|
|
|
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;
|
|
|
|
|
|
|
|
spf_adj_list_parse_lsp(spftree, adj_list, frag, pseudo_nodeid,
|
|
|
|
pseudo_metric);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-08-21 00:55:42 +02:00
|
|
|
struct isis_area *area = spftree->area;
|
2018-07-26 22:53:08 +02:00
|
|
|
char buff[VID2STR_BUFFER];
|
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
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
|
|
|
|
print_sys_hostname(vertex->N.id), vtype2string(vertex->type),
|
2015-11-23 21:44:34 +01:00
|
|
|
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
|
2004-12-24 01:14:50 +01:00
|
|
|
vertex->d_N);
|
2004-09-10 22:48:21 +02:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2012-03-24 16:35:20 +01:00
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (VTYPE_IP(vertex->type)
|
|
|
|
&& !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
|
2020-08-21 00:55:42 +02:00
|
|
|
if (listcount(vertex->Adj_N) > 0) {
|
|
|
|
struct route_table *route_table;
|
|
|
|
|
|
|
|
if (spftree->type == SPF_TYPE_TI_LFA) {
|
|
|
|
if (isis_lfa_check(spftree, vertex) != 0)
|
|
|
|
return;
|
|
|
|
route_table = spftree->lfa.old.spftree
|
|
|
|
->route_table_backup;
|
|
|
|
} else
|
|
|
|
route_table = spftree->route_table;
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_route_create(&vertex->N.ip.dest, &vertex->N.ip.src,
|
2017-04-27 12:54:21 +02:00
|
|
|
vertex->d_N, vertex->depth,
|
2020-08-21 00:55:42 +02:00
|
|
|
vertex->Adj_N, area, route_table);
|
|
|
|
} else if (IS_DEBUG_SPF_EVENTS)
|
2012-03-24 16:35:20 +01:00
|
|
|
zlog_debug(
|
2020-08-21 00:55:42 +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
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
static void init_spt(struct isis_spftree *spftree, int mtid)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2020-08-23 05:22:32 +02:00
|
|
|
/* Clear data from previous run. */
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_spf_node_list_clear(&spftree->adj_nodes);
|
2020-08-23 05:22:32 +02:00
|
|
|
list_delete_all_node(spftree->sadj_list);
|
2017-08-03 14:30:32 +02:00
|
|
|
isis_vertex_queue_clear(&spftree->tents);
|
|
|
|
isis_vertex_queue_clear(&spftree->paths);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 13:56:47 +02:00
|
|
|
spftree->mtid = mtid;
|
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;
|
|
|
|
|
|
|
|
while (isis_vertex_queue_count(&spftree->tents)) {
|
|
|
|
vertex = isis_vertex_queue_pop(&spftree->tents);
|
|
|
|
|
|
|
|
#ifdef EXTREME_DEBUG
|
|
|
|
zlog_debug(
|
|
|
|
"ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
|
|
|
|
print_sys_hostname(vertex->N.id),
|
|
|
|
vtype2string(vertex->type), vertex->depth, vertex->d_N);
|
|
|
|
#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) {
|
|
|
|
zlog_warn("ISIS-Spf: No LSP found for %s",
|
2018-09-25 17:54:09 +02:00
|
|
|
isis_format_id(vertex->N.id,
|
|
|
|
sizeof(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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
|
|
|
|
uint8_t *sysid,
|
|
|
|
struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
if (!spftree)
|
2020-08-23 05:22:32 +02:00
|
|
|
spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1],
|
|
|
|
sysid, ISIS_LEVEL2, SPFTREE_IPV4,
|
2020-08-24 20:27:15 +02:00
|
|
|
SPF_TYPE_FORWARD,
|
2020-08-23 05:22:32 +02:00
|
|
|
F_SPFTREE_HOPCOUNT_METRIC);
|
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;
|
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) {
|
|
|
|
zlog_err("ISIS-Spf: could not find own l%d LSP!",
|
|
|
|
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(
|
|
|
|
"isis_run_spf should never be called with SPFTREE_COUNT as argument!");
|
|
|
|
exit(1);
|
2018-07-26 15:08:11 +02:00
|
|
|
}
|
|
|
|
|
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)) {
|
2012-03-24 16:35:20 +01: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);
|
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. */
|
|
|
|
if (area->lfa_protected_links[spftree->level - 1] > 0)
|
|
|
|
isis_spf_run_lfa(area, spftree);
|
|
|
|
}
|
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
|
|
|
|
{
|
|
|
|
if (area->is_type == IS_LEVEL_1) {
|
2020-08-21 00:55:42 +02:00
|
|
|
isis_route_verify_table(area, trees[0]->route_table,
|
|
|
|
trees[0]->route_table_backup);
|
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,
|
|
|
|
trees[1]->route_table_backup);
|
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,
|
|
|
|
trees[1]->route_table_backup);
|
2018-07-24 17:40:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void isis_spf_invalidate_routes(struct isis_spftree *tree)
|
|
|
|
{
|
|
|
|
isis_route_invalidate_table(tree->area, tree->route_table);
|
2020-08-21 00:55:42 +02:00
|
|
|
|
|
|
|
/* Delete backup routes. */
|
|
|
|
route_table_finish(tree->route_table_backup);
|
|
|
|
tree->route_table_backup = srcdest_table_init();
|
|
|
|
tree->route_table_backup->cleanup = isis_route_node_cleanup;
|
2018-07-24 17:40:24 +02:00
|
|
|
}
|
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
static int isis_run_spf_cb(struct thread *thread)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-04-27 12:54:21 +02:00
|
|
|
struct isis_spf_run *run = THREAD_ARG(thread);
|
|
|
|
struct isis_area *area = run->area;
|
|
|
|
int level = run->level;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 12:54:21 +02:00
|
|
|
XFREE(MTYPE_ISIS_SPF_RUN, run);
|
|
|
|
area->spf_timer[level - 1] = NULL;
|
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);
|
2017-04-27 12:54:21 +02:00
|
|
|
return ISIS_WARNING;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
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)
|
2017-04-27 12:54:21 +02:00
|
|
|
zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
|
|
|
|
area->area_tag, level);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (area->ip_circuits)
|
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_IPV4][level - 1]);
|
|
|
|
if (area->ipv6_circuits)
|
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_IPV6][level - 1]);
|
|
|
|
if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
|
|
|
|
isis_run_spf_with_protection(
|
|
|
|
area, area->spftree[SPFTREE_DSTSRC][level - 1]);
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
isis_area_verify_routes(area);
|
|
|
|
|
2019-08-04 03:02:37 +02:00
|
|
|
isis_area_verify_sr(area);
|
|
|
|
|
2018-07-24 17:40:24 +02:00
|
|
|
/* walk all circuits and reset any spf specific flags */
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_circuit *circuit;
|
|
|
|
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);
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
return 0;
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2018-07-26 12:57:38 +02:00
|
|
|
struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
|
2017-09-23 19:28:48 +02:00
|
|
|
time_t now = monotime(NULL);
|
|
|
|
int diff = now - spftree->last_run_monotime;
|
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(
|
2020-03-27 12:35:23 +01:00
|
|
|
"ISIS-Spf (%s) L%d SPF schedule called, lastrun %d 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
|
|
|
|
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
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
thread_add_timer_msec(master, isis_run_spf_cb,
|
|
|
|
isis_run_spf_arg(area, level), delay,
|
|
|
|
&area->spf_timer[level - 1]);
|
|
|
|
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(
|
|
|
|
"ISIS-Spf (%s) L%d SPF scheduled immediately due to BFD 'down' message",
|
|
|
|
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
|
|
|
|
2017-04-25 00:33:25 +02:00
|
|
|
thread_add_timer(master, isis_run_spf_cb, isis_run_spf_arg(area, level),
|
2017-09-23 19:28:48 +02:00
|
|
|
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)
|
2017-12-06 22:23:55 +01:00
|
|
|
zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %ld sec from now",
|
|
|
|
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,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *root_sysid)
|
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];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 18:50:29 +02:00
|
|
|
vty_out(vty,
|
|
|
|
"Vertex Type Metric Next-Hop Interface Parent\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-03 14:30:32 +02:00
|
|
|
for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
|
2012-03-24 16:35:20 +01:00
|
|
|
if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
|
|
|
|
vty_out(vty, "%-20s %-12s %-6s",
|
|
|
|
print_sys_hostname(root_sysid), "", "");
|
2017-09-01 00:57:57 +02:00
|
|
|
vty_out(vty, "%-30s\n", "");
|
|
|
|
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;
|
|
|
|
|
|
|
|
vty_out(vty, "%-20s %-12s %-6u ",
|
|
|
|
vid2string(vertex, buff, sizeof(buff)),
|
|
|
|
vtype2string(vertex->type), 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);
|
2018-03-06 20:02:52 +01:00
|
|
|
i++) {
|
2017-09-01 00:57:57 +02:00
|
|
|
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) {
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, "%-20s %-12s %-6s ", "", "", "");
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (vadj) {
|
|
|
|
struct isis_spf_adj *sadj = vadj->sadj;
|
|
|
|
|
2017-09-01 00:57:57 +02:00
|
|
|
vty_out(vty, "%-20s %-9s ",
|
2020-08-23 05:22:32 +02:00
|
|
|
print_sys_hostname(sadj->id),
|
|
|
|
sadj->adj ? sadj->adj->circuit
|
|
|
|
->interface->name
|
|
|
|
: "-");
|
2017-09-01 00:57:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pvertex) {
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!vadj)
|
2017-09-01 00:57:57 +02:00
|
|
|
vty_out(vty, "%-20s %-9s ", "", "");
|
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
vty_out(vty, "%s(%d)",
|
2018-03-06 20:02:52 +01:00
|
|
|
vid2string(pvertex, buff, sizeof(buff)),
|
2012-03-24 16:35:20 +01:00
|
|
|
pvertex->type);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2017-09-01 00:57:57 +02:00
|
|
|
++rows;
|
|
|
|
}
|
2017-07-13 19:04:25 +02:00
|
|
|
vty_out(vty, "\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-08-24 19:46:36 +02:00
|
|
|
void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree)
|
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;
|
|
|
|
}
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
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);
|
2018-07-26 22:53:08 +02:00
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
|
2020-07-13 14:37:59 +02:00
|
|
|
static void show_isis_topology_common(struct vty *vty, int levels,
|
|
|
|
struct isis *isis)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_area *area;
|
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
|
|
|
|
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)) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "Area %s:\n",
|
|
|
|
area->area_tag ? area->area_tag : "null");
|
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
|
|
|
|
2018-07-26 22:53:08 +02:00
|
|
|
if (area->ip_circuits > 0) {
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_print_spftree(
|
|
|
|
vty,
|
|
|
|
area->spftree[SPFTREE_IPV4][level - 1]);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2018-07-26 22:53:08 +02:00
|
|
|
if (area->ipv6_circuits > 0) {
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_print_spftree(
|
|
|
|
vty,
|
|
|
|
area->spftree[SPFTREE_IPV6][level - 1]);
|
2018-07-26 22:53:08 +02:00
|
|
|
}
|
|
|
|
if (isis_area_ipv6_dstsrc_enabled(area)) {
|
2020-08-23 05:22:32 +02:00
|
|
|
isis_print_spftree(vty,
|
|
|
|
area->spftree[SPFTREE_DSTSRC]
|
|
|
|
[level - 1]);
|
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)) {
|
|
|
|
vty_out(vty,
|
|
|
|
"IS-IS paths to level-2 routers with hop-by-hop metric\n");
|
|
|
|
isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
|
2017-07-13 19:04:25 +02:00
|
|
|
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>]"
|
|
|
|
#endif
|
|
|
|
,
|
|
|
|
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"
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
int idx = 0;
|
|
|
|
const char *vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
bool all_vrf = false;
|
|
|
|
int idx_vrf = 0;
|
|
|
|
|
|
|
|
if (argv_find(argv, argc, "topology", &idx)) {
|
|
|
|
if (argc < idx + 2)
|
|
|
|
levels = ISIS_LEVEL1 | ISIS_LEVEL2;
|
|
|
|
else if (strmatch(argv[idx + 1]->arg, "level-1"))
|
|
|
|
levels = ISIS_LEVEL1;
|
|
|
|
else
|
|
|
|
levels = 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, vrf_name, all_vrf);
|
|
|
|
|
|
|
|
if (vrf_name) {
|
|
|
|
if (all_vrf) {
|
2020-08-21 02:44:27 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
|
2020-07-13 14:37:59 +02:00
|
|
|
show_isis_topology_common(vty, levels, isis);
|
2020-08-21 02:44:27 +02:00
|
|
|
return CMD_SUCCESS;
|
2020-07-13 14:37:59 +02:00
|
|
|
}
|
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis != NULL)
|
|
|
|
show_isis_topology_common(vty, levels, isis);
|
|
|
|
}
|
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
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, "IS-IS %s %s routing table:\n\n",
|
|
|
|
circuit_t2string(spftree->level), tree_id_text);
|
|
|
|
|
|
|
|
/* Prepare table. */
|
|
|
|
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
|
|
|
|
ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
|
|
|
|
tt->style.cell.rpad = 2;
|
|
|
|
tt->style.corner = '+';
|
|
|
|
ttable_restyle(tt);
|
|
|
|
ttable_rowseps(tt, 0, BOTTOM, 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;
|
|
|
|
struct isis_nexthop *nexthop;
|
|
|
|
struct listnode *node;
|
|
|
|
bool first = true;
|
|
|
|
char buf_prefix[BUFSIZ];
|
|
|
|
|
|
|
|
rinfo = rn->info;
|
|
|
|
if (!rinfo)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
(void)prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
|
|
|
|
struct interface *ifp;
|
|
|
|
char buf_iface[BUFSIZ];
|
|
|
|
char buf_nhop[BUFSIZ];
|
|
|
|
char buf_labels[BUFSIZ] = {};
|
|
|
|
|
2020-08-23 05:22:32 +02:00
|
|
|
if (!CHECK_FLAG(spftree->flags,
|
|
|
|
F_SPFTREE_NO_ADJACENCIES)) {
|
|
|
|
inet_ntop(nexthop->family, &nexthop->ip,
|
|
|
|
buf_nhop, sizeof(buf_nhop));
|
|
|
|
ifp = if_lookup_by_index(nexthop->ifindex,
|
|
|
|
VRF_DEFAULT);
|
|
|
|
if (ifp)
|
|
|
|
strlcpy(buf_iface, ifp->name,
|
|
|
|
sizeof(buf_iface));
|
|
|
|
else
|
|
|
|
snprintf(buf_iface, sizeof(buf_iface),
|
|
|
|
"ifindex %u",
|
|
|
|
nexthop->ifindex);
|
|
|
|
} else {
|
|
|
|
strlcpy(buf_nhop,
|
|
|
|
print_sys_hostname(nexthop->sysid),
|
|
|
|
sizeof(buf_nhop));
|
|
|
|
strlcpy(buf_iface, "-", sizeof(buf_iface));
|
|
|
|
}
|
2020-08-23 04:24:06 +02:00
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (nexthop->label_stack) {
|
|
|
|
for (int i = 0;
|
|
|
|
i < nexthop->label_stack->num_labels;
|
|
|
|
i++) {
|
|
|
|
char buf_label[BUFSIZ];
|
|
|
|
|
|
|
|
label2str(
|
|
|
|
nexthop->label_stack->label[i],
|
|
|
|
buf_label, sizeof(buf_label));
|
|
|
|
if (i != 0)
|
|
|
|
strlcat(buf_labels, "/",
|
|
|
|
sizeof(buf_labels));
|
|
|
|
strlcat(buf_labels, buf_label,
|
|
|
|
sizeof(buf_labels));
|
|
|
|
}
|
|
|
|
} else if (nexthop->sr.label != MPLS_INVALID_LABEL)
|
2020-08-23 04:24:06 +02:00
|
|
|
label2str(nexthop->sr.label, buf_labels,
|
|
|
|
sizeof(buf_labels));
|
|
|
|
else
|
|
|
|
strlcpy(buf_labels, "-", sizeof(buf_labels));
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
|
|
|
|
rinfo->cost, buf_iface, buf_nhop,
|
|
|
|
buf_labels);
|
|
|
|
first = false;
|
|
|
|
} else
|
|
|
|
ttable_add_row(tt, "||%s|%s|%s", buf_iface,
|
|
|
|
buf_nhop, buf_labels);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Dump the generated table. */
|
|
|
|
if (tt->nrows > 1) {
|
|
|
|
char *table;
|
|
|
|
|
|
|
|
table = ttable_dump(tt, "\n");
|
|
|
|
vty_out(vty, "%s\n", table);
|
|
|
|
XFREE(MTYPE_TMP, table);
|
|
|
|
}
|
|
|
|
ttable_del(tt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_isis_route_common(struct vty *vty, int levels,
|
2020-08-21 00:55:42 +02:00
|
|
|
struct isis *isis, bool backup)
|
2020-08-23 04:24:06 +02:00
|
|
|
{
|
|
|
|
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_routes(
|
|
|
|
vty,
|
2020-08-21 00:55:42 +02:00
|
|
|
area->spftree[SPFTREE_IPV4][level - 1],
|
|
|
|
backup);
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
if (area->ipv6_circuits > 0) {
|
|
|
|
isis_print_routes(
|
|
|
|
vty,
|
2020-08-21 00:55:42 +02:00
|
|
|
area->spftree[SPFTREE_IPV6][level - 1],
|
|
|
|
backup);
|
2020-08-23 04:24:06 +02:00
|
|
|
}
|
|
|
|
if (isis_area_ipv6_dstsrc_enabled(area)) {
|
|
|
|
isis_print_routes(vty,
|
|
|
|
area->spftree[SPFTREE_DSTSRC]
|
2020-08-21 00:55:42 +02:00
|
|
|
[level - 1],
|
|
|
|
backup);
|
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>]"
|
|
|
|
#endif
|
2020-08-21 00:55:42 +02:00
|
|
|
" [backup]",
|
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"
|
|
|
|
#endif
|
2020-08-21 00:55:42 +02:00
|
|
|
"Show backup routes\n")
|
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;
|
2020-08-21 00:55:42 +02:00
|
|
|
bool backup = false;
|
2020-08-23 04:24:06 +02:00
|
|
|
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);
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
if (argv_find(argv, argc, "backup", &idx))
|
|
|
|
backup = true;
|
|
|
|
|
2020-08-23 04:24:06 +02:00
|
|
|
if (vrf_name) {
|
|
|
|
if (all_vrf) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
|
2020-08-21 00:55:42 +02:00
|
|
|
show_isis_route_common(vty, levels, isis,
|
|
|
|
backup);
|
2020-08-23 04:24:06 +02:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
isis = isis_lookup_by_vrfname(vrf_name);
|
|
|
|
if (isis != NULL)
|
2020-08-21 00:55:42 +02:00
|
|
|
show_isis_route_common(vty, levels, isis, backup);
|
2020-08-23 04:24:06 +02: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
|
|
|
{
|
|
|
|
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-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)
|
|
|
|
{
|
|
|
|
vty_out(vty, " last run elapsed : ");
|
|
|
|
vty_out_timestr(vty, spftree->last_run_timestamp);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
|
|
|
|
vty_out(vty, " last run duration : %u usec\n",
|
2018-03-27 21:13:34 +02:00
|
|
|
(uint32_t)spftree->last_run_duration);
|
2017-08-03 11:45:58 +02:00
|
|
|
|
2018-03-06 20:02:52 +01:00
|
|
|
vty_out(vty, " run count : %u\n", spftree->runcount);
|
2017-08-03 11:45:58 +02:00
|
|
|
}
|