]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_spf.c
Merge pull request #6889 from opensourcerouting/isisd-assorted-fixes
[mirror_frr.git] / isisd / isis_spf.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_spf.c
3 * The SPT algorithm
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 6 * Tampere University of Technology
eb5d44eb 7 * Institute of Communications Engineering
1b49e4f0 8 * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
eb5d44eb 9 *
d62a17ae 10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public Licenseas published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
eb5d44eb 13 * any later version.
14 *
d62a17ae 15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
eb5d44eb 18 * more details.
896014f4
DL
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
eb5d44eb 23 */
24
eb5d44eb 25#include <zebra.h>
eb5d44eb 26
27#include "thread.h"
28#include "linklist.h"
29#include "vty.h"
30#include "log.h"
31#include "command.h"
32#include "memory.h"
33#include "prefix.h"
eb5d44eb 34#include "if.h"
35#include "table.h"
03f7e182 36#include "spf_backoff.h"
321c1bbb 37#include "srcdest_table.h"
eb5d44eb 38
39#include "isis_constants.h"
40#include "isis_common.h"
3f045a08 41#include "isis_flags.h"
eb5d44eb 42#include "isisd.h"
43#include "isis_misc.h"
44#include "isis_adjacency.h"
45#include "isis_circuit.h"
eb5d44eb 46#include "isis_pdu.h"
47#include "isis_lsp.h"
48#include "isis_dynhn.h"
49#include "isis_spf.h"
50#include "isis_route.h"
51#include "isis_csm.h"
2b67862c 52#include "isis_mt.h"
841791b6 53#include "isis_tlvs.h"
b30e837b 54#include "fabricd.h"
cbd8e49e 55#include "isis_spf_private.h"
eb5d44eb 56
1b49e4f0
CF
57DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
58
af8ac8f9
CF
59/*
60 * supports the given af ?
61 */
62static bool speaks(uint8_t *protocols, uint8_t count, int family)
63{
64 for (uint8_t i = 0; i < count; i++) {
65 if (family == AF_INET && protocols[i] == NLPID_IP)
66 return true;
67 if (family == AF_INET6 && protocols[i] == NLPID_IPV6)
68 return true;
69 }
70 return false;
71}
72
1b49e4f0 73struct isis_spf_run {
d62a17ae 74 struct isis_area *area;
75 int level;
1b49e4f0
CF
76};
77
eb5d44eb 78/* 7.2.7 */
d62a17ae 79static void remove_excess_adjs(struct list *adjs)
eb5d44eb 80{
d62a17ae 81 struct listnode *node, *excess = NULL;
82 struct isis_adjacency *adj, *candidate = NULL;
83 int comp;
84
85 for (ALL_LIST_ELEMENTS_RO(adjs, node, adj)) {
86 if (excess == NULL)
87 excess = node;
88 candidate = listgetdata(excess);
89
90 if (candidate->sys_type < adj->sys_type) {
91 excess = node;
92 continue;
93 }
94 if (candidate->sys_type > adj->sys_type)
95 continue;
f390d2c7 96
d62a17ae 97 comp = memcmp(candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
98 if (comp > 0) {
99 excess = node;
100 continue;
101 }
102 if (comp < 0)
103 continue;
eb5d44eb 104
0849c75e 105 if (candidate->circuit->idx > adj->circuit->idx) {
d62a17ae 106 excess = node;
107 continue;
108 }
f390d2c7 109
0849c75e 110 if (candidate->circuit->idx < adj->circuit->idx)
d62a17ae 111 continue;
f390d2c7 112
d62a17ae 113 comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN);
114 if (comp > 0) {
115 excess = node;
116 continue;
117 }
f390d2c7 118 }
f390d2c7 119
d62a17ae 120 list_delete_node(adjs, excess);
eb5d44eb 121
d62a17ae 122 return;
eb5d44eb 123}
124
d62a17ae 125static const char *vtype2string(enum vertextype vtype)
eb5d44eb 126{
d62a17ae 127 switch (vtype) {
128 case VTYPE_PSEUDO_IS:
129 return "pseudo_IS";
d62a17ae 130 case VTYPE_PSEUDO_TE_IS:
131 return "pseudo_TE-IS";
d62a17ae 132 case VTYPE_NONPSEUDO_IS:
133 return "IS";
d62a17ae 134 case VTYPE_NONPSEUDO_TE_IS:
135 return "TE-IS";
d62a17ae 136 case VTYPE_ES:
137 return "ES";
d62a17ae 138 case VTYPE_IPREACH_INTERNAL:
139 return "IP internal";
d62a17ae 140 case VTYPE_IPREACH_EXTERNAL:
141 return "IP external";
d62a17ae 142 case VTYPE_IPREACH_TE:
143 return "IP TE";
d62a17ae 144 case VTYPE_IP6REACH_INTERNAL:
145 return "IP6 internal";
d62a17ae 146 case VTYPE_IP6REACH_EXTERNAL:
147 return "IP6 external";
d62a17ae 148 default:
149 return "UNKNOWN";
150 }
151 return NULL; /* Not reached */
eb5d44eb 152}
153
d4cff91a 154const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
eb5d44eb 155{
d62a17ae 156 if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
157 return print_sys_hostname(vertex->N.id);
158 }
159
160 if (VTYPE_IP(vertex->type)) {
321c1bbb
CF
161 srcdest2str(&vertex->N.ip.dest,
162 &vertex->N.ip.src,
163 buff, size);
d62a17ae 164 return buff;
165 }
166
167 return "UNKNOWN";
eb5d44eb 168}
169
686afe9f 170static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
f6ae63ca 171 void *id,
ae9c9aba 172 enum vertextype vtype)
eb919f07
CF
173{
174 struct isis_vertex *vertex;
175
176 vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
177
f6ae63ca 178 isis_vertex_id_init(vertex, id, vtype);
d62a17ae 179
180 vertex->Adj_N = list_new();
181 vertex->parents = list_new();
d62a17ae 182
686afe9f
CF
183 if (spftree->hopcount_metric) {
184 vertex->firsthops = hash_create(isis_vertex_queue_hash_key,
185 isis_vertex_queue_hash_cmp,
186 NULL);
187 }
188
d62a17ae 189 return vertex;
eb5d44eb 190}
191
d62a17ae 192static void isis_vertex_adj_del(struct isis_vertex *vertex,
193 struct isis_adjacency *adj)
3f045a08 194{
d62a17ae 195 struct listnode *node, *nextnode;
196 if (!vertex)
197 return;
198 for (node = listhead(vertex->Adj_N); node; node = nextnode) {
199 nextnode = listnextnode(node);
200 if (listgetdata(node) == adj)
201 list_delete_node(vertex->Adj_N, node);
202 }
203 return;
3f045a08
JB
204}
205
d62a17ae 206struct isis_spftree *isis_spftree_new(struct isis_area *area)
3f045a08 207{
d62a17ae 208 struct isis_spftree *tree;
209
210 tree = XCALLOC(MTYPE_ISIS_SPFTREE, sizeof(struct isis_spftree));
d62a17ae 211
bded4060
CF
212 isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
213 isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
321c1bbb 214 tree->route_table = srcdest_table_init();
d62a17ae 215 tree->area = area;
216 tree->last_run_timestamp = 0;
3dca3c8c 217 tree->last_run_monotime = 0;
d62a17ae 218 tree->last_run_duration = 0;
219 tree->runcount = 0;
220 return tree;
3f045a08
JB
221}
222
d62a17ae 223void isis_spftree_del(struct isis_spftree *spftree)
eb5d44eb 224{
eb919f07
CF
225 isis_vertex_queue_free(&spftree->tents);
226 isis_vertex_queue_free(&spftree->paths);
3dace42d
CF
227 route_table_finish(spftree->route_table);
228 spftree->route_table = NULL;
eb5d44eb 229
3dace42d 230 XFREE(MTYPE_ISIS_SPFTREE, spftree);
d62a17ae 231 return;
eb5d44eb 232}
3f045a08 233
d62a17ae 234static void isis_spftree_adj_del(struct isis_spftree *spftree,
235 struct isis_adjacency *adj)
3f045a08 236{
d62a17ae 237 struct listnode *node;
eb919f07 238 struct isis_vertex *v;
d62a17ae 239 if (!adj)
240 return;
bded4060 241 assert(!isis_vertex_queue_count(&spftree->tents));
eb919f07
CF
242 for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v))
243 isis_vertex_adj_del(v, adj);
d62a17ae 244 return;
3f045a08 245}
eb5d44eb 246
d62a17ae 247void spftree_area_init(struct isis_area *area)
eb5d44eb 248{
be985ba0
CF
249 for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
250 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
251 if (!(area->is_type & level))
252 continue;
253 if (area->spftree[tree][level - 1])
254 continue;
d62a17ae 255
be985ba0
CF
256 area->spftree[tree][level - 1] = isis_spftree_new(area);
257 }
d62a17ae 258 }
eb5d44eb 259}
260
d62a17ae 261void spftree_area_del(struct isis_area *area)
eb5d44eb 262{
be985ba0
CF
263 for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
264 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
265 if (!(area->is_type & level))
266 continue;
267 if (!area->spftree[tree][level - 1])
268 continue;
d62a17ae 269
be985ba0 270 isis_spftree_del(area->spftree[tree][level - 1]);
d62a17ae 271 }
272 }
3f045a08 273}
f390d2c7 274
d62a17ae 275void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
3f045a08 276{
be985ba0
CF
277 for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
278 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
279 if (!(area->is_type & level))
280 continue;
281 if (!area->spftree[tree][level - 1])
282 continue;
283 isis_spftree_adj_del(area->spftree[tree][level - 1],
284 adj);
285 }
d62a17ae 286 }
b30e837b
CF
287
288 if (fabricd_spftree(area) != NULL)
289 isis_spftree_adj_del(fabricd_spftree(area), adj);
3f045a08
JB
290}
291
d62a17ae 292/*
293 * Find the system LSP: returns the LSP in our LSP database
3f045a08
JB
294 * associated with the given system ID.
295 */
d62a17ae 296static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
d7c0a89a 297 uint8_t *sysid)
3f045a08 298{
d62a17ae 299 struct isis_lsp *lsp;
d7c0a89a 300 uint8_t lspid[ISIS_SYS_ID_LEN + 2];
d62a17ae 301
302 memcpy(lspid, sysid, ISIS_SYS_ID_LEN);
303 LSP_PSEUDO_ID(lspid) = 0;
304 LSP_FRAGMENT(lspid) = 0;
4bef0ec4 305 lsp = lsp_search(&area->lspdb[level - 1], lspid);
af8ac8f9 306 if (lsp && lsp->hdr.rem_lifetime != 0)
d62a17ae 307 return lsp;
308 return NULL;
eb5d44eb 309}
310
311/*
312 * Add this IS to the root of SPT
313 */
d62a17ae 314static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
d7c0a89a 315 uint8_t *sysid)
eb5d44eb 316{
d62a17ae 317 struct isis_vertex *vertex;
318 struct isis_lsp *lsp;
eb5d44eb 319#ifdef EXTREME_DEBUG
321c1bbb 320 char buff[VID2STR_BUFFER];
eb5d44eb 321#endif /* EXTREME_DEBUG */
f390d2c7 322
d62a17ae 323 lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
324 if (lsp == NULL)
325 zlog_warn("ISIS-Spf: could not find own l%d LSP!",
326 spftree->level);
eb5d44eb 327
f6ae63ca 328 vertex = isis_vertex_new(spftree, sysid,
9d303b37
DL
329 spftree->area->oldmetric
330 ? VTYPE_NONPSEUDO_IS
331 : VTYPE_NONPSEUDO_TE_IS);
bded4060 332 isis_vertex_queue_append(&spftree->paths, vertex);
eb5d44eb 333
334#ifdef EXTREME_DEBUG
d62a17ae 335 zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
336 vtype2string(vertex->type),
337 vid2string(vertex, buff, sizeof(buff)), vertex->depth,
338 vertex->d_N);
eb5d44eb 339#endif /* EXTREME_DEBUG */
340
d62a17ae 341 return vertex;
eb5d44eb 342}
343
e3b78da8 344static void vertex_add_parent_firsthop(struct hash_bucket *bucket, void *arg)
686afe9f
CF
345{
346 struct isis_vertex *vertex = arg;
e3b78da8 347 struct isis_vertex *hop = bucket->data;
686afe9f
CF
348
349 hash_get(vertex->firsthops, hop, hash_alloc_intern);
350}
351
352static void vertex_update_firsthops(struct isis_vertex *vertex,
353 struct isis_vertex *parent)
354{
355 if (vertex->d_N <= 2)
356 hash_get(vertex->firsthops, vertex, hash_alloc_intern);
357
358 if (vertex->d_N < 2 || !parent)
359 return;
360
361 hash_iterate(parent->firsthops, vertex_add_parent_firsthop, vertex);
362}
363
eb5d44eb 364/*
365 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
366 */
d62a17ae 367static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
368 enum vertextype vtype, void *id,
369 uint32_t cost, int depth,
370 struct isis_adjacency *adj,
371 struct isis_vertex *parent)
eb5d44eb 372{
eb919f07 373 struct isis_vertex *vertex;
d62a17ae 374 struct listnode *node;
375 struct isis_adjacency *parent_adj;
321c1bbb 376 char buff[VID2STR_BUFFER];
eb5d44eb 377
75750ccf
EDP
378 vertex = isis_find_vertex(&spftree->paths, id, vtype);
379 if (vertex != NULL) {
380 zlog_err(
381 "%s: vertex %s of type %s already in PATH; check for sysId collisions with established neighbors",
382 __func__, vid2string(vertex, buff, sizeof(buff)),
383 vtype2string(vertex->type));
384 return NULL;
385 }
386 vertex = isis_find_vertex(&spftree->tents, id, vtype);
387 if (vertex != NULL) {
388 zlog_err(
389 "%s: vertex %s of type %s already in TENT; check for sysId collisions with established neighbors",
390 __func__, vid2string(vertex, buff, sizeof(buff)),
391 vtype2string(vertex->type));
392 return NULL;
393 }
394
686afe9f 395 vertex = isis_vertex_new(spftree, id, vtype);
d62a17ae 396 vertex->d_N = cost;
397 vertex->depth = depth;
398
399 if (parent) {
400 listnode_add(vertex->parents, parent);
d62a17ae 401 }
402
686afe9f
CF
403 if (spftree->hopcount_metric)
404 vertex_update_firsthops(vertex, parent);
405
d62a17ae 406 if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
407 for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_adj))
408 listnode_add(vertex->Adj_N, parent_adj);
409 } else if (adj) {
410 listnode_add(vertex->Adj_N, adj);
411 }
3f045a08 412
f390d2c7 413#ifdef EXTREME_DEBUG
d62a17ae 414 zlog_debug(
415 "ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
416 print_sys_hostname(vertex->N.id), vtype2string(vertex->type),
417 vid2string(vertex, buff, sizeof(buff)), vertex->depth,
418 vertex->d_N, listcount(vertex->Adj_N));
eb5d44eb 419#endif /* EXTREME_DEBUG */
3f045a08 420
eb919f07 421 isis_vertex_queue_insert(&spftree->tents, vertex);
d62a17ae 422 return vertex;
423}
424
425static void isis_spf_add_local(struct isis_spftree *spftree,
426 enum vertextype vtype, void *id,
427 struct isis_adjacency *adj, uint32_t cost,
428 struct isis_vertex *parent)
429{
430 struct isis_vertex *vertex;
431
eb919f07 432 vertex = isis_find_vertex(&spftree->tents, id, vtype);
d62a17ae 433
434 if (vertex) {
435 /* C.2.5 c) */
436 if (vertex->d_N == cost) {
437 if (adj)
438 listnode_add(vertex->Adj_N, adj);
439 /* d) */
440 if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
441 remove_excess_adjs(vertex->Adj_N);
9d303b37
DL
442 if (parent && (listnode_lookup(vertex->parents, parent)
443 == NULL))
d62a17ae 444 listnode_add(vertex->parents, parent);
d62a17ae 445 return;
446 } else if (vertex->d_N < cost) {
447 /* e) do nothing */
448 return;
449 } else { /* vertex->d_N > cost */
450 /* f) */
eb919f07 451 isis_vertex_queue_delete(&spftree->tents, vertex);
d62a17ae 452 isis_vertex_del(vertex);
453 }
f390d2c7 454 }
d62a17ae 455
456 isis_spf_add2tent(spftree, vtype, id, cost, 1, adj, parent);
457 return;
eb5d44eb 458}
459
d62a17ae 460static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
461 void *id, uint32_t dist, uint16_t depth,
462 struct isis_vertex *parent)
eb5d44eb 463{
d62a17ae 464 struct isis_vertex *vertex;
eb5d44eb 465#ifdef EXTREME_DEBUG
321c1bbb 466 char buff[VID2STR_BUFFER];
eb5d44eb 467#endif
468
d62a17ae 469 assert(spftree && parent);
470
b30e837b
CF
471 if (spftree->hopcount_metric
472 && !VTYPE_IS(vtype))
473 return;
474
321c1bbb 475 struct prefix_pair p;
af8ac8f9 476 if (vtype >= VTYPE_IPREACH_INTERNAL) {
321c1bbb
CF
477 memcpy(&p, id, sizeof(p));
478 apply_mask(&p.dest);
479 apply_mask((struct prefix *)&p.src);
af8ac8f9
CF
480 id = &p;
481 }
482
d62a17ae 483 /* RFC3787 section 5.1 */
484 if (spftree->area->newmetric == 1) {
485 if (dist > MAX_WIDE_PATH_METRIC)
486 return;
487 }
488 /* C.2.6 b) */
489 else if (spftree->area->oldmetric == 1) {
490 if (dist > MAX_NARROW_PATH_METRIC)
491 return;
492 }
493
494 /* c) */
eb919f07 495 vertex = isis_find_vertex(&spftree->paths, id, vtype);
d62a17ae 496 if (vertex) {
eb5d44eb 497#ifdef EXTREME_DEBUG
d62a17ae 498 zlog_debug(
499 "ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
500 print_sys_hostname(vertex->N.id), vtype2string(vtype),
501 vid2string(vertex, buff, sizeof(buff)), dist);
eb5d44eb 502#endif /* EXTREME_DEBUG */
d62a17ae 503 assert(dist >= vertex->d_N);
504 return;
505 }
506
eb919f07 507 vertex = isis_find_vertex(&spftree->tents, id, vtype);
d62a17ae 508 /* d) */
509 if (vertex) {
510/* 1) */
eb5d44eb 511#ifdef EXTREME_DEBUG
d62a17ae 512 zlog_debug(
513 "ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
514 print_sys_hostname(vertex->N.id), vtype2string(vtype),
515 vid2string(vertex, buff, sizeof(buff)), dist,
516 (parent ? print_sys_hostname(parent->N.id) : "null"),
517 (parent ? listcount(parent->Adj_N) : 0));
eb5d44eb 518#endif /* EXTREME_DEBUG */
d62a17ae 519 if (vertex->d_N == dist) {
520 struct listnode *node;
521 struct isis_adjacency *parent_adj;
522 for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node,
523 parent_adj))
524 if (listnode_lookup(vertex->Adj_N, parent_adj)
525 == NULL)
526 listnode_add(vertex->Adj_N, parent_adj);
686afe9f
CF
527 if (spftree->hopcount_metric)
528 vertex_update_firsthops(vertex, parent);
d62a17ae 529 /* 2) */
530 if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
531 remove_excess_adjs(vertex->Adj_N);
532 if (listnode_lookup(vertex->parents, parent) == NULL)
533 listnode_add(vertex->parents, parent);
d62a17ae 534 return;
535 } else if (vertex->d_N < dist) {
536 return;
537 /* 4) */
538 } else {
eb919f07 539 isis_vertex_queue_delete(&spftree->tents, vertex);
d62a17ae 540 isis_vertex_del(vertex);
541 }
f390d2c7 542 }
f390d2c7 543
3f045a08 544#ifdef EXTREME_DEBUG
d62a17ae 545 zlog_debug("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
546 print_sys_hostname(id), vtype2string(vtype), dist,
547 (parent ? print_sys_hostname(parent->N.id) : "null"));
3f045a08
JB
548#endif /* EXTREME_DEBUG */
549
d62a17ae 550 isis_spf_add2tent(spftree, vtype, id, dist, depth, NULL, parent);
551 return;
eb5d44eb 552}
553
554/*
555 * C.2.6 Step 1
556 */
d62a17ae 557static int isis_spf_process_lsp(struct isis_spftree *spftree,
558 struct isis_lsp *lsp, uint32_t cost,
d7c0a89a 559 uint16_t depth, uint8_t *root_sysid,
d62a17ae 560 struct isis_vertex *parent)
eb5d44eb 561{
af8ac8f9
CF
562 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
563 struct listnode *fragnode = NULL;
d62a17ae 564 uint32_t dist;
d62a17ae 565 enum vertextype vtype;
d7c0a89a 566 static const uint8_t null_sysid[ISIS_SYS_ID_LEN];
af8ac8f9 567 struct isis_mt_router_info *mt_router_info = NULL;
321c1bbb 568 struct prefix_pair ip_info;
af8ac8f9
CF
569
570 if (!lsp->tlvs)
571 return ISIS_OK;
d62a17ae 572
573 if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
af8ac8f9
CF
574 mt_router_info = isis_tlvs_lookup_mt_router_info(lsp->tlvs,
575 spftree->mtid);
d62a17ae 576
9d303b37 577 if (!pseudo_lsp && (spftree->mtid == ISIS_MT_IPV4_UNICAST
af8ac8f9
CF
578 && !speaks(lsp->tlvs->protocols_supported.protocols,
579 lsp->tlvs->protocols_supported.count,
580 spftree->family))
d62a17ae 581 && !mt_router_info)
582 return ISIS_OK;
eb5d44eb 583
39a275aa 584 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
98c5bc15
CF
585 bool no_overload = (pseudo_lsp
586 || (spftree->mtid == ISIS_MT_IPV4_UNICAST
39a275aa 587 && !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits))
98c5bc15 588 || (mt_router_info && !mt_router_info->overload));
39a275aa 589
f390d2c7 590lspfragloop:
af8ac8f9 591 if (lsp->hdr.seqno == 0) {
d62a17ae 592 zlog_warn(
593 "isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
594 return ISIS_WARNING;
595 }
f390d2c7 596
3f045a08 597#ifdef EXTREME_DEBUG
d62a17ae 598 zlog_debug("ISIS-Spf: process_lsp %s",
af8ac8f9 599 print_sys_hostname(lsp->hdr.lsp_id));
3f045a08
JB
600#endif /* EXTREME_DEBUG */
601
39a275aa 602 if (no_overload) {
d62a17ae 603 if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
af8ac8f9
CF
604 struct isis_oldstyle_reach *r;
605 for (r = (struct isis_oldstyle_reach *)
606 lsp->tlvs->oldstyle_reach.head;
607 r; r = r->next) {
a2d41bb0
CF
608 if (fabricd)
609 continue;
610
d62a17ae 611 /* C.2.6 a) */
612 /* Two way connectivity */
af8ac8f9 613 if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN))
d62a17ae 614 continue;
615 if (!pseudo_lsp
af8ac8f9 616 && !memcmp(r->id, null_sysid,
d62a17ae 617 ISIS_SYS_ID_LEN))
618 continue;
af8ac8f9 619 dist = cost + r->metric;
d62a17ae 620 process_N(spftree,
af8ac8f9 621 LSP_PSEUDO_ID(r->id)
d62a17ae 622 ? VTYPE_PSEUDO_IS
623 : VTYPE_NONPSEUDO_IS,
af8ac8f9
CF
624 (void *)r->id, dist, depth + 1,
625 parent);
d62a17ae 626 }
627 }
628
af8ac8f9
CF
629 struct isis_item_list *te_neighs = NULL;
630 if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
631 te_neighs = &lsp->tlvs->extended_reach;
632 else
633 te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach,
634 spftree->mtid);
635
636 struct isis_extended_reach *er;
637 for (er = te_neighs
638 ? (struct isis_extended_reach *)
639 te_neighs->head
640 : NULL;
641 er; er = er->next) {
642 if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
d62a17ae 643 continue;
644 if (!pseudo_lsp
af8ac8f9 645 && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
d62a17ae 646 continue;
b30e837b 647 dist = cost + (spftree->hopcount_metric ? 1 : er->metric);
d62a17ae 648 process_N(spftree,
af8ac8f9
CF
649 LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
650 : VTYPE_NONPSEUDO_TE_IS,
651 (void *)er->id, dist, depth + 1, parent);
d62a17ae 652 }
f390d2c7 653 }
d62a17ae 654
3be6e411 655 if (!fabricd && !pseudo_lsp && spftree->family == AF_INET
d62a17ae 656 && spftree->mtid == ISIS_MT_IPV4_UNICAST) {
af8ac8f9
CF
657 struct isis_item_list *reachs[] = {
658 &lsp->tlvs->oldstyle_ip_reach,
659 &lsp->tlvs->oldstyle_ip_reach_ext};
d62a17ae 660
d62a17ae 661 for (unsigned int i = 0; i < array_size(reachs); i++) {
af8ac8f9
CF
662 vtype = i ? VTYPE_IPREACH_EXTERNAL
663 : VTYPE_IPREACH_INTERNAL;
664
321c1bbb
CF
665 memset(&ip_info, 0, sizeof(ip_info));
666 ip_info.dest.family = AF_INET;
667
af8ac8f9
CF
668 struct isis_oldstyle_ip_reach *r;
669 for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
670 ->head;
671 r; r = r->next) {
672 dist = cost + r->metric;
321c1bbb
CF
673 ip_info.dest.u.prefix4 = r->prefix.prefix;
674 ip_info.dest.prefixlen = r->prefix.prefixlen;
675 process_N(spftree, vtype, &ip_info,
af8ac8f9 676 dist, depth + 1, parent);
d62a17ae 677 }
678 }
f390d2c7 679 }
d62a17ae 680
681 if (!pseudo_lsp && spftree->family == AF_INET) {
af8ac8f9
CF
682 struct isis_item_list *ipv4_reachs;
683 if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
684 ipv4_reachs = &lsp->tlvs->extended_ip_reach;
685 else
686 ipv4_reachs = isis_lookup_mt_items(
687 &lsp->tlvs->mt_ip_reach, spftree->mtid);
688
321c1bbb
CF
689 memset(&ip_info, 0, sizeof(ip_info));
690 ip_info.dest.family = AF_INET;
691
af8ac8f9
CF
692 struct isis_extended_ip_reach *r;
693 for (r = ipv4_reachs
694 ? (struct isis_extended_ip_reach *)
695 ipv4_reachs->head
696 : NULL;
697 r; r = r->next) {
698 dist = cost + r->metric;
321c1bbb
CF
699 ip_info.dest.u.prefix4 = r->prefix.prefix;
700 ip_info.dest.prefixlen = r->prefix.prefixlen;
701 process_N(spftree, VTYPE_IPREACH_TE, &ip_info,
d62a17ae 702 dist, depth + 1, parent);
f390d2c7 703 }
f390d2c7 704 }
d62a17ae 705
706 if (!pseudo_lsp && spftree->family == AF_INET6) {
af8ac8f9
CF
707 struct isis_item_list *ipv6_reachs;
708 if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
709 ipv6_reachs = &lsp->tlvs->ipv6_reach;
710 else
711 ipv6_reachs = isis_lookup_mt_items(
712 &lsp->tlvs->mt_ipv6_reach, spftree->mtid);
713
714 struct isis_ipv6_reach *r;
715 for (r = ipv6_reachs
716 ? (struct isis_ipv6_reach *)ipv6_reachs->head
717 : NULL;
718 r; r = r->next) {
719 dist = cost + r->metric;
720 vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
721 : VTYPE_IP6REACH_INTERNAL;
321c1bbb
CF
722 memset(&ip_info, 0, sizeof(ip_info));
723 ip_info.dest.family = AF_INET6;
724 ip_info.dest.u.prefix6 = r->prefix.prefix;
725 ip_info.dest.prefixlen = r->prefix.prefixlen;
726
727 if (r->subtlvs
728 && r->subtlvs->source_prefix
729 && r->subtlvs->source_prefix->prefixlen) {
730 if (spftree->tree_id != SPFTREE_DSTSRC) {
731 char buff[VID2STR_BUFFER];
732 zlog_warn("Ignoring dest-src route %s in non dest-src topology",
733 srcdest2str(
734 &ip_info.dest,
735 r->subtlvs->source_prefix,
736 buff, sizeof(buff)
737 )
738 );
739 continue;
740 }
741 ip_info.src = *r->subtlvs->source_prefix;
742 }
743 process_N(spftree, vtype, &ip_info, dist,
d62a17ae 744 depth + 1, parent);
745 }
f390d2c7 746 }
d62a17ae 747
748 if (fragnode == NULL)
749 fragnode = listhead(lsp->lspu.frags);
750 else
751 fragnode = listnextnode(fragnode);
752
753 if (fragnode) {
754 lsp = listgetdata(fragnode);
755 goto lspfragloop;
756 }
757
758 return ISIS_OK;
759}
760
761static int isis_spf_preload_tent(struct isis_spftree *spftree,
d7c0a89a
QY
762 uint8_t *root_sysid,
763 struct isis_vertex *parent)
d62a17ae 764{
765 struct isis_circuit *circuit;
766 struct listnode *cnode, *anode, *ipnode;
767 struct isis_adjacency *adj;
768 struct isis_lsp *lsp;
769 struct list *adj_list;
770 struct list *adjdb;
771 struct prefix_ipv4 *ipv4;
321c1bbb 772 struct prefix_pair ip_info;
d62a17ae 773 int retval = ISIS_OK;
d7c0a89a
QY
774 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
775 static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2];
d62a17ae 776 struct prefix_ipv6 *ipv6;
777 struct isis_circuit_mt_setting *circuit_mt;
778
779 for (ALL_LIST_ELEMENTS_RO(spftree->area->circuit_list, cnode,
780 circuit)) {
781 circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
782 if (circuit_mt && !circuit_mt->enabled)
783 continue;
784 if (circuit->state != C_STATE_UP)
785 continue;
786 if (!(circuit->is_type & spftree->level))
787 continue;
788 if (spftree->family == AF_INET && !circuit->ip_router)
789 continue;
790 if (spftree->family == AF_INET6 && !circuit->ipv6_router)
791 continue;
792 /*
793 * Add IP(v6) addresses of this circuit
794 */
b30e837b 795 if (spftree->family == AF_INET && !spftree->hopcount_metric) {
321c1bbb
CF
796 memset(&ip_info, 0, sizeof(ip_info));
797 ip_info.dest.family = AF_INET;
d62a17ae 798 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
799 ipv4)) {
321c1bbb
CF
800 ip_info.dest.u.prefix4 = ipv4->prefix;
801 ip_info.dest.prefixlen = ipv4->prefixlen;
802 apply_mask(&ip_info.dest);
d62a17ae 803 isis_spf_add_local(spftree,
804 VTYPE_IPREACH_INTERNAL,
321c1bbb 805 &ip_info, NULL, 0, parent);
d62a17ae 806 }
807 }
b30e837b 808 if (spftree->family == AF_INET6 && !spftree->hopcount_metric) {
321c1bbb
CF
809 memset(&ip_info, 0, sizeof(ip_info));
810 ip_info.dest.family = AF_INET6;
d62a17ae 811 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
812 ipnode, ipv6)) {
321c1bbb
CF
813 ip_info.dest.u.prefix6 = ipv6->prefix;
814 ip_info.dest.prefixlen = ipv6->prefixlen;
815 apply_mask(&ip_info.dest);
d62a17ae 816 isis_spf_add_local(spftree,
817 VTYPE_IP6REACH_INTERNAL,
321c1bbb 818 &ip_info, NULL, 0, parent);
d62a17ae 819 }
820 }
821 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
822 /*
823 * Add the adjacencies
824 */
825 adj_list = list_new();
826 adjdb = circuit->u.bc.adjdb[spftree->level - 1];
827 isis_adj_build_up_list(adjdb, adj_list);
828 if (listcount(adj_list) == 0) {
6a154c88 829 list_delete(&adj_list);
e740f9c1 830 if (IS_DEBUG_SPF_EVENTS)
d62a17ae 831 zlog_debug(
832 "ISIS-Spf: no L%d adjacencies on circuit %s",
833 spftree->level,
834 circuit->interface->name);
835 continue;
836 }
837 for (ALL_LIST_ELEMENTS_RO(adj_list, anode, adj)) {
838 if (!adj_has_mt(adj, spftree->mtid))
839 continue;
840 if (spftree->mtid == ISIS_MT_IPV4_UNICAST
af8ac8f9
CF
841 && !speaks(adj->nlpids.nlpids,
842 adj->nlpids.count,
843 spftree->family))
d62a17ae 844 continue;
845 switch (adj->sys_type) {
846 case ISIS_SYSTYPE_ES:
847 memcpy(lsp_id, adj->sysid,
848 ISIS_SYS_ID_LEN);
849 LSP_PSEUDO_ID(lsp_id) = 0;
850 isis_spf_add_local(
851 spftree, VTYPE_ES, lsp_id, adj,
b30e837b 852 spftree->hopcount_metric ? 1 :
d62a17ae 853 circuit->te_metric
854 [spftree->level - 1],
855 parent);
856 break;
857 case ISIS_SYSTYPE_IS:
858 case ISIS_SYSTYPE_L1_IS:
859 case ISIS_SYSTYPE_L2_IS:
860 memcpy(lsp_id, adj->sysid,
861 ISIS_SYS_ID_LEN);
862 LSP_PSEUDO_ID(lsp_id) = 0;
863 LSP_FRAGMENT(lsp_id) = 0;
864 isis_spf_add_local(
865 spftree,
866 spftree->area->oldmetric
867 ? VTYPE_NONPSEUDO_IS
868 : VTYPE_NONPSEUDO_TE_IS,
869 lsp_id, adj,
b30e837b 870 spftree->hopcount_metric ? 1 :
d62a17ae 871 circuit->te_metric
872 [spftree->level - 1],
873 parent);
874 lsp = lsp_search(
4bef0ec4
DL
875 &spftree->area->lspdb[spftree->level- 1],
876 lsp_id);
d62a17ae 877 if (lsp == NULL
af8ac8f9 878 || lsp->hdr.rem_lifetime == 0)
d62a17ae 879 zlog_warn(
3efd0893 880 "ISIS-Spf: No LSP %s found for IS adjacency L%d on %s (ID %u)",
d62a17ae 881 rawlspid_print(lsp_id),
882 spftree->level,
883 circuit->interface->name,
884 circuit->circuit_id);
885 break;
886 case ISIS_SYSTYPE_UNKNOWN:
887 default:
888 zlog_warn(
0437e105 889 "isis_spf_preload_tent unknown adj type");
d62a17ae 890 }
891 }
6a154c88 892 list_delete(&adj_list);
d62a17ae 893 /*
894 * Add the pseudonode
895 */
896 if (spftree->level == 1)
897 memcpy(lsp_id, circuit->u.bc.l1_desig_is,
898 ISIS_SYS_ID_LEN + 1);
899 else
900 memcpy(lsp_id, circuit->u.bc.l2_desig_is,
901 ISIS_SYS_ID_LEN + 1);
902 /* can happen during DR reboot */
903 if (memcmp(lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1)
904 == 0) {
e740f9c1 905 if (IS_DEBUG_SPF_EVENTS)
d62a17ae 906 zlog_debug(
907 "ISIS-Spf: No L%d DR on %s (ID %d)",
908 spftree->level,
909 circuit->interface->name,
910 circuit->circuit_id);
911 continue;
912 }
913 adj = isis_adj_lookup(lsp_id, adjdb);
914 /* if no adj, we are the dis or error */
915 if (!adj && !circuit->u.bc.is_dr[spftree->level - 1]) {
916 zlog_warn(
3efd0893 917 "ISIS-Spf: No adjacency found from root to L%d DR %s on %s (ID %d)",
d62a17ae 918 spftree->level, rawlspid_print(lsp_id),
919 circuit->interface->name,
920 circuit->circuit_id);
921 continue;
922 }
923 lsp = lsp_search(
4bef0ec4
DL
924 &spftree->area->lspdb[spftree->level - 1],
925 lsp_id);
af8ac8f9 926 if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
d62a17ae 927 zlog_warn(
3efd0893 928 "ISIS-Spf: No lsp (%p) found from root to L%d DR %s on %s (ID %d)",
d62a17ae 929 (void *)lsp, spftree->level,
930 rawlspid_print(lsp_id),
931 circuit->interface->name,
932 circuit->circuit_id);
933 continue;
934 }
b30e837b
CF
935 isis_spf_process_lsp(spftree, lsp,
936 spftree->hopcount_metric ?
937 1 : circuit->te_metric[spftree->level - 1],
938 0, root_sysid, parent);
d62a17ae 939 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
940 adj = circuit->u.p2p.neighbor;
44b89511 941 if (!adj || adj->adj_state != ISIS_ADJ_UP)
d62a17ae 942 continue;
943 if (!adj_has_mt(adj, spftree->mtid))
944 continue;
945 switch (adj->sys_type) {
946 case ISIS_SYSTYPE_ES:
947 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
948 LSP_PSEUDO_ID(lsp_id) = 0;
949 isis_spf_add_local(
950 spftree, VTYPE_ES, lsp_id, adj,
b30e837b 951 spftree->hopcount_metric ? 1 :
d62a17ae 952 circuit->te_metric[spftree->level - 1],
953 parent);
954 break;
955 case ISIS_SYSTYPE_IS:
956 case ISIS_SYSTYPE_L1_IS:
957 case ISIS_SYSTYPE_L2_IS:
958 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
959 LSP_PSEUDO_ID(lsp_id) = 0;
960 LSP_FRAGMENT(lsp_id) = 0;
961 if (spftree->mtid != ISIS_MT_IPV4_UNICAST
af8ac8f9
CF
962 || speaks(adj->nlpids.nlpids,
963 adj->nlpids.count,
964 spftree->family))
d62a17ae 965 isis_spf_add_local(
966 spftree,
967 spftree->area->oldmetric
968 ? VTYPE_NONPSEUDO_IS
969 : VTYPE_NONPSEUDO_TE_IS,
970 lsp_id, adj,
b30e837b 971 spftree->hopcount_metric ? 1 :
d62a17ae 972 circuit->te_metric
973 [spftree->level - 1],
974 parent);
975 break;
976 case ISIS_SYSTYPE_UNKNOWN:
977 default:
978 zlog_warn(
979 "isis_spf_preload_tent unknown adj type");
980 break;
981 }
982 } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
983 continue;
984 } else {
985 zlog_warn("isis_spf_preload_tent unsupported media");
986 retval = ISIS_WARNING;
987 }
f390d2c7 988 }
eb5d44eb 989
d62a17ae 990 return retval;
eb5d44eb 991}
992
993/*
994 * The parent(s) for vertex is set when added to TENT list
995 * now we just put the child pointer(s) in place
996 */
d62a17ae 997static void add_to_paths(struct isis_spftree *spftree,
998 struct isis_vertex *vertex)
eb5d44eb 999{
321c1bbb 1000 char buff[VID2STR_BUFFER];
3f045a08 1001
ae9c9aba 1002 if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type))
d62a17ae 1003 return;
bded4060 1004 isis_vertex_queue_append(&spftree->paths, vertex);
eb5d44eb 1005
f390d2c7 1006#ifdef EXTREME_DEBUG
d62a17ae 1007 zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1008 print_sys_hostname(vertex->N.id), vtype2string(vertex->type),
1009 vid2string(vertex, buff, sizeof(buff)), vertex->depth,
1010 vertex->d_N);
f390d2c7 1011#endif /* EXTREME_DEBUG */
3f045a08 1012
d62a17ae 1013 if (VTYPE_IP(vertex->type)) {
1014 if (listcount(vertex->Adj_N) > 0)
321c1bbb
CF
1015 isis_route_create(&vertex->N.ip.dest,
1016 &vertex->N.ip.src,
d62a17ae 1017 vertex->d_N, vertex->depth,
1018 vertex->Adj_N, spftree->area,
3dace42d 1019 spftree->route_table);
e740f9c1 1020 else if (IS_DEBUG_SPF_EVENTS)
d62a17ae 1021 zlog_debug(
3efd0893 1022 "ISIS-Spf: no adjacencies do not install route for %s depth %d dist %d",
d62a17ae 1023 vid2string(vertex, buff, sizeof(buff)),
1024 vertex->depth, vertex->d_N);
1025 }
1026
1027 return;
eb5d44eb 1028}
1029
d62a17ae 1030static void init_spt(struct isis_spftree *spftree, int mtid, int level,
b30e837b
CF
1031 int family, enum spf_tree_id tree_id,
1032 bool hopcount_metric)
eb5d44eb 1033{
eb919f07
CF
1034 isis_vertex_queue_clear(&spftree->tents);
1035 isis_vertex_queue_clear(&spftree->paths);
d62a17ae 1036
1037 spftree->mtid = mtid;
1038 spftree->level = level;
1039 spftree->family = family;
6d38d078 1040 spftree->tree_id = tree_id;
b30e837b
CF
1041 spftree->hopcount_metric = hopcount_metric;
1042}
1043
1044static void isis_spf_loop(struct isis_spftree *spftree,
1045 uint8_t *root_sysid)
1046{
1047 struct isis_vertex *vertex;
b30e837b
CF
1048 struct isis_lsp *lsp;
1049
1050 while (isis_vertex_queue_count(&spftree->tents)) {
1051 vertex = isis_vertex_queue_pop(&spftree->tents);
1052
1053#ifdef EXTREME_DEBUG
1054 zlog_debug(
1055 "ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1056 print_sys_hostname(vertex->N.id),
1057 vtype2string(vertex->type), vertex->depth, vertex->d_N);
1058#endif /* EXTREME_DEBUG */
1059
1060 add_to_paths(spftree, vertex);
cbd8e49e
CF
1061 if (!VTYPE_IS(vertex->type))
1062 continue;
1063
1064 lsp = lsp_for_vertex(spftree, vertex);
1065 if (!lsp) {
1066 zlog_warn("ISIS-Spf: No LSP found for %s",
883b4b86
A
1067 isis_format_id(vertex->N.id,
1068 sizeof(vertex->N.id)));
cbd8e49e 1069 continue;
b30e837b 1070 }
cbd8e49e
CF
1071
1072 isis_spf_process_lsp(spftree, lsp, vertex->d_N, vertex->depth,
1073 root_sysid, vertex);
b30e837b
CF
1074 }
1075}
1076
1077struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
1078 uint8_t *sysid,
1079 struct isis_spftree *spftree)
1080{
1081 if (!spftree)
1082 spftree = isis_spftree_new(area);
1083
1084 init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2,
1085 AF_INET, SPFTREE_IPV4, true);
1086 if (!memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN)) {
1087 /* If we are running locally, initialize with information from adjacencies */
1088 struct isis_vertex *root = isis_spf_add_root(spftree, sysid);
1089 isis_spf_preload_tent(spftree, sysid, root);
1090 } else {
1091 isis_vertex_queue_insert(&spftree->tents, isis_vertex_new(
686afe9f
CF
1092 spftree, sysid,
1093 VTYPE_NONPSEUDO_TE_IS));
b30e837b
CF
1094 }
1095
1096 isis_spf_loop(spftree, sysid);
1097
1098 return spftree;
eb5d44eb 1099}
1100
6d38d078 1101static int isis_run_spf(struct isis_area *area, int level,
e26e2c15 1102 enum spf_tree_id tree_id, uint8_t *sysid)
eb5d44eb 1103{
d62a17ae 1104 int retval = ISIS_OK;
d62a17ae 1105 struct isis_vertex *root_vertex;
6d38d078 1106 struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
e26e2c15
RW
1107 struct timeval time_start;
1108 struct timeval time_end;
6d38d078 1109 uint16_t mtid = 0;
d62a17ae 1110
1111 /* Get time that can't roll backwards. */
e26e2c15 1112 monotime(&time_start);
d62a17ae 1113
6d38d078
CF
1114 int family = -1;
1115 switch (tree_id) {
1116 case SPFTREE_IPV4:
1117 family = AF_INET;
1118 mtid = ISIS_MT_IPV4_UNICAST;
1119 break;
1120 case SPFTREE_IPV6:
1121 family = AF_INET6;
1122 mtid = isis_area_ipv6_topology(area);
1123 break;
321c1bbb
CF
1124 case SPFTREE_DSTSRC:
1125 family = AF_INET6;
1126 mtid = ISIS_MT_IPV6_DSTSRC;
1127 break;
6d38d078
CF
1128 case SPFTREE_COUNT:
1129 assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!");
1130 return ISIS_WARNING;
1131 }
1132
d62a17ae 1133 assert(spftree);
1134 assert(sysid);
1135
d62a17ae 1136 /*
1137 * C.2.5 Step 0
1138 */
b30e837b 1139 init_spt(spftree, mtid, level, family, tree_id, false);
d62a17ae 1140 /* a) */
1141 root_vertex = isis_spf_add_root(spftree, sysid);
1142 /* b) */
1143 retval = isis_spf_preload_tent(spftree, sysid, root_vertex);
1144 if (retval != ISIS_OK) {
1145 zlog_warn("ISIS-Spf: failed to load TENT SPF-root:%s",
1146 print_sys_hostname(sysid));
1147 goto out;
1148 }
1149
1150 /*
1151 * C.2.7 Step 2
1152 */
ce837d81 1153 if (!isis_vertex_queue_count(&spftree->tents)
e740f9c1 1154 && (IS_DEBUG_SPF_EVENTS)) {
d62a17ae 1155 zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
1156 print_sys_hostname(sysid));
d62a17ae 1157 }
1158
b30e837b 1159 isis_spf_loop(spftree, sysid);
13fb40ac 1160out:
d62a17ae 1161 spftree->runcount++;
1162 spftree->last_run_timestamp = time(NULL);
e26e2c15
RW
1163 spftree->last_run_monotime = monotime(&time_end);
1164 spftree->last_run_duration =
1165 ((time_end.tv_sec - time_start.tv_sec) * 1000000)
1166 + (time_end.tv_usec - time_start.tv_usec);
d62a17ae 1167
1168 return retval;
eb5d44eb 1169}
1170
3dace42d
CF
1171void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
1172{
1173 if (area->is_type == IS_LEVEL_1) {
1174 isis_route_verify_table(area, trees[0]->route_table);
1175 } else if (area->is_type == IS_LEVEL_2) {
1176 isis_route_verify_table(area, trees[1]->route_table);
1177 } else {
1178 isis_route_verify_merge(area, trees[0]->route_table,
1179 trees[1]->route_table);
1180 }
1181}
1182
1183void isis_spf_invalidate_routes(struct isis_spftree *tree)
1184{
1185 isis_route_invalidate_table(tree->area, tree->route_table);
1186}
1187
d62a17ae 1188static int isis_run_spf_cb(struct thread *thread)
eb5d44eb 1189{
d62a17ae 1190 struct isis_spf_run *run = THREAD_ARG(thread);
1191 struct isis_area *area = run->area;
1192 int level = run->level;
1193 int retval = ISIS_OK;
1194
1195 XFREE(MTYPE_ISIS_SPF_RUN, run);
1196 area->spf_timer[level - 1] = NULL;
1197
1198 if (!(area->is_type & level)) {
e740f9c1 1199 if (IS_DEBUG_SPF_EVENTS)
d62a17ae 1200 zlog_warn("ISIS-SPF (%s) area does not share level",
1201 area->area_tag);
1202 return ISIS_WARNING;
1203 }
eb5d44eb 1204
3dace42d
CF
1205 isis_area_invalidate_routes(area, level);
1206
e740f9c1 1207 if (IS_DEBUG_SPF_EVENTS)
d62a17ae 1208 zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
1209 area->area_tag, level);
f390d2c7 1210
d62a17ae 1211 if (area->ip_circuits)
e26e2c15 1212 retval = isis_run_spf(area, level, SPFTREE_IPV4, isis->sysid);
d62a17ae 1213 if (area->ipv6_circuits)
e26e2c15
RW
1214 retval = isis_run_spf(area, level, SPFTREE_IPV6, isis->sysid);
1215 if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
1216 retval = isis_run_spf(area, level, SPFTREE_DSTSRC, isis->sysid);
eb5d44eb 1217
3dace42d
CF
1218 isis_area_verify_routes(area);
1219
26f6acaf
RW
1220 isis_area_verify_sr(area);
1221
3dace42d
CF
1222 /* walk all circuits and reset any spf specific flags */
1223 struct listnode *node;
1224 struct isis_circuit *circuit;
1225 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
1226 UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
1227
b30e837b
CF
1228 fabricd_run_spf(area);
1229
d62a17ae 1230 return retval;
eb5d44eb 1231}
1232
d62a17ae 1233static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
eb5d44eb 1234{
d62a17ae 1235 struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
1236
1237 run->area = area;
1238 run->level = level;
1239
1240 return run;
eb5d44eb 1241}
eb5d44eb 1242
d62db30d
CF
1243int _isis_spf_schedule(struct isis_area *area, int level,
1244 const char *func, const char *file, int line)
eb5d44eb 1245{
be985ba0 1246 struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
3dca3c8c
CF
1247 time_t now = monotime(NULL);
1248 int diff = now - spftree->last_run_monotime;
d62a17ae 1249
1250 assert(diff >= 0);
1251 assert(area->is_type & level);
1252
e740f9c1 1253 if (IS_DEBUG_SPF_EVENTS) {
d62a17ae 1254 zlog_debug(
3efd0893 1255 "ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago Caller: %s %s:%d",
d62db30d
CF
1256 area->area_tag, level, diff, func, file, line);
1257 }
d62a17ae 1258
1259 if (area->spf_delay_ietf[level - 1]) {
1260 /* Need to call schedule function also if spf delay is running
1261 * to
1262 * restart holdoff timer - compare
1263 * draft-ietf-rtgwg-backoff-algo-04 */
1264 long delay =
1265 spf_backoff_schedule(area->spf_delay_ietf[level - 1]);
1266 if (area->spf_timer[level - 1])
1267 return ISIS_OK;
1268
1269 thread_add_timer_msec(master, isis_run_spf_cb,
1270 isis_run_spf_arg(area, level), delay,
1271 &area->spf_timer[level - 1]);
1272 return ISIS_OK;
3f045a08 1273 }
d62a17ae 1274
1275 if (area->spf_timer[level - 1])
1276 return ISIS_OK;
1277
1278 /* wait configured min_spf_interval before doing the SPF */
3dca3c8c 1279 long timer;
690497fb
G
1280 if (diff >= area->min_spf_interval[level - 1]
1281 || area->bfd_force_spf_refresh) {
1282 /*
1283 * Last run is more than min interval ago or BFD signalled a
1284 * 'down' message, schedule immediate run
1285 */
3dca3c8c 1286 timer = 0;
690497fb
G
1287
1288 if (area->bfd_force_spf_refresh) {
1289 zlog_debug(
1290 "ISIS-Spf (%s) L%d SPF scheduled immediately due to BFD 'down' message",
1291 area->area_tag, level);
1292 area->bfd_force_spf_refresh = false;
1293 }
3dca3c8c
CF
1294 } else {
1295 timer = area->min_spf_interval[level - 1] - diff;
f390d2c7 1296 }
3f045a08 1297
d62a17ae 1298 thread_add_timer(master, isis_run_spf_cb, isis_run_spf_arg(area, level),
3dca3c8c 1299 timer, &area->spf_timer[level - 1]);
d62a17ae 1300
e740f9c1 1301 if (IS_DEBUG_SPF_EVENTS)
013b29d7
RZ
1302 zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %ld sec from now",
1303 area->area_tag, level, timer);
d62a17ae 1304
1305 return ISIS_OK;
1306}
1307
eb919f07 1308static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
d7c0a89a 1309 uint8_t *root_sysid)
d62a17ae 1310{
1311 struct listnode *node;
d62a17ae 1312 struct isis_vertex *vertex;
321c1bbb 1313 char buff[VID2STR_BUFFER];
d62a17ae 1314
1315 vty_out(vty,
1316 "Vertex Type Metric Next-Hop Interface Parent\n");
1317
eb919f07 1318 for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
d62a17ae 1319 if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
1320 vty_out(vty, "%-20s %-12s %-6s",
1321 print_sys_hostname(root_sysid), "", "");
af88c591
CF
1322 vty_out(vty, "%-30s\n", "");
1323 continue;
d62a17ae 1324 }
1325
af88c591
CF
1326 int rows = 0;
1327 struct listnode *anode = listhead(vertex->Adj_N);
1328 struct listnode *pnode = listhead(vertex->parents);
1329 struct isis_adjacency *adj;
1330 struct isis_vertex *pvertex;
1331
1332 vty_out(vty, "%-20s %-12s %-6u ",
1333 vid2string(vertex, buff, sizeof(buff)),
1334 vtype2string(vertex->type), vertex->d_N);
1230a82d
A
1335 for (unsigned int i = 0;
1336 i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0,
1337 vertex->parents ? listcount(vertex->parents) : 0);
996c9314 1338 i++) {
af88c591
CF
1339 if (anode) {
1340 adj = listgetdata(anode);
1341 anode = anode->next;
1342 } else {
1343 adj = NULL;
1344 }
1345
1346 if (pnode) {
1347 pvertex = listgetdata(pnode);
1348 pnode = pnode->next;
1349 } else {
1350 pvertex = NULL;
1351 }
1352
1353 if (rows) {
1354 vty_out(vty, "\n");
1355 vty_out(vty, "%-20s %-12s %-6s ", "", "", "");
1356 }
1357
1358 if (adj) {
1359 vty_out(vty, "%-20s %-9s ",
1360 print_sys_hostname(adj->sysid),
1361 adj->circuit->interface->name);
1362 }
1363
1364 if (pvertex) {
1365 if (!adj)
1366 vty_out(vty, "%-20s %-9s ", "", "");
1367
d62a17ae 1368 vty_out(vty, "%s(%d)",
996c9314 1369 vid2string(pvertex, buff, sizeof(buff)),
d62a17ae 1370 pvertex->type);
d62a17ae 1371 }
d62a17ae 1372
af88c591
CF
1373 ++rows;
1374 }
d62a17ae 1375 vty_out(vty, "\n");
1376 }
eb5d44eb 1377}
1378
321c1bbb
CF
1379static void isis_print_spftree(struct vty *vty, int level,
1380 struct isis_area *area,
1381 enum spf_tree_id tree_id)
1382{
1383 const char *tree_id_text = NULL;
1384
1385 switch (tree_id) {
1386 case SPFTREE_IPV4:
1387 tree_id_text = "that speak IP";
1388 break;
1389 case SPFTREE_IPV6:
1390 tree_id_text = "that speak IPv6";
1391 break;
1392 case SPFTREE_DSTSRC:
1393 tree_id_text = "that support IPv6 dst-src routing";
1394 break;
1395 case SPFTREE_COUNT:
1396 assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type");
1397 return;
1398 }
1399
1400 if (!area->spftree[tree_id][level - 1]
1401 || !isis_vertex_queue_count(
1402 &area->spftree[tree_id][level - 1]->paths))
1403 return;
1404
1405 vty_out(vty, "IS-IS paths to level-%d routers %s\n",
1406 level, tree_id_text);
1407 isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths,
1408 isis->sysid);
1409 vty_out(vty, "\n");
1410}
1411
eb5d44eb 1412DEFUN (show_isis_topology,
1413 show_isis_topology_cmd,
ef020087
CF
1414 "show " PROTO_NAME " topology"
1415#ifndef FABRICD
1416 " [<level-1|level-2>]"
1417#endif
1418 , SHOW_STR
7c0cbd0e 1419 PROTO_HELP
1b49e4f0 1420 "IS-IS paths to Intermediate Systems\n"
ef020087 1421#ifndef FABRICD
1b49e4f0 1422 "Paths to all level-1 routers in the area\n"
ef020087
CF
1423 "Paths to all level-2 routers in the domain\n"
1424#endif
1425 )
eb5d44eb 1426{
d62a17ae 1427 int levels;
1428 struct listnode *node;
1429 struct isis_area *area;
1430
1431 if (argc < 4)
1432 levels = ISIS_LEVEL1 | ISIS_LEVEL2;
1433 else if (strmatch(argv[3]->text, "level-1"))
1434 levels = ISIS_LEVEL1;
1435 else
1436 levels = ISIS_LEVEL2;
1437
1438 if (!isis->area_list || isis->area_list->count == 0)
1439 return CMD_SUCCESS;
1440
1441 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
1442 vty_out(vty, "Area %s:\n",
1443 area->area_tag ? area->area_tag : "null");
1444
1445 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
1446 if ((level & levels) == 0)
1447 continue;
1448
321c1bbb
CF
1449 if (area->ip_circuits > 0) {
1450 isis_print_spftree(vty, level, area,
1451 SPFTREE_IPV4);
d62a17ae 1452 }
321c1bbb
CF
1453 if (area->ipv6_circuits > 0) {
1454 isis_print_spftree(vty, level, area,
1455 SPFTREE_IPV6);
1456 }
1457 if (isis_area_ipv6_dstsrc_enabled(area)) {
1458 isis_print_spftree(vty, level, area,
1459 SPFTREE_DSTSRC);
d62a17ae 1460 }
1461 }
f390d2c7 1462
b30e837b
CF
1463 if (fabricd_spftree(area)) {
1464 vty_out(vty,
1465 "IS-IS paths to level-2 routers with hop-by-hop metric\n");
1466 isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid);
1467 vty_out(vty, "\n");
1468 }
1469
d62a17ae 1470 vty_out(vty, "\n");
f390d2c7 1471 }
3f045a08 1472
d62a17ae 1473 return CMD_SUCCESS;
f390d2c7 1474}
eb5d44eb 1475
4d762f26 1476void isis_spf_cmds_init(void)
eb5d44eb 1477{
d62a17ae 1478 install_element(VIEW_NODE, &show_isis_topology_cmd);
eb5d44eb 1479}
02cd317e
CF
1480
1481void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
1482{
1483 vty_out(vty, " last run elapsed : ");
1484 vty_out_timestr(vty, spftree->last_run_timestamp);
1485 vty_out(vty, "\n");
1486
1487 vty_out(vty, " last run duration : %u usec\n",
d7c0a89a 1488 (uint32_t)spftree->last_run_duration);
02cd317e 1489
996c9314 1490 vty_out(vty, " run count : %u\n", spftree->runcount);
02cd317e 1491}