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