]> git.proxmox.com Git - mirror_frr.git/blame - isisd/fabricd.c
isisd: Remove unused t_send_lsp timer
[mirror_frr.git] / isisd / fabricd.c
CommitLineData
8e6fb83b
CF
1/*
2 * IS-IS Rout(e)ing protocol - OpenFabric extensions
3 *
4 * Copyright (C) 2018 Christian Franke
5 *
6 * This file is part of FreeRangeRouting (FRR)
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22#include <zebra.h>
23#include "isisd/fabricd.h"
24#include "isisd/isisd.h"
25#include "isisd/isis_memory.h"
26#include "isisd/isis_circuit.h"
27#include "isisd/isis_misc.h"
28#include "isisd/isis_adjacency.h"
b30e837b 29#include "isisd/isis_spf.h"
92ed0cde
CF
30#include "isisd/isis_tlvs.h"
31#include "isisd/isis_lsp.h"
1f5be499 32#include "isisd/isis_spf_private.h"
9b39405f 33#include "isisd/isis_tx_queue.h"
8e6fb83b
CF
34
35DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
1f5be499 36DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry")
8e6fb83b
CF
37
38/* Tracks initial synchronization as per section 2.4
39 *
40 * We declare the sync complete once we have seen at least one
41 * CSNP and there are no more LSPs with SSN or SRM set.
42 */
43enum fabricd_sync_state {
44 FABRICD_SYNC_PENDING,
45 FABRICD_SYNC_STARTED,
46 FABRICD_SYNC_COMPLETE
47};
48
49struct fabricd {
92ed0cde
CF
50 struct isis_area *area;
51
8e6fb83b
CF
52 enum fabricd_sync_state initial_sync_state;
53 time_t initial_sync_start;
54 struct isis_circuit *initial_sync_circuit;
55 struct thread *initial_sync_timeout;
b30e837b
CF
56
57 struct isis_spftree *spftree;
1f5be499
CF
58 struct skiplist *neighbors;
59 struct hash *neighbors_neighbors;
92ed0cde
CF
60
61 uint8_t tier;
62 uint8_t tier_config;
75e0ec94
CF
63 uint8_t tier_pending;
64 struct thread *tier_calculation_timer;
65 struct thread *tier_set_timer;
8e6fb83b
CF
66};
67
1f5be499
CF
68/* Code related to maintaining the neighbor lists */
69
70struct neighbor_entry {
71 struct isis_vertex *vertex;
72 bool present;
73};
74
75static struct neighbor_entry *neighbor_entry_new(struct isis_vertex *vertex)
76{
77 struct neighbor_entry *rv = XMALLOC(MTYPE_FABRICD_NEIGHBOR, sizeof(*rv));
78
79 rv->vertex = vertex;
80 return rv;
81}
82
83static void neighbor_entry_del(struct neighbor_entry *neighbor)
84{
85 XFREE(MTYPE_FABRICD_NEIGHBOR, neighbor);
86}
87
88static void neighbor_entry_del_void(void *arg)
89{
90 neighbor_entry_del((struct neighbor_entry *)arg);
91}
92
93static void neighbor_lists_clear(struct fabricd *f)
94{
95 while (!skiplist_empty(f->neighbors))
96 skiplist_delete_first(f->neighbors);
97
98 hash_clean(f->neighbors_neighbors, neighbor_entry_del_void);
99}
100
101static unsigned neighbor_entry_hash_key(void *np)
102{
103 struct neighbor_entry *n = np;
104
105 return jhash(n->vertex->N.id, ISIS_SYS_ID_LEN, 0x55aa5a5a);
106}
107
74df8d6d 108static bool neighbor_entry_hash_cmp(const void *a, const void *b)
1f5be499
CF
109{
110 const struct neighbor_entry *na = a, *nb = b;
111
112 return memcmp(na->vertex->N.id, nb->vertex->N.id, ISIS_SYS_ID_LEN) == 0;
113}
114
115static int neighbor_entry_list_cmp(void *a, void *b)
116{
117 struct neighbor_entry *na = a, *nb = b;
118
119 return -memcmp(na->vertex->N.id, nb->vertex->N.id, ISIS_SYS_ID_LEN);
120}
121
9d224819
CF
122static struct neighbor_entry *neighbor_entry_lookup_list(struct skiplist *list,
123 const uint8_t *id)
124{
125 struct isis_vertex querier;
126 isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
127
128 struct neighbor_entry n = {
129 .vertex = &querier
130 };
131
132 struct neighbor_entry *rv;
133
134 if (skiplist_search(list, &n, (void**)&rv))
135 return NULL;
136
137 if (!rv->present)
138 return NULL;
139
140 return rv;
141}
142
143static struct neighbor_entry *neighbor_entry_lookup_hash(struct hash *hash,
144 const uint8_t *id)
145{
146 struct isis_vertex querier;
147 isis_vertex_id_init(&querier, id, VTYPE_NONPSEUDO_TE_IS);
148
149 struct neighbor_entry n = {
150 .vertex = &querier
151 };
152
153 struct neighbor_entry *rv = hash_lookup(hash, &n);
154
155 if (!rv || !rv->present)
156 return NULL;
157
158 return rv;
159}
160
1f5be499
CF
161static void neighbor_lists_update(struct fabricd *f)
162{
163 neighbor_lists_clear(f);
164
165 struct listnode *node;
166 struct isis_vertex *v;
167
168 for (ALL_QUEUE_ELEMENTS_RO(&f->spftree->paths, node, v)) {
169 if (!v->d_N || !VTYPE_IS(v->type))
170 continue;
171
172 if (v->d_N > 2)
173 break;
174
175 struct neighbor_entry *n = neighbor_entry_new(v);
176 if (v->d_N == 1) {
177 skiplist_insert(f->neighbors, n, n);
178 } else {
179 struct neighbor_entry *inserted;
180 inserted = hash_get(f->neighbors_neighbors, n, hash_alloc_intern);
181 assert(inserted == n);
182 }
183 }
184}
185
b30e837b 186struct fabricd *fabricd_new(struct isis_area *area)
8e6fb83b
CF
187{
188 struct fabricd *rv = XCALLOC(MTYPE_FABRICD_STATE, sizeof(*rv));
189
92ed0cde 190 rv->area = area;
8e6fb83b 191 rv->initial_sync_state = FABRICD_SYNC_PENDING;
1f5be499 192
b30e837b 193 rv->spftree = isis_spftree_new(area);
1f5be499
CF
194 rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp,
195 neighbor_entry_del_void);
196 rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key,
197 neighbor_entry_hash_cmp,
198 "Fabricd Neighbors");
199
92ed0cde 200 rv->tier = rv->tier_config = ISIS_TIER_UNDEFINED;
8e6fb83b
CF
201 return rv;
202};
203
b30e837b
CF
204void fabricd_finish(struct fabricd *f)
205{
206 if (f->initial_sync_timeout)
207 thread_cancel(f->initial_sync_timeout);
208
75e0ec94
CF
209 if (f->tier_calculation_timer)
210 thread_cancel(f->tier_calculation_timer);
211
212 if (f->tier_set_timer)
213 thread_cancel(f->tier_set_timer);
214
b30e837b 215 isis_spftree_del(f->spftree);
1f5be499
CF
216 neighbor_lists_clear(f);
217 skiplist_free(f->neighbors);
218 hash_free(f->neighbors_neighbors);
b30e837b
CF
219}
220
8e6fb83b
CF
221static int fabricd_initial_sync_timeout(struct thread *thread)
222{
223 struct fabricd *f = THREAD_ARG(thread);
224
225 zlog_info("OpenFabric: Initial synchronization on %s timed out!",
226 f->initial_sync_circuit->interface->name);
227 f->initial_sync_state = FABRICD_SYNC_PENDING;
228 f->initial_sync_circuit = NULL;
229 f->initial_sync_timeout = NULL;
230 return 0;
231}
232
233void fabricd_initial_sync_hello(struct isis_circuit *circuit)
234{
235 struct fabricd *f = circuit->area->fabricd;
236
237 if (!f)
238 return;
239
240 if (f->initial_sync_state > FABRICD_SYNC_PENDING)
241 return;
242
243 f->initial_sync_state = FABRICD_SYNC_STARTED;
244
245 long timeout = 2 * circuit->hello_interval[1] * circuit->hello_multiplier[1];
246
247 f->initial_sync_circuit = circuit;
248 if (f->initial_sync_timeout)
249 return;
250
251 thread_add_timer(master, fabricd_initial_sync_timeout, f,
252 timeout, &f->initial_sync_timeout);
253 f->initial_sync_start = monotime(NULL);
254
255 zlog_info("OpenFabric: Started initial synchronization with %s on %s",
256 sysid_print(circuit->u.p2p.neighbor->sysid),
257 circuit->interface->name);
258}
259
260bool fabricd_initial_sync_is_in_progress(struct isis_area *area)
261{
262 struct fabricd *f = area->fabricd;
263
264 if (!f)
265 return false;
266
267 if (f->initial_sync_state > FABRICD_SYNC_PENDING
268 && f->initial_sync_state < FABRICD_SYNC_COMPLETE)
269 return true;
270
271 return false;
272}
273
df0ba689
CF
274bool fabricd_initial_sync_is_complete(struct isis_area *area)
275{
276 struct fabricd *f = area->fabricd;
277
278 if (!f)
279 return false;
280
281 return f->initial_sync_state == FABRICD_SYNC_COMPLETE;
282}
283
8e6fb83b
CF
284struct isis_circuit *fabricd_initial_sync_circuit(struct isis_area *area)
285{
286 struct fabricd *f = area->fabricd;
287 if (!f)
288 return NULL;
289
290 return f->initial_sync_circuit;
291}
292
293void fabricd_initial_sync_finish(struct isis_area *area)
294{
295 struct fabricd *f = area->fabricd;
296
297 if (!f)
298 return;
299
300 if (monotime(NULL) - f->initial_sync_start < 5)
301 return;
302
303 zlog_info("OpenFabric: Initial synchronization on %s complete.",
304 f->initial_sync_circuit->interface->name);
305 f->initial_sync_state = FABRICD_SYNC_COMPLETE;
306 f->initial_sync_circuit = NULL;
307 thread_cancel(f->initial_sync_timeout);
308 f->initial_sync_timeout = NULL;
309}
b30e837b 310
75e0ec94
CF
311static void fabricd_bump_tier_calculation_timer(struct fabricd *f);
312static void fabricd_set_tier(struct fabricd *f, uint8_t tier);
313
314static uint8_t fabricd_calculate_fabric_tier(struct isis_area *area)
315{
316 struct isis_spftree *local_tree = fabricd_spftree(area);
317 struct listnode *node;
318
319 struct isis_vertex *furthest_t0 = NULL,
320 *second_furthest_t0 = NULL;
321
322 struct isis_vertex *v;
323
324 for (ALL_QUEUE_ELEMENTS_RO(&local_tree->paths, node, v)) {
325 struct isis_lsp *lsp = lsp_for_vertex(local_tree, v);
326
327 if (!lsp || !lsp->tlvs
328 || !lsp->tlvs->spine_leaf
329 || !lsp->tlvs->spine_leaf->has_tier
330 || lsp->tlvs->spine_leaf->tier != 0)
331 continue;
332
333 second_furthest_t0 = furthest_t0;
334 furthest_t0 = v;
335 }
336
337 if (!second_furthest_t0) {
338 zlog_info("OpenFabric: Could not find two T0 routers");
339 return ISIS_TIER_UNDEFINED;
340 }
341
342 zlog_info("OpenFabric: Found %s as furthest t0 from local system, dist == %"
343 PRIu32, rawlspid_print(furthest_t0->N.id), furthest_t0->d_N);
344
345 struct isis_spftree *remote_tree =
346 isis_run_hopcount_spf(area, furthest_t0->N.id, NULL);
347
348 struct isis_vertex *furthest_from_remote =
349 isis_vertex_queue_last(&remote_tree->paths);
350
351 if (!furthest_from_remote) {
352 zlog_info("OpenFabric: Found no furthest node in remote spf");
353 isis_spftree_del(remote_tree);
354 return ISIS_TIER_UNDEFINED;
355 } else {
356 zlog_info("OpenFabric: Found %s as furthest from remote dist == %"
357 PRIu32, rawlspid_print(furthest_from_remote->N.id),
358 furthest_from_remote->d_N);
359 }
360
361 int64_t tier = furthest_from_remote->d_N - furthest_t0->d_N;
362 isis_spftree_del(remote_tree);
363
364 if (tier < 0 || tier >= ISIS_TIER_UNDEFINED) {
365 zlog_info("OpenFabric: Calculated tier %" PRId64 " seems implausible",
366 tier);
367 return ISIS_TIER_UNDEFINED;
368 }
369
370 zlog_info("OpenFabric: Calculated %" PRId64 " as tier", tier);
371 return tier;
372}
373
374static int fabricd_tier_set_timer(struct thread *thread)
375{
376 struct fabricd *f = THREAD_ARG(thread);
377 f->tier_set_timer = NULL;
378
379 fabricd_set_tier(f, f->tier_pending);
380 return 0;
381}
382
383static int fabricd_tier_calculation_cb(struct thread *thread)
384{
385 struct fabricd *f = THREAD_ARG(thread);
386 uint8_t tier = ISIS_TIER_UNDEFINED;
387 f->tier_calculation_timer = NULL;
388
389 tier = fabricd_calculate_fabric_tier(f->area);
390 if (tier == ISIS_TIER_UNDEFINED)
391 return 0;
392
393 zlog_info("OpenFabric: Got tier %" PRIu8 " from algorithm. Arming timer.",
394 tier);
395 f->tier_pending = tier;
396 thread_add_timer(master, fabricd_tier_set_timer, f,
397 f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
398 &f->tier_set_timer);
399
400 return 0;
401}
402
403static void fabricd_bump_tier_calculation_timer(struct fabricd *f)
404{
405 /* Cancel timer if we already know our tier */
406 if (f->tier != ISIS_TIER_UNDEFINED
407 || f->tier_set_timer) {
408 if (f->tier_calculation_timer) {
409 thread_cancel(f->tier_calculation_timer);
410 f->tier_calculation_timer = NULL;
411 }
412 return;
413 }
414
415 /* If we need to calculate the tier, wait some
416 * time for the topology to settle before running
417 * the calculation */
418 if (f->tier_calculation_timer) {
419 thread_cancel(f->tier_calculation_timer);
420 f->tier_calculation_timer = NULL;
421 }
422
423 thread_add_timer(master, fabricd_tier_calculation_cb, f,
424 2 * f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
425 &f->tier_calculation_timer);
426}
427
92ed0cde
CF
428static void fabricd_set_tier(struct fabricd *f, uint8_t tier)
429{
430 if (f->tier == tier)
431 return;
432
75e0ec94 433 zlog_info("OpenFabric: Set own tier to %" PRIu8, tier);
92ed0cde
CF
434 f->tier = tier;
435
75e0ec94 436 fabricd_bump_tier_calculation_timer(f);
92ed0cde
CF
437 lsp_regenerate_schedule(f->area, ISIS_LEVEL2, 0);
438}
439
b30e837b
CF
440void fabricd_run_spf(struct isis_area *area)
441{
442 struct fabricd *f = area->fabricd;
443
444 if (!f)
445 return;
446
447 isis_run_hopcount_spf(area, isis->sysid, f->spftree);
1f5be499 448 neighbor_lists_update(f);
75e0ec94 449 fabricd_bump_tier_calculation_timer(f);
b30e837b
CF
450}
451
452struct isis_spftree *fabricd_spftree(struct isis_area *area)
453{
454 struct fabricd *f = area->fabricd;
455
456 if (!f)
457 return NULL;
458
459 return f->spftree;
460}
92ed0cde
CF
461
462void fabricd_configure_tier(struct isis_area *area, uint8_t tier)
463{
464 struct fabricd *f = area->fabricd;
465
466 if (!f || f->tier_config == tier)
467 return;
468
469 f->tier_config = tier;
470 fabricd_set_tier(f, tier);
471}
472
473uint8_t fabricd_tier(struct isis_area *area)
474{
475 struct fabricd *f = area->fabricd;
476
477 if (!f)
478 return ISIS_TIER_UNDEFINED;
479
480 return f->tier;
481}
482
483int fabricd_write_settings(struct isis_area *area, struct vty *vty)
484{
485 struct fabricd *f = area->fabricd;
486 int written = 0;
487
488 if (!f)
489 return written;
490
491 if (f->tier_config != ISIS_TIER_UNDEFINED) {
492 vty_out(vty, " fabric-tier %" PRIu8 "\n", f->tier_config);
493 written++;
494 }
495
496 return written;
497}
9d224819
CF
498
499static void move_to_dnr(struct isis_lsp *lsp, struct neighbor_entry *n)
500{
501 struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
502
503 n->present = false;
d4cff91a
CF
504
505 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
506 char buff[PREFIX2STR_BUFFER];
507 zlog_debug("OpenFabric: Adding %s to DNR",
508 vid2string(n->vertex, buff, sizeof(buff)));
509 }
510
9d224819
CF
511 if (adj) {
512 isis_tx_queue_add(adj->circuit->tx_queue, lsp,
513 TX_LSP_CIRCUIT_SCOPED);
514 }
515}
516
517static void move_to_rf(struct isis_lsp *lsp, struct neighbor_entry *n)
518{
519 struct isis_adjacency *adj = listnode_head(n->vertex->Adj_N);
520
521 n->present = false;
d4cff91a
CF
522
523 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
524 char buff[PREFIX2STR_BUFFER];
525 zlog_debug("OpenFabric: Adding %s to RF",
526 vid2string(n->vertex, buff, sizeof(buff)));
527 }
528
9d224819
CF
529 if (adj) {
530 isis_tx_queue_add(adj->circuit->tx_queue, lsp,
531 TX_LSP_NORMAL);
532 }
533}
534
535static void mark_neighbor_as_present(struct hash_backet *backet, void *arg)
536{
537 struct neighbor_entry *n = backet->data;
538
539 n->present = true;
540}
541
542static void handle_firsthops(struct hash_backet *backet, void *arg)
543{
544 struct isis_lsp *lsp = arg;
545 struct fabricd *f = lsp->area->fabricd;
546 struct isis_vertex *vertex = backet->data;
547
548 struct neighbor_entry *n;
549
550 n = neighbor_entry_lookup_list(f->neighbors, vertex->N.id);
d4cff91a
CF
551 if (n) {
552 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
553 char buff[PREFIX2STR_BUFFER];
554 zlog_debug("Removing %s from NL as its in the reverse path",
555 vid2string(vertex, buff, sizeof(buff)));
556 }
9d224819 557 n->present = false;
d4cff91a 558 }
9d224819
CF
559
560 n = neighbor_entry_lookup_hash(f->neighbors_neighbors, vertex->N.id);
d4cff91a
CF
561 if (n) {
562 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
563 char buff[PREFIX2STR_BUFFER];
564 zlog_debug("Removing %s from NN as its in the reverse path",
565 vid2string(vertex, buff, sizeof(buff)));
566 }
9d224819 567 n->present = false;
d4cff91a 568 }
9d224819
CF
569}
570
571void fabricd_lsp_flood(struct isis_lsp *lsp)
572{
573 struct fabricd *f = lsp->area->fabricd;
574 assert(f);
575
576 void *cursor = NULL;
577 struct neighbor_entry *n;
578
d4cff91a
CF
579 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
580 zlog_debug("OpenFabric: Flooding LSP %s",
581 rawlspid_print(lsp->hdr.lsp_id));
582 }
583
9d224819
CF
584 /* Mark all elements in NL as present and move T0s into DNR */
585 while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
586 n->present = true;
587
253faee9
CF
588 struct isis_lsp *node_lsp = lsp_for_vertex(f->spftree,
589 n->vertex);
590 if (!node_lsp
591 || !node_lsp->tlvs
592 || !node_lsp->tlvs->spine_leaf
593 || !node_lsp->tlvs->spine_leaf->has_tier
594 || node_lsp->tlvs->spine_leaf->tier != 0) {
9d224819 595 continue;
253faee9 596 }
9d224819 597
d4cff91a
CF
598 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
599 zlog_debug("Moving %s to DNR because it's T0",
253faee9 600 rawlspid_print(node_lsp->hdr.lsp_id));
d4cff91a
CF
601 }
602
9d224819
CF
603 move_to_dnr(lsp, n);
604 }
605
606 /* Mark all elements in NN as present */
607 hash_iterate(f->neighbors_neighbors, mark_neighbor_as_present, NULL);
608
609 struct isis_vertex *originator = isis_find_vertex(&f->spftree->paths,
610 lsp->hdr.lsp_id,
611 VTYPE_NONPSEUDO_TE_IS);
612
613 /* Remove all IS from NL and NN in the shortest path
614 * to the IS that originated the LSP */
615 if (originator)
616 hash_iterate(originator->firsthops, handle_firsthops, lsp);
617
618 /* Iterate over all remaining IS in NL */
619 cursor = NULL;
620 while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
621 if (!n->present)
622 continue;
623
624 struct isis_lsp *nlsp = lsp_for_vertex(f->spftree, n->vertex);
625 if (!nlsp || !nlsp->tlvs) {
d4cff91a
CF
626 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
627 char buff[PREFIX2STR_BUFFER];
628 zlog_debug("Moving %s to DNR as it has no LSP",
629 vid2string(n->vertex, buff, sizeof(buff)));
630 }
631
9d224819
CF
632 move_to_dnr(lsp, n);
633 continue;
634 }
635
d4cff91a
CF
636 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
637 char buff[PREFIX2STR_BUFFER];
638 zlog_debug("Considering %s from NL...",
639 vid2string(n->vertex, buff, sizeof(buff)));
640 }
641
9d224819
CF
642 /* For all neighbors of the NL IS check whether they are present
643 * in NN. If yes, remove from NN and set need_reflood. */
644 bool need_reflood = false;
645 struct isis_extended_reach *er;
646 for (er = (struct isis_extended_reach *)nlsp->tlvs->extended_reach.head;
647 er; er = er->next) {
648 struct neighbor_entry *nn;
649
650 nn = neighbor_entry_lookup_hash(f->neighbors_neighbors,
651 er->id);
652
653 if (nn) {
d4cff91a
CF
654 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
655 char buff[PREFIX2STR_BUFFER];
656 zlog_debug("Found neighbor %s in NN, removing it from NN and setting reflood.",
657 vid2string(nn->vertex, buff, sizeof(buff)));
658 }
659
9d224819
CF
660 nn->present = false;
661 need_reflood = true;
662 }
663 }
664
665 if (need_reflood)
666 move_to_rf(lsp, n);
667 else
668 move_to_dnr(lsp, n);
669 }
d4cff91a
CF
670
671 if (isis->debugs & DEBUG_FABRICD_FLOODING) {
672 zlog_debug("OpenFabric: Flooding algorithm complete.");
673 }
9d224819 674}
df0ba689
CF
675
676void fabricd_trigger_csnp(struct isis_area *area)
677{
678 struct fabricd *f = area->fabricd;
679
680 if (!f)
681 return;
682
683 struct listnode *node;
684 struct isis_circuit *circuit;
685
686 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
687 if (!circuit->t_send_csnp[1])
688 continue;
689
690 thread_cancel(circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
691 thread_add_timer_msec(master, send_l2_csnp, circuit,
692 isis_jitter(500, CSNP_JITTER),
693 &circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
694 }
695}
41415888
CF
696
697struct list *fabricd_ip_addrs(struct isis_circuit *circuit)
698{
699 if (circuit->ip_addrs && listcount(circuit->ip_addrs))
700 return circuit->ip_addrs;
701
702 if (!fabricd || !circuit->area || !circuit->area->circuit_list)
703 return NULL;
704
705 struct listnode *node;
706 struct isis_circuit *c;
707
708 for (ALL_LIST_ELEMENTS_RO(circuit->area->circuit_list, node, c)) {
709 if (c->circ_type != CIRCUIT_T_LOOPBACK)
710 continue;
711
712 if (!c->ip_addrs || !listcount(c->ip_addrs))
713 return NULL;
714
715 return c->ip_addrs;
716 }
717
718 return NULL;
719}