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