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