]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_spf.c
tools, doc: update checkpatch for u_int_*
[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 */
80struct isis_vertex {
81 enum vertextype type;
82
83 union {
84 u_char id[ISIS_SYS_ID_LEN + 1];
85 struct prefix prefix;
86 } N;
87
98c5bc15
CF
88 u_int32_t d_N; /* d(N) Distance from this IS */
89 u_int16_t depth; /* The depth in the imaginary tree */
90 struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
91 struct list *parents; /* list of parents for ECMP */
bded4060 92 uint64_t insert_counter;
02cd317e
CF
93};
94
eb919f07
CF
95/* Vertex Queue and associated functions */
96
97struct isis_vertex_queue {
bded4060
CF
98 union {
99 struct skiplist *slist;
100 struct list *list;
101 } l;
eb919f07 102 struct hash *hash;
bded4060 103 uint64_t insert_counter;
eb919f07
CF
104};
105
106static unsigned isis_vertex_queue_hash_key(void *vp)
107{
108 struct isis_vertex *vertex = vp;
109
110 if (VTYPE_IP(vertex->type))
111 return prefix_hash_key(&vertex->N.prefix);
112
113 return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
114}
115
116static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
117{
118 const struct isis_vertex *va = a, *vb = b;
119
120 if (va->type != vb->type)
121 return 0;
122
123 if (VTYPE_IP(va->type))
124 return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0;
125
126 return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
127}
128
bded4060
CF
129/*
130 * Compares vertizes for sorting in the TENT list. Returns true
131 * if candidate should be considered before current, false otherwise.
132 */
133static int isis_vertex_queue_tent_cmp(void *a, void *b)
134{
135 struct isis_vertex *va = a;
136 struct isis_vertex *vb = b;
137
138 if (va->d_N < vb->d_N)
139 return -1;
140
141 if (va->d_N > vb->d_N)
142 return 1;
143
144 if (va->type < vb->type)
145 return -1;
146
147 if (va->type > vb->type)
148 return 1;
149
150 if (va->insert_counter < vb->insert_counter)
151 return -1;
152
153 if (va->insert_counter > vb->insert_counter)
154 return 1;
155
60d39142 156 return 0;
bded4060
CF
157}
158
159static struct skiplist *isis_vertex_queue_skiplist(void)
160{
161 return skiplist_new(0, isis_vertex_queue_tent_cmp, NULL);
162}
163
996c9314
LB
164static void isis_vertex_queue_init(struct isis_vertex_queue *queue,
165 const char *name, bool ordered)
eb919f07 166{
bded4060
CF
167 if (ordered) {
168 queue->insert_counter = 1;
169 queue->l.slist = isis_vertex_queue_skiplist();
170 } else {
171 queue->insert_counter = 0;
172 queue->l.list = list_new();
173 }
eb919f07 174 queue->hash = hash_create(isis_vertex_queue_hash_key,
996c9314 175 isis_vertex_queue_hash_cmp, name);
eb919f07
CF
176}
177
178static void isis_vertex_del(struct isis_vertex *vertex);
179
180static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
181{
182 hash_clean(queue->hash, NULL);
183
bded4060
CF
184 if (queue->insert_counter) {
185 struct isis_vertex *vertex;
996c9314
LB
186 while (0 == skiplist_first(queue->l.slist, NULL,
187 (void **)&vertex)) {
bded4060
CF
188 isis_vertex_del(vertex);
189 skiplist_delete_first(queue->l.slist);
190 }
191 queue->insert_counter = 1;
192 } else {
193 queue->l.list->del = (void (*)(void *))isis_vertex_del;
194 list_delete_all_node(queue->l.list);
195 queue->l.list->del = NULL;
196 }
eb919f07
CF
197}
198
199static void isis_vertex_queue_free(struct isis_vertex_queue *queue)
200{
201 isis_vertex_queue_clear(queue);
202
203 hash_free(queue->hash);
204 queue->hash = NULL;
205
bded4060
CF
206 if (queue->insert_counter) {
207 skiplist_free(queue->l.slist);
208 queue->l.slist = NULL;
affe9e99
DS
209 } else
210 list_delete_and_null(&queue->l.list);
eb919f07
CF
211}
212
213static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue)
214{
bded4060 215 return hashcount(queue->hash);
eb919f07
CF
216}
217
bded4060
CF
218static void isis_vertex_queue_append(struct isis_vertex_queue *queue,
219 struct isis_vertex *vertex)
eb919f07 220{
bded4060
CF
221 assert(!queue->insert_counter);
222
223 listnode_add(queue->l.list, vertex);
eb919f07
CF
224
225 struct isis_vertex *inserted;
226
227 inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
228 assert(inserted == vertex);
229}
230
bded4060
CF
231static void isis_vertex_queue_insert(struct isis_vertex_queue *queue,
232 struct isis_vertex *vertex)
233{
234 assert(queue->insert_counter);
235 vertex->insert_counter = queue->insert_counter++;
236 assert(queue->insert_counter != (uint64_t)-1);
237
238 skiplist_insert(queue->l.slist, vertex, vertex);
239
240 struct isis_vertex *inserted;
241 inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
242 assert(inserted == vertex);
243}
244
996c9314
LB
245static struct isis_vertex *
246isis_vertex_queue_pop(struct isis_vertex_queue *queue)
eb919f07 247{
bded4060 248 assert(queue->insert_counter);
eb919f07 249
bded4060 250 struct isis_vertex *rv;
eb919f07 251
996c9314 252 if (skiplist_first(queue->l.slist, NULL, (void **)&rv))
bded4060 253 return NULL;
eb919f07 254
bded4060 255 skiplist_delete_first(queue->l.slist);
eb919f07
CF
256 hash_release(queue->hash, rv);
257
258 return rv;
259}
260
261static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
262 struct isis_vertex *vertex)
263{
bded4060
CF
264 assert(queue->insert_counter);
265
266 skiplist_delete(queue->l.slist, vertex, vertex);
eb919f07
CF
267 hash_release(queue->hash, vertex);
268}
269
996c9314
LB
270#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \
271 ALL_LIST_ELEMENTS_RO((queue)->l.list, node, data)
eb919f07
CF
272
273
274/* End of vertex queue definitions */
275
02cd317e 276struct isis_spftree {
eb919f07
CF
277 struct isis_vertex_queue paths; /* the SPT */
278 struct isis_vertex_queue tents; /* TENT */
98c5bc15
CF
279 struct isis_area *area; /* back pointer to area */
280 unsigned int runcount; /* number of runs since uptime */
281 time_t last_run_timestamp; /* last run timestamp as wall time for display */
282 time_t last_run_monotime; /* last run as monotime for scheduling */
283 time_t last_run_duration; /* last run duration in msec */
02cd317e
CF
284
285 uint16_t mtid;
286 int family;
287 int level;
288};
289
290
af8ac8f9
CF
291/*
292 * supports the given af ?
293 */
294static bool speaks(uint8_t *protocols, uint8_t count, int family)
295{
296 for (uint8_t i = 0; i < count; i++) {
297 if (family == AF_INET && protocols[i] == NLPID_IP)
298 return true;
299 if (family == AF_INET6 && protocols[i] == NLPID_IPV6)
300 return true;
301 }
302 return false;
303}
304
1b49e4f0 305struct isis_spf_run {
d62a17ae 306 struct isis_area *area;
307 int level;
1b49e4f0
CF
308};
309
eb5d44eb 310/* 7.2.7 */
d62a17ae 311static void remove_excess_adjs(struct list *adjs)
eb5d44eb 312{
d62a17ae 313 struct listnode *node, *excess = NULL;
314 struct isis_adjacency *adj, *candidate = NULL;
315 int comp;
316
317 for (ALL_LIST_ELEMENTS_RO(adjs, node, adj)) {
318 if (excess == NULL)
319 excess = node;
320 candidate = listgetdata(excess);
321
322 if (candidate->sys_type < adj->sys_type) {
323 excess = node;
324 continue;
325 }
326 if (candidate->sys_type > adj->sys_type)
327 continue;
f390d2c7 328
d62a17ae 329 comp = memcmp(candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
330 if (comp > 0) {
331 excess = node;
332 continue;
333 }
334 if (comp < 0)
335 continue;
eb5d44eb 336
0849c75e 337 if (candidate->circuit->idx > adj->circuit->idx) {
d62a17ae 338 excess = node;
339 continue;
340 }
f390d2c7 341
0849c75e 342 if (candidate->circuit->idx < adj->circuit->idx)
d62a17ae 343 continue;
f390d2c7 344
d62a17ae 345 comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN);
346 if (comp > 0) {
347 excess = node;
348 continue;
349 }
f390d2c7 350 }
f390d2c7 351
d62a17ae 352 list_delete_node(adjs, excess);
eb5d44eb 353
d62a17ae 354 return;
eb5d44eb 355}
356
d62a17ae 357static const char *vtype2string(enum vertextype vtype)
eb5d44eb 358{
d62a17ae 359 switch (vtype) {
360 case VTYPE_PSEUDO_IS:
361 return "pseudo_IS";
362 break;
363 case VTYPE_PSEUDO_TE_IS:
364 return "pseudo_TE-IS";
365 break;
366 case VTYPE_NONPSEUDO_IS:
367 return "IS";
368 break;
369 case VTYPE_NONPSEUDO_TE_IS:
370 return "TE-IS";
371 break;
372 case VTYPE_ES:
373 return "ES";
374 break;
375 case VTYPE_IPREACH_INTERNAL:
376 return "IP internal";
377 break;
378 case VTYPE_IPREACH_EXTERNAL:
379 return "IP external";
380 break;
381 case VTYPE_IPREACH_TE:
382 return "IP TE";
383 break;
384 case VTYPE_IP6REACH_INTERNAL:
385 return "IP6 internal";
386 break;
387 case VTYPE_IP6REACH_EXTERNAL:
388 return "IP6 external";
389 break;
390 default:
391 return "UNKNOWN";
392 }
393 return NULL; /* Not reached */
eb5d44eb 394}
395
d62a17ae 396static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
eb5d44eb 397{
d62a17ae 398 if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
399 return print_sys_hostname(vertex->N.id);
400 }
401
402 if (VTYPE_IP(vertex->type)) {
403 prefix2str((struct prefix *)&vertex->N.prefix, buff, size);
404 return buff;
405 }
406
407 return "UNKNOWN";
eb5d44eb 408}
409
996c9314
LB
410static void isis_vertex_id_init(struct isis_vertex *vertex, void *id,
411 enum vertextype vtype)
eb5d44eb 412{
d62a17ae 413 vertex->type = vtype;
414
415 if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
416 memcpy(vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN + 1);
417 } else if (VTYPE_IP(vtype)) {
418 memcpy(&vertex->N.prefix, (struct prefix *)id,
419 sizeof(struct prefix));
420 } else {
421 zlog_err("WTF!");
422 }
eb919f07
CF
423}
424
425static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
426{
427 struct isis_vertex *vertex;
428
429 vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
430
431 isis_vertex_id_init(vertex, id, vtype);
d62a17ae 432
433 vertex->Adj_N = list_new();
434 vertex->parents = list_new();
d62a17ae 435
436 return vertex;
eb5d44eb 437}
438
d62a17ae 439static void isis_vertex_del(struct isis_vertex *vertex)
eb5d44eb 440{
affe9e99
DS
441 list_delete_and_null(&vertex->Adj_N);
442 list_delete_and_null(&vertex->parents);
eb5d44eb 443
d62a17ae 444 memset(vertex, 0, sizeof(struct isis_vertex));
445 XFREE(MTYPE_ISIS_VERTEX, vertex);
f390d2c7 446
d62a17ae 447 return;
eb5d44eb 448}
449
d62a17ae 450static void isis_vertex_adj_del(struct isis_vertex *vertex,
451 struct isis_adjacency *adj)
3f045a08 452{
d62a17ae 453 struct listnode *node, *nextnode;
454 if (!vertex)
455 return;
456 for (node = listhead(vertex->Adj_N); node; node = nextnode) {
457 nextnode = listnextnode(node);
458 if (listgetdata(node) == adj)
459 list_delete_node(vertex->Adj_N, node);
460 }
461 return;
3f045a08
JB
462}
463
d62a17ae 464struct isis_spftree *isis_spftree_new(struct isis_area *area)
3f045a08 465{
d62a17ae 466 struct isis_spftree *tree;
467
468 tree = XCALLOC(MTYPE_ISIS_SPFTREE, sizeof(struct isis_spftree));
469 if (tree == NULL) {
470 zlog_err("ISIS-Spf: isis_spftree_new Out of memory!");
471 return NULL;
472 }
473
bded4060
CF
474 isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
475 isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
d62a17ae 476 tree->area = area;
477 tree->last_run_timestamp = 0;
3dca3c8c 478 tree->last_run_monotime = 0;
d62a17ae 479 tree->last_run_duration = 0;
480 tree->runcount = 0;
481 return tree;
3f045a08
JB
482}
483
d62a17ae 484void isis_spftree_del(struct isis_spftree *spftree)
eb5d44eb 485{
eb919f07
CF
486 isis_vertex_queue_free(&spftree->tents);
487 isis_vertex_queue_free(&spftree->paths);
d62a17ae 488 XFREE(MTYPE_ISIS_SPFTREE, spftree);
eb5d44eb 489
d62a17ae 490 return;
eb5d44eb 491}
3f045a08 492
d62a17ae 493static void isis_spftree_adj_del(struct isis_spftree *spftree,
494 struct isis_adjacency *adj)
3f045a08 495{
d62a17ae 496 struct listnode *node;
eb919f07 497 struct isis_vertex *v;
d62a17ae 498 if (!adj)
499 return;
bded4060 500 assert(!isis_vertex_queue_count(&spftree->tents));
eb919f07
CF
501 for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v))
502 isis_vertex_adj_del(v, adj);
d62a17ae 503 return;
3f045a08 504}
eb5d44eb 505
d62a17ae 506void spftree_area_init(struct isis_area *area)
eb5d44eb 507{
d62a17ae 508 if (area->is_type & IS_LEVEL_1) {
509 if (area->spftree[0] == NULL)
510 area->spftree[0] = isis_spftree_new(area);
511 if (area->spftree6[0] == NULL)
512 area->spftree6[0] = isis_spftree_new(area);
513 }
514
515 if (area->is_type & IS_LEVEL_2) {
516 if (area->spftree[1] == NULL)
517 area->spftree[1] = isis_spftree_new(area);
518 if (area->spftree6[1] == NULL)
519 area->spftree6[1] = isis_spftree_new(area);
520 }
521
522 return;
eb5d44eb 523}
524
d62a17ae 525void spftree_area_del(struct isis_area *area)
eb5d44eb 526{
d62a17ae 527 if (area->is_type & IS_LEVEL_1) {
528 if (area->spftree[0] != NULL) {
529 isis_spftree_del(area->spftree[0]);
530 area->spftree[0] = NULL;
531 }
532 if (area->spftree6[0]) {
533 isis_spftree_del(area->spftree6[0]);
534 area->spftree6[0] = NULL;
535 }
536 }
537
538 if (area->is_type & IS_LEVEL_2) {
539 if (area->spftree[1] != NULL) {
540 isis_spftree_del(area->spftree[1]);
541 area->spftree[1] = NULL;
542 }
543 if (area->spftree6[1] != NULL) {
544 isis_spftree_del(area->spftree6[1]);
545 area->spftree6[1] = NULL;
546 }
547 }
548
549 return;
3f045a08 550}
f390d2c7 551
d62a17ae 552void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
3f045a08 553{
d62a17ae 554 if (area->is_type & IS_LEVEL_1) {
555 if (area->spftree[0] != NULL)
556 isis_spftree_adj_del(area->spftree[0], adj);
557 if (area->spftree6[0] != NULL)
558 isis_spftree_adj_del(area->spftree6[0], adj);
559 }
560
561 if (area->is_type & IS_LEVEL_2) {
562 if (area->spftree[1] != NULL)
563 isis_spftree_adj_del(area->spftree[1], adj);
564 if (area->spftree6[1] != NULL)
565 isis_spftree_adj_del(area->spftree6[1], adj);
566 }
567
568 return;
3f045a08
JB
569}
570
d62a17ae 571/*
572 * Find the system LSP: returns the LSP in our LSP database
3f045a08
JB
573 * associated with the given system ID.
574 */
d62a17ae 575static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
576 u_char *sysid)
3f045a08 577{
d62a17ae 578 struct isis_lsp *lsp;
579 u_char lspid[ISIS_SYS_ID_LEN + 2];
580
581 memcpy(lspid, sysid, ISIS_SYS_ID_LEN);
582 LSP_PSEUDO_ID(lspid) = 0;
583 LSP_FRAGMENT(lspid) = 0;
584 lsp = lsp_search(lspid, area->lspdb[level - 1]);
af8ac8f9 585 if (lsp && lsp->hdr.rem_lifetime != 0)
d62a17ae 586 return lsp;
587 return NULL;
eb5d44eb 588}
589
590/*
591 * Add this IS to the root of SPT
592 */
d62a17ae 593static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
594 u_char *sysid)
eb5d44eb 595{
d62a17ae 596 struct isis_vertex *vertex;
597 struct isis_lsp *lsp;
eb5d44eb 598#ifdef EXTREME_DEBUG
d62a17ae 599 char buff[PREFIX2STR_BUFFER];
eb5d44eb 600#endif /* EXTREME_DEBUG */
d62a17ae 601 u_char id[ISIS_SYS_ID_LEN + 1];
f390d2c7 602
d62a17ae 603 memcpy(id, sysid, ISIS_SYS_ID_LEN);
604 LSP_PSEUDO_ID(id) = 0;
f390d2c7 605
d62a17ae 606 lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
607 if (lsp == NULL)
608 zlog_warn("ISIS-Spf: could not find own l%d LSP!",
609 spftree->level);
eb5d44eb 610
9d303b37
DL
611 vertex = isis_vertex_new(id,
612 spftree->area->oldmetric
613 ? VTYPE_NONPSEUDO_IS
614 : VTYPE_NONPSEUDO_TE_IS);
bded4060 615 isis_vertex_queue_append(&spftree->paths, vertex);
eb5d44eb 616
617#ifdef EXTREME_DEBUG
d62a17ae 618 zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
619 vtype2string(vertex->type),
620 vid2string(vertex, buff, sizeof(buff)), vertex->depth,
621 vertex->d_N);
eb5d44eb 622#endif /* EXTREME_DEBUG */
623
d62a17ae 624 return vertex;
eb5d44eb 625}
626
996c9314
LB
627static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue,
628 void *id, enum vertextype vtype)
eb5d44eb 629{
eb919f07 630 struct isis_vertex querier;
d62a17ae 631
eb919f07
CF
632 isis_vertex_id_init(&querier, id, vtype);
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,
808 uint16_t depth, u_char *root_sysid,
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;
d62a17ae 815 static const u_char 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,
976 u_char *root_sysid, struct isis_vertex *parent)
977{
978 struct isis_circuit *circuit;
979 struct listnode *cnode, *anode, *ipnode;
980 struct isis_adjacency *adj;
981 struct isis_lsp *lsp;
982 struct list *adj_list;
983 struct list *adjdb;
984 struct prefix_ipv4 *ipv4;
985 struct prefix prefix;
986 int retval = ISIS_OK;
987 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
988 static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
989 struct prefix_ipv6 *ipv6;
990 struct isis_circuit_mt_setting *circuit_mt;
991
992 for (ALL_LIST_ELEMENTS_RO(spftree->area->circuit_list, cnode,
993 circuit)) {
994 circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
995 if (circuit_mt && !circuit_mt->enabled)
996 continue;
997 if (circuit->state != C_STATE_UP)
998 continue;
999 if (!(circuit->is_type & spftree->level))
1000 continue;
1001 if (spftree->family == AF_INET && !circuit->ip_router)
1002 continue;
1003 if (spftree->family == AF_INET6 && !circuit->ipv6_router)
1004 continue;
1005 /*
1006 * Add IP(v6) addresses of this circuit
1007 */
1008 if (spftree->family == AF_INET) {
1009 prefix.family = AF_INET;
1010 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
1011 ipv4)) {
1012 prefix.u.prefix4 = ipv4->prefix;
1013 prefix.prefixlen = ipv4->prefixlen;
1014 apply_mask(&prefix);
1015 isis_spf_add_local(spftree,
1016 VTYPE_IPREACH_INTERNAL,
1017 &prefix, NULL, 0, parent);
1018 }
1019 }
1020 if (spftree->family == AF_INET6) {
1021 prefix.family = AF_INET6;
1022 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1023 ipnode, ipv6)) {
1024 prefix.prefixlen = ipv6->prefixlen;
1025 prefix.u.prefix6 = ipv6->prefix;
1026 apply_mask(&prefix);
1027 isis_spf_add_local(spftree,
1028 VTYPE_IP6REACH_INTERNAL,
1029 &prefix, NULL, 0, parent);
1030 }
1031 }
1032 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
1033 /*
1034 * Add the adjacencies
1035 */
1036 adj_list = list_new();
1037 adjdb = circuit->u.bc.adjdb[spftree->level - 1];
1038 isis_adj_build_up_list(adjdb, adj_list);
1039 if (listcount(adj_list) == 0) {
affe9e99 1040 list_delete_and_null(&adj_list);
d62a17ae 1041 if (isis->debugs & DEBUG_SPF_EVENTS)
1042 zlog_debug(
1043 "ISIS-Spf: no L%d adjacencies on circuit %s",
1044 spftree->level,
1045 circuit->interface->name);
1046 continue;
1047 }
1048 for (ALL_LIST_ELEMENTS_RO(adj_list, anode, adj)) {
1049 if (!adj_has_mt(adj, spftree->mtid))
1050 continue;
1051 if (spftree->mtid == ISIS_MT_IPV4_UNICAST
af8ac8f9
CF
1052 && !speaks(adj->nlpids.nlpids,
1053 adj->nlpids.count,
1054 spftree->family))
d62a17ae 1055 continue;
1056 switch (adj->sys_type) {
1057 case ISIS_SYSTYPE_ES:
1058 memcpy(lsp_id, adj->sysid,
1059 ISIS_SYS_ID_LEN);
1060 LSP_PSEUDO_ID(lsp_id) = 0;
1061 isis_spf_add_local(
1062 spftree, VTYPE_ES, lsp_id, adj,
1063 circuit->te_metric
1064 [spftree->level - 1],
1065 parent);
1066 break;
1067 case ISIS_SYSTYPE_IS:
1068 case ISIS_SYSTYPE_L1_IS:
1069 case ISIS_SYSTYPE_L2_IS:
1070 memcpy(lsp_id, adj->sysid,
1071 ISIS_SYS_ID_LEN);
1072 LSP_PSEUDO_ID(lsp_id) = 0;
1073 LSP_FRAGMENT(lsp_id) = 0;
1074 isis_spf_add_local(
1075 spftree,
1076 spftree->area->oldmetric
1077 ? VTYPE_NONPSEUDO_IS
1078 : VTYPE_NONPSEUDO_TE_IS,
1079 lsp_id, adj,
1080 circuit->te_metric
1081 [spftree->level - 1],
1082 parent);
1083 lsp = lsp_search(
1084 lsp_id,
1085 spftree->area
1086 ->lspdb[spftree->level
1087 - 1]);
1088 if (lsp == NULL
af8ac8f9 1089 || lsp->hdr.rem_lifetime == 0)
d62a17ae 1090 zlog_warn(
1091 "ISIS-Spf: No LSP %s found for IS adjacency "
1092 "L%d on %s (ID %u)",
1093 rawlspid_print(lsp_id),
1094 spftree->level,
1095 circuit->interface->name,
1096 circuit->circuit_id);
1097 break;
1098 case ISIS_SYSTYPE_UNKNOWN:
1099 default:
1100 zlog_warn(
1101 "isis_spf_preload_tent unknow adj type");
1102 }
1103 }
affe9e99 1104 list_delete_and_null(&adj_list);
d62a17ae 1105 /*
1106 * Add the pseudonode
1107 */
1108 if (spftree->level == 1)
1109 memcpy(lsp_id, circuit->u.bc.l1_desig_is,
1110 ISIS_SYS_ID_LEN + 1);
1111 else
1112 memcpy(lsp_id, circuit->u.bc.l2_desig_is,
1113 ISIS_SYS_ID_LEN + 1);
1114 /* can happen during DR reboot */
1115 if (memcmp(lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1)
1116 == 0) {
1117 if (isis->debugs & DEBUG_SPF_EVENTS)
1118 zlog_debug(
1119 "ISIS-Spf: No L%d DR on %s (ID %d)",
1120 spftree->level,
1121 circuit->interface->name,
1122 circuit->circuit_id);
1123 continue;
1124 }
1125 adj = isis_adj_lookup(lsp_id, adjdb);
1126 /* if no adj, we are the dis or error */
1127 if (!adj && !circuit->u.bc.is_dr[spftree->level - 1]) {
1128 zlog_warn(
1129 "ISIS-Spf: No adjacency found from root "
1130 "to L%d DR %s on %s (ID %d)",
1131 spftree->level, rawlspid_print(lsp_id),
1132 circuit->interface->name,
1133 circuit->circuit_id);
1134 continue;
1135 }
1136 lsp = lsp_search(
1137 lsp_id,
1138 spftree->area->lspdb[spftree->level - 1]);
af8ac8f9 1139 if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
d62a17ae 1140 zlog_warn(
1141 "ISIS-Spf: No lsp (%p) found from root "
1142 "to L%d DR %s on %s (ID %d)",
1143 (void *)lsp, spftree->level,
1144 rawlspid_print(lsp_id),
1145 circuit->interface->name,
1146 circuit->circuit_id);
1147 continue;
1148 }
1149 isis_spf_process_lsp(
1150 spftree, lsp,
1151 circuit->te_metric[spftree->level - 1], 0,
1152 root_sysid, parent);
1153 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
1154 adj = circuit->u.p2p.neighbor;
44b89511 1155 if (!adj || adj->adj_state != ISIS_ADJ_UP)
d62a17ae 1156 continue;
1157 if (!adj_has_mt(adj, spftree->mtid))
1158 continue;
1159 switch (adj->sys_type) {
1160 case ISIS_SYSTYPE_ES:
1161 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1162 LSP_PSEUDO_ID(lsp_id) = 0;
1163 isis_spf_add_local(
1164 spftree, VTYPE_ES, lsp_id, adj,
1165 circuit->te_metric[spftree->level - 1],
1166 parent);
1167 break;
1168 case ISIS_SYSTYPE_IS:
1169 case ISIS_SYSTYPE_L1_IS:
1170 case ISIS_SYSTYPE_L2_IS:
1171 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1172 LSP_PSEUDO_ID(lsp_id) = 0;
1173 LSP_FRAGMENT(lsp_id) = 0;
1174 if (spftree->mtid != ISIS_MT_IPV4_UNICAST
af8ac8f9
CF
1175 || speaks(adj->nlpids.nlpids,
1176 adj->nlpids.count,
1177 spftree->family))
d62a17ae 1178 isis_spf_add_local(
1179 spftree,
1180 spftree->area->oldmetric
1181 ? VTYPE_NONPSEUDO_IS
1182 : VTYPE_NONPSEUDO_TE_IS,
1183 lsp_id, adj,
1184 circuit->te_metric
1185 [spftree->level - 1],
1186 parent);
1187 break;
1188 case ISIS_SYSTYPE_UNKNOWN:
1189 default:
1190 zlog_warn(
1191 "isis_spf_preload_tent unknown adj type");
1192 break;
1193 }
1194 } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
1195 continue;
1196 } else {
1197 zlog_warn("isis_spf_preload_tent unsupported media");
1198 retval = ISIS_WARNING;
1199 }
f390d2c7 1200 }
eb5d44eb 1201
d62a17ae 1202 return retval;
eb5d44eb 1203}
1204
1205/*
1206 * The parent(s) for vertex is set when added to TENT list
1207 * now we just put the child pointer(s) in place
1208 */
d62a17ae 1209static void add_to_paths(struct isis_spftree *spftree,
1210 struct isis_vertex *vertex)
eb5d44eb 1211{
d62a17ae 1212 char buff[PREFIX2STR_BUFFER];
3f045a08 1213
eb919f07 1214 if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type))
d62a17ae 1215 return;
bded4060 1216 isis_vertex_queue_append(&spftree->paths, vertex);
eb5d44eb 1217
f390d2c7 1218#ifdef EXTREME_DEBUG
d62a17ae 1219 zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1220 print_sys_hostname(vertex->N.id), vtype2string(vertex->type),
1221 vid2string(vertex, buff, sizeof(buff)), vertex->depth,
1222 vertex->d_N);
f390d2c7 1223#endif /* EXTREME_DEBUG */
3f045a08 1224
d62a17ae 1225 if (VTYPE_IP(vertex->type)) {
1226 if (listcount(vertex->Adj_N) > 0)
1227 isis_route_create((struct prefix *)&vertex->N.prefix,
1228 vertex->d_N, vertex->depth,
1229 vertex->Adj_N, spftree->area,
1230 spftree->level);
1231 else if (isis->debugs & DEBUG_SPF_EVENTS)
1232 zlog_debug(
1233 "ISIS-Spf: no adjacencies do not install route for "
1234 "%s depth %d dist %d",
1235 vid2string(vertex, buff, sizeof(buff)),
1236 vertex->depth, vertex->d_N);
1237 }
1238
1239 return;
eb5d44eb 1240}
1241
d62a17ae 1242static void init_spt(struct isis_spftree *spftree, int mtid, int level,
1243 int family)
eb5d44eb 1244{
eb919f07
CF
1245 isis_vertex_queue_clear(&spftree->tents);
1246 isis_vertex_queue_clear(&spftree->paths);
d62a17ae 1247
1248 spftree->mtid = mtid;
1249 spftree->level = level;
1250 spftree->family = family;
1251 return;
eb5d44eb 1252}
1253
d62a17ae 1254static int isis_run_spf(struct isis_area *area, int level, int family,
a699dd69 1255 u_char *sysid, struct timeval *nowtv)
eb5d44eb 1256{
d62a17ae 1257 int retval = ISIS_OK;
d62a17ae 1258 struct isis_vertex *vertex;
1259 struct isis_vertex *root_vertex;
1260 struct isis_spftree *spftree = NULL;
1261 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1262 struct isis_lsp *lsp;
1263 struct route_table *table = NULL;
1264 struct timeval time_now;
1265 unsigned long long start_time, end_time;
1266 uint16_t mtid;
1267
1268 /* Get time that can't roll backwards. */
a699dd69
RZ
1269 start_time = nowtv->tv_sec;
1270 start_time = (start_time * 1000000) + nowtv->tv_usec;
d62a17ae 1271
1272 if (family == AF_INET)
1273 spftree = area->spftree[level - 1];
1274 else if (family == AF_INET6)
1275 spftree = area->spftree6[level - 1];
1276 assert(spftree);
1277 assert(sysid);
1278
1279 /* Make all routes in current route table inactive. */
1280 if (family == AF_INET)
1281 table = area->route_table[level - 1];
1282 else if (family == AF_INET6)
1283 table = area->route_table6[level - 1];
1284
1285 isis_route_invalidate_table(area, table);
1286
1287 /* We only support ipv4-unicast and ipv6-unicast as topologies for now
1288 */
1289 if (family == AF_INET6)
1290 mtid = isis_area_ipv6_topology(area);
1291 else
1292 mtid = ISIS_MT_IPV4_UNICAST;
1293
1294 /*
1295 * C.2.5 Step 0
1296 */
1297 init_spt(spftree, mtid, level, family);
1298 /* a) */
1299 root_vertex = isis_spf_add_root(spftree, sysid);
1300 /* b) */
1301 retval = isis_spf_preload_tent(spftree, sysid, root_vertex);
1302 if (retval != ISIS_OK) {
1303 zlog_warn("ISIS-Spf: failed to load TENT SPF-root:%s",
1304 print_sys_hostname(sysid));
1305 goto out;
1306 }
1307
1308 /*
1309 * C.2.7 Step 2
1310 */
ce837d81
CF
1311 if (!isis_vertex_queue_count(&spftree->tents)
1312 && (isis->debugs & DEBUG_SPF_EVENTS)) {
d62a17ae 1313 zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
1314 print_sys_hostname(sysid));
d62a17ae 1315 }
1316
eb919f07
CF
1317 while (isis_vertex_queue_count(&spftree->tents)) {
1318 vertex = isis_vertex_queue_pop(&spftree->tents);
3f045a08
JB
1319
1320#ifdef EXTREME_DEBUG
d62a17ae 1321 zlog_debug(
1322 "ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1323 print_sys_hostname(vertex->N.id),
1324 vtype2string(vertex->type), vertex->depth, vertex->d_N);
3f045a08
JB
1325#endif /* EXTREME_DEBUG */
1326
d62a17ae 1327 add_to_paths(spftree, vertex);
1328 if (VTYPE_IS(vertex->type)) {
1329 memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1330 LSP_FRAGMENT(lsp_id) = 0;
1331 lsp = lsp_search(lsp_id, area->lspdb[level - 1]);
af8ac8f9 1332 if (lsp && lsp->hdr.rem_lifetime != 0) {
d62a17ae 1333 isis_spf_process_lsp(spftree, lsp, vertex->d_N,
1334 vertex->depth, sysid,
1335 vertex);
1336 } else {
1337 zlog_warn("ISIS-Spf: No LSP found for %s",
1338 rawlspid_print(lsp_id));
1339 }
1340 }
eb5d44eb 1341 }
f390d2c7 1342
13fb40ac 1343out:
d62a17ae 1344 isis_route_validate(area);
1345 spftree->runcount++;
1346 spftree->last_run_timestamp = time(NULL);
3dca3c8c 1347 spftree->last_run_monotime = monotime(&time_now);
d62a17ae 1348 end_time = time_now.tv_sec;
1349 end_time = (end_time * 1000000) + time_now.tv_usec;
1350 spftree->last_run_duration = end_time - start_time;
1351
1352 return retval;
eb5d44eb 1353}
1354
d62a17ae 1355static int isis_run_spf_cb(struct thread *thread)
eb5d44eb 1356{
d62a17ae 1357 struct isis_spf_run *run = THREAD_ARG(thread);
1358 struct isis_area *area = run->area;
1359 int level = run->level;
1360 int retval = ISIS_OK;
1361
1362 XFREE(MTYPE_ISIS_SPF_RUN, run);
1363 area->spf_timer[level - 1] = NULL;
1364
1365 if (!(area->is_type & level)) {
1366 if (isis->debugs & DEBUG_SPF_EVENTS)
1367 zlog_warn("ISIS-SPF (%s) area does not share level",
1368 area->area_tag);
1369 return ISIS_WARNING;
1370 }
eb5d44eb 1371
d62a17ae 1372 if (isis->debugs & DEBUG_SPF_EVENTS)
1373 zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
1374 area->area_tag, level);
f390d2c7 1375
d62a17ae 1376 if (area->ip_circuits)
a699dd69 1377 retval = isis_run_spf(area, level, AF_INET, isis->sysid,
996c9314 1378 &thread->real);
d62a17ae 1379 if (area->ipv6_circuits)
a699dd69 1380 retval = isis_run_spf(area, level, AF_INET6, isis->sysid,
996c9314 1381 &thread->real);
eb5d44eb 1382
d62a17ae 1383 return retval;
eb5d44eb 1384}
1385
d62a17ae 1386static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
eb5d44eb 1387{
d62a17ae 1388 struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
1389
1390 run->area = area;
1391 run->level = level;
1392
1393 return run;
eb5d44eb 1394}
eb5d44eb 1395
d62a17ae 1396int isis_spf_schedule(struct isis_area *area, int level)
eb5d44eb 1397{
d62a17ae 1398 struct isis_spftree *spftree = area->spftree[level - 1];
3dca3c8c
CF
1399 time_t now = monotime(NULL);
1400 int diff = now - spftree->last_run_monotime;
d62a17ae 1401
1402 assert(diff >= 0);
1403 assert(area->is_type & level);
1404
1405 if (isis->debugs & DEBUG_SPF_EVENTS)
1406 zlog_debug(
1407 "ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1408 area->area_tag, level, diff);
1409
1410 if (area->spf_delay_ietf[level - 1]) {
1411 /* Need to call schedule function also if spf delay is running
1412 * to
1413 * restart holdoff timer - compare
1414 * draft-ietf-rtgwg-backoff-algo-04 */
1415 long delay =
1416 spf_backoff_schedule(area->spf_delay_ietf[level - 1]);
1417 if (area->spf_timer[level - 1])
1418 return ISIS_OK;
1419
1420 thread_add_timer_msec(master, isis_run_spf_cb,
1421 isis_run_spf_arg(area, level), delay,
1422 &area->spf_timer[level - 1]);
1423 return ISIS_OK;
3f045a08 1424 }
d62a17ae 1425
1426 if (area->spf_timer[level - 1])
1427 return ISIS_OK;
1428
1429 /* wait configured min_spf_interval before doing the SPF */
3dca3c8c 1430 long timer;
d62a17ae 1431 if (diff >= area->min_spf_interval[level - 1]) {
98c5bc15 1432 /* Last run is more than min interval ago, schedule immediate run */
3dca3c8c
CF
1433 timer = 0;
1434 } else {
1435 timer = area->min_spf_interval[level - 1] - diff;
f390d2c7 1436 }
3f045a08 1437
d62a17ae 1438 thread_add_timer(master, isis_run_spf_cb, isis_run_spf_arg(area, level),
3dca3c8c 1439 timer, &area->spf_timer[level - 1]);
d62a17ae 1440
1441 if (isis->debugs & DEBUG_SPF_EVENTS)
013b29d7
RZ
1442 zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %ld sec from now",
1443 area->area_tag, level, timer);
d62a17ae 1444
1445 return ISIS_OK;
1446}
1447
eb919f07 1448static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
d62a17ae 1449 u_char *root_sysid)
1450{
1451 struct listnode *node;
d62a17ae 1452 struct isis_vertex *vertex;
d62a17ae 1453 char buff[PREFIX2STR_BUFFER];
1454
1455 vty_out(vty,
1456 "Vertex Type Metric Next-Hop Interface Parent\n");
1457
eb919f07 1458 for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
d62a17ae 1459 if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
1460 vty_out(vty, "%-20s %-12s %-6s",
1461 print_sys_hostname(root_sysid), "", "");
af88c591
CF
1462 vty_out(vty, "%-30s\n", "");
1463 continue;
d62a17ae 1464 }
1465
af88c591
CF
1466 int rows = 0;
1467 struct listnode *anode = listhead(vertex->Adj_N);
1468 struct listnode *pnode = listhead(vertex->parents);
1469 struct isis_adjacency *adj;
1470 struct isis_vertex *pvertex;
1471
1472 vty_out(vty, "%-20s %-12s %-6u ",
1473 vid2string(vertex, buff, sizeof(buff)),
1474 vtype2string(vertex->type), vertex->d_N);
996c9314
LB
1475 for (unsigned int i = 0; i < MAX(listcount(vertex->Adj_N),
1476 listcount(vertex->parents));
1477 i++) {
af88c591
CF
1478 if (anode) {
1479 adj = listgetdata(anode);
1480 anode = anode->next;
1481 } else {
1482 adj = NULL;
1483 }
1484
1485 if (pnode) {
1486 pvertex = listgetdata(pnode);
1487 pnode = pnode->next;
1488 } else {
1489 pvertex = NULL;
1490 }
1491
1492 if (rows) {
1493 vty_out(vty, "\n");
1494 vty_out(vty, "%-20s %-12s %-6s ", "", "", "");
1495 }
1496
1497 if (adj) {
1498 vty_out(vty, "%-20s %-9s ",
1499 print_sys_hostname(adj->sysid),
1500 adj->circuit->interface->name);
1501 }
1502
1503 if (pvertex) {
1504 if (!adj)
1505 vty_out(vty, "%-20s %-9s ", "", "");
1506
d62a17ae 1507 vty_out(vty, "%s(%d)",
996c9314 1508 vid2string(pvertex, buff, sizeof(buff)),
d62a17ae 1509 pvertex->type);
d62a17ae 1510 }
d62a17ae 1511
af88c591
CF
1512 ++rows;
1513 }
d62a17ae 1514 vty_out(vty, "\n");
1515 }
eb5d44eb 1516}
1517
1518DEFUN (show_isis_topology,
1519 show_isis_topology_cmd,
1b49e4f0 1520 "show isis topology [<level-1|level-2>]",
eb5d44eb 1521 SHOW_STR
1522 "IS-IS information\n"
1b49e4f0
CF
1523 "IS-IS paths to Intermediate Systems\n"
1524 "Paths to all level-1 routers in the area\n"
1525 "Paths to all level-2 routers in the domain\n")
eb5d44eb 1526{
d62a17ae 1527 int levels;
1528 struct listnode *node;
1529 struct isis_area *area;
1530
1531 if (argc < 4)
1532 levels = ISIS_LEVEL1 | ISIS_LEVEL2;
1533 else if (strmatch(argv[3]->text, "level-1"))
1534 levels = ISIS_LEVEL1;
1535 else
1536 levels = ISIS_LEVEL2;
1537
1538 if (!isis->area_list || isis->area_list->count == 0)
1539 return CMD_SUCCESS;
1540
1541 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
1542 vty_out(vty, "Area %s:\n",
1543 area->area_tag ? area->area_tag : "null");
1544
1545 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
1546 if ((level & levels) == 0)
1547 continue;
1548
1549 if (area->ip_circuits > 0 && area->spftree[level - 1]
98c5bc15 1550 && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
d62a17ae 1551 vty_out(vty,
1552 "IS-IS paths to level-%d routers that speak IP\n",
1553 level);
1554 isis_print_paths(
eb919f07 1555 vty, &area->spftree[level - 1]->paths,
d62a17ae 1556 isis->sysid);
1557 vty_out(vty, "\n");
1558 }
1559 if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
98c5bc15 1560 && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
d62a17ae 1561 vty_out(vty,
1562 "IS-IS paths to level-%d routers that speak IPv6\n",
1563 level);
1564 isis_print_paths(
eb919f07 1565 vty, &area->spftree6[level - 1]->paths,
d62a17ae 1566 isis->sysid);
1567 vty_out(vty, "\n");
1568 }
1569 }
f390d2c7 1570
d62a17ae 1571 vty_out(vty, "\n");
f390d2c7 1572 }
3f045a08 1573
d62a17ae 1574 return CMD_SUCCESS;
f390d2c7 1575}
eb5d44eb 1576
d62a17ae 1577void isis_spf_cmds_init()
eb5d44eb 1578{
d62a17ae 1579 install_element(VIEW_NODE, &show_isis_topology_cmd);
eb5d44eb 1580}
02cd317e
CF
1581
1582void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
1583{
1584 vty_out(vty, " last run elapsed : ");
1585 vty_out_timestr(vty, spftree->last_run_timestamp);
1586 vty_out(vty, "\n");
1587
1588 vty_out(vty, " last run duration : %u usec\n",
1589 (u_int32_t)spftree->last_run_duration);
1590
996c9314 1591 vty_out(vty, " run count : %u\n", spftree->runcount);
02cd317e 1592}