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