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