]> git.proxmox.com Git - mirror_frr.git/blame - isisd/fabricd.c
Merge pull request #3502 from donaldsharp/socket_to_me_baby
[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"
dc0dacfc 34#include "isisd/isis_csm.h"
8e6fb83b
CF
35
36DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
1f5be499 37DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry")
1eb7c3a1 38DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log")
8e6fb83b
CF
39
40/* Tracks initial synchronization as per section 2.4
41 *
42 * We declare the sync complete once we have seen at least one
43 * CSNP and there are no more LSPs with SSN or SRM set.
44 */
45enum fabricd_sync_state {
46 FABRICD_SYNC_PENDING,
47 FABRICD_SYNC_STARTED,
48 FABRICD_SYNC_COMPLETE
49};
50
51struct fabricd {
92ed0cde
CF
52 struct isis_area *area;
53
8e6fb83b
CF
54 enum fabricd_sync_state initial_sync_state;
55 time_t initial_sync_start;
56 struct isis_circuit *initial_sync_circuit;
57 struct thread *initial_sync_timeout;
b30e837b
CF
58
59 struct isis_spftree *spftree;
1f5be499
CF
60 struct skiplist *neighbors;
61 struct hash *neighbors_neighbors;
92ed0cde
CF
62
63 uint8_t tier;
64 uint8_t tier_config;
75e0ec94
CF
65 uint8_t tier_pending;
66 struct thread *tier_calculation_timer;
67 struct thread *tier_set_timer;
e923107c
CF
68
69 int csnp_delay;
70 bool always_send_csnp;
8e6fb83b
CF
71};
72
1f5be499
CF
73/* Code related to maintaining the neighbor lists */
74
75struct neighbor_entry {
dc0dacfc
CF
76 uint8_t id[ISIS_SYS_ID_LEN];
77 struct isis_adjacency *adj;
1f5be499
CF
78 bool present;
79};
80
dc0dacfc
CF
81static struct neighbor_entry *neighbor_entry_new(const uint8_t *id,
82 struct isis_adjacency *adj)
1f5be499 83{
89cdc4df
RM
84 struct neighbor_entry *rv = XMALLOC(MTYPE_FABRICD_NEIGHBOR,
85 sizeof(*rv));
1f5be499 86
dc0dacfc
CF
87 memcpy(rv->id, id, sizeof(rv->id));
88 rv->adj = adj;
89
1f5be499
CF
90 return rv;
91}
92
93static void neighbor_entry_del(struct neighbor_entry *neighbor)
94{
95 XFREE(MTYPE_FABRICD_NEIGHBOR, neighbor);
96}
97
98static void neighbor_entry_del_void(void *arg)
99{
100 neighbor_entry_del((struct neighbor_entry *)arg);
101}
102
103static void neighbor_lists_clear(struct fabricd *f)
104{
105 while (!skiplist_empty(f->neighbors))
106 skiplist_delete_first(f->neighbors);
107
108 hash_clean(f->neighbors_neighbors, neighbor_entry_del_void);
109}
110
111static unsigned neighbor_entry_hash_key(void *np)
112{
113 struct neighbor_entry *n = np;
114
dc0dacfc 115 return jhash(n->id, sizeof(n->id), 0x55aa5a5a);
1f5be499
CF
116}
117
74df8d6d 118static bool neighbor_entry_hash_cmp(const void *a, const void *b)
1f5be499
CF
119{
120 const struct neighbor_entry *na = a, *nb = b;
121
dc0dacfc 122 return memcmp(na->id, nb->id, sizeof(na->id)) == 0;
1f5be499
CF
123}
124
125static int neighbor_entry_list_cmp(void *a, void *b)
126{
127 struct neighbor_entry *na = a, *nb = b;
128
dc0dacfc 129 return -memcmp(na->id, nb->id, sizeof(na->id));
1f5be499
CF
130}
131
9d224819
CF
132static struct neighbor_entry *neighbor_entry_lookup_list(struct skiplist *list,
133 const uint8_t *id)
134{
89cdc4df 135 struct neighbor_entry n = { {0} };
9d224819 136
dc0dacfc 137 memcpy(n.id, id, sizeof(n.id));
9d224819
CF
138
139 struct neighbor_entry *rv;
140
141 if (skiplist_search(list, &n, (void**)&rv))
142 return NULL;
143
144 if (!rv->present)
145 return NULL;
146
147 return rv;
148}
149
150static struct neighbor_entry *neighbor_entry_lookup_hash(struct hash *hash,
151 const uint8_t *id)
152{
dc0dacfc 153 struct neighbor_entry n = {{0}};
9d224819 154
dc0dacfc 155 memcpy(n.id, id, sizeof(n.id));
9d224819
CF
156
157 struct neighbor_entry *rv = hash_lookup(hash, &n);
158
159 if (!rv || !rv->present)
160 return NULL;
161
162 return rv;
163}
164
2cd971af 165static int fabricd_handle_adj_state_change(struct isis_adjacency *arg)
1f5be499 166{
2cd971af
CF
167 struct fabricd *f = arg->circuit->area->fabricd;
168
169 if (!f)
170 return 0;
171
172 while (!skiplist_empty(f->neighbors))
173 skiplist_delete_first(f->neighbors);
1f5be499
CF
174
175 struct listnode *node;
dc0dacfc
CF
176 struct isis_circuit *circuit;
177
178 for (ALL_LIST_ELEMENTS_RO(f->area->circuit_list, node, circuit)) {
179 if (circuit->state != C_STATE_UP)
180 continue;
181
182 struct isis_adjacency *adj = circuit->u.p2p.neighbor;
183
184 if (!adj || adj->adj_state != ISIS_ADJ_UP)
185 continue;
186
187 struct neighbor_entry *n = neighbor_entry_new(adj->sysid, adj);
188
189 skiplist_insert(f->neighbors, n, n);
190 }
191
2cd971af
CF
192 return 0;
193}
194
195static void neighbors_neighbors_update(struct fabricd *f)
196{
197 hash_clean(f->neighbors_neighbors, neighbor_entry_del_void);
198
199 struct listnode *node;
1f5be499
CF
200 struct isis_vertex *v;
201
202 for (ALL_QUEUE_ELEMENTS_RO(&f->spftree->paths, node, v)) {
dc0dacfc 203 if (v->d_N < 2 || !VTYPE_IS(v->type))
1f5be499
CF
204 continue;
205
206 if (v->d_N > 2)
207 break;
208
dc0dacfc
CF
209 struct neighbor_entry *n = neighbor_entry_new(v->N.id, NULL);
210 struct neighbor_entry *inserted;
211 inserted = hash_get(f->neighbors_neighbors, n,
212 hash_alloc_intern);
213 assert(inserted == n);
1f5be499
CF
214 }
215}
216
b30e837b 217struct fabricd *fabricd_new(struct isis_area *area)
8e6fb83b
CF
218{
219 struct fabricd *rv = XCALLOC(MTYPE_FABRICD_STATE, sizeof(*rv));
220
92ed0cde 221 rv->area = area;
8e6fb83b 222 rv->initial_sync_state = FABRICD_SYNC_PENDING;
1f5be499 223
b30e837b 224 rv->spftree = isis_spftree_new(area);
1f5be499
CF
225 rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp,
226 neighbor_entry_del_void);
227 rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key,
228 neighbor_entry_hash_cmp,
229 "Fabricd Neighbors");
230
92ed0cde 231 rv->tier = rv->tier_config = ISIS_TIER_UNDEFINED;
e923107c
CF
232
233 rv->csnp_delay = FABRICD_DEFAULT_CSNP_DELAY;
8e6fb83b
CF
234 return rv;
235};
236
b30e837b
CF
237void fabricd_finish(struct fabricd *f)
238{
239 if (f->initial_sync_timeout)
240 thread_cancel(f->initial_sync_timeout);
241
75e0ec94
CF
242 if (f->tier_calculation_timer)
243 thread_cancel(f->tier_calculation_timer);
244
245 if (f->tier_set_timer)
246 thread_cancel(f->tier_set_timer);
247
b30e837b 248 isis_spftree_del(f->spftree);
1f5be499
CF
249 neighbor_lists_clear(f);
250 skiplist_free(f->neighbors);
251 hash_free(f->neighbors_neighbors);
b30e837b
CF
252}
253
8e6fb83b
CF
254static int fabricd_initial_sync_timeout(struct thread *thread)
255{
256 struct fabricd *f = THREAD_ARG(thread);
257
258 zlog_info("OpenFabric: Initial synchronization on %s timed out!",
259 f->initial_sync_circuit->interface->name);
260 f->initial_sync_state = FABRICD_SYNC_PENDING;
261 f->initial_sync_circuit = NULL;
262 f->initial_sync_timeout = NULL;
263 return 0;
264}
265
266void fabricd_initial_sync_hello(struct isis_circuit *circuit)
267{
268 struct fabricd *f = circuit->area->fabricd;
269
270 if (!f)
271 return;
272
273 if (f->initial_sync_state > FABRICD_SYNC_PENDING)
274 return;
275
276 f->initial_sync_state = FABRICD_SYNC_STARTED;
277
278 long timeout = 2 * circuit->hello_interval[1] * circuit->hello_multiplier[1];
279
280 f->initial_sync_circuit = circuit;
281 if (f->initial_sync_timeout)
282 return;
283
284 thread_add_timer(master, fabricd_initial_sync_timeout, f,
285 timeout, &f->initial_sync_timeout);
286 f->initial_sync_start = monotime(NULL);
287
288 zlog_info("OpenFabric: Started initial synchronization with %s on %s",
289 sysid_print(circuit->u.p2p.neighbor->sysid),
290 circuit->interface->name);
291}
292
293bool fabricd_initial_sync_is_in_progress(struct isis_area *area)
294{
295 struct fabricd *f = area->fabricd;
296
297 if (!f)
298 return false;
299
300 if (f->initial_sync_state > FABRICD_SYNC_PENDING
301 && f->initial_sync_state < FABRICD_SYNC_COMPLETE)
302 return true;
303
304 return false;
305}
306
df0ba689
CF
307bool fabricd_initial_sync_is_complete(struct isis_area *area)
308{
309 struct fabricd *f = area->fabricd;
310
311 if (!f)
312 return false;
313
314 return f->initial_sync_state == FABRICD_SYNC_COMPLETE;
315}
316
8e6fb83b
CF
317struct isis_circuit *fabricd_initial_sync_circuit(struct isis_area *area)
318{
319 struct fabricd *f = area->fabricd;
320 if (!f)
321 return NULL;
322
323 return f->initial_sync_circuit;
324}
325
326void fabricd_initial_sync_finish(struct isis_area *area)
327{
328 struct fabricd *f = area->fabricd;
329
330 if (!f)
331 return;
332
333 if (monotime(NULL) - f->initial_sync_start < 5)
334 return;
335
336 zlog_info("OpenFabric: Initial synchronization on %s complete.",
337 f->initial_sync_circuit->interface->name);
338 f->initial_sync_state = FABRICD_SYNC_COMPLETE;
339 f->initial_sync_circuit = NULL;
340 thread_cancel(f->initial_sync_timeout);
341 f->initial_sync_timeout = NULL;
342}
b30e837b 343
75e0ec94
CF
344static void fabricd_bump_tier_calculation_timer(struct fabricd *f);
345static void fabricd_set_tier(struct fabricd *f, uint8_t tier);
346
347static uint8_t fabricd_calculate_fabric_tier(struct isis_area *area)
348{
349 struct isis_spftree *local_tree = fabricd_spftree(area);
350 struct listnode *node;
351
352 struct isis_vertex *furthest_t0 = NULL,
353 *second_furthest_t0 = NULL;
354
355 struct isis_vertex *v;
356
357 for (ALL_QUEUE_ELEMENTS_RO(&local_tree->paths, node, v)) {
358 struct isis_lsp *lsp = lsp_for_vertex(local_tree, v);
359
360 if (!lsp || !lsp->tlvs
361 || !lsp->tlvs->spine_leaf
362 || !lsp->tlvs->spine_leaf->has_tier
363 || lsp->tlvs->spine_leaf->tier != 0)
364 continue;
365
366 second_furthest_t0 = furthest_t0;
367 furthest_t0 = v;
368 }
369
370 if (!second_furthest_t0) {
371 zlog_info("OpenFabric: Could not find two T0 routers");
372 return ISIS_TIER_UNDEFINED;
373 }
374
375 zlog_info("OpenFabric: Found %s as furthest t0 from local system, dist == %"
376 PRIu32, rawlspid_print(furthest_t0->N.id), furthest_t0->d_N);
377
378 struct isis_spftree *remote_tree =
379 isis_run_hopcount_spf(area, furthest_t0->N.id, NULL);
380
381 struct isis_vertex *furthest_from_remote =
382 isis_vertex_queue_last(&remote_tree->paths);
383
384 if (!furthest_from_remote) {
385 zlog_info("OpenFabric: Found no furthest node in remote spf");
386 isis_spftree_del(remote_tree);
387 return ISIS_TIER_UNDEFINED;
388 } else {
389 zlog_info("OpenFabric: Found %s as furthest from remote dist == %"
390 PRIu32, rawlspid_print(furthest_from_remote->N.id),
391 furthest_from_remote->d_N);
392 }
393
394 int64_t tier = furthest_from_remote->d_N - furthest_t0->d_N;
395 isis_spftree_del(remote_tree);
396
397 if (tier < 0 || tier >= ISIS_TIER_UNDEFINED) {
398 zlog_info("OpenFabric: Calculated tier %" PRId64 " seems implausible",
399 tier);
400 return ISIS_TIER_UNDEFINED;
401 }
402
403 zlog_info("OpenFabric: Calculated %" PRId64 " as tier", tier);
404 return tier;
405}
406
407static int fabricd_tier_set_timer(struct thread *thread)
408{
409 struct fabricd *f = THREAD_ARG(thread);
410 f->tier_set_timer = NULL;
411
412 fabricd_set_tier(f, f->tier_pending);
413 return 0;
414}
415
416static int fabricd_tier_calculation_cb(struct thread *thread)
417{
418 struct fabricd *f = THREAD_ARG(thread);
419 uint8_t tier = ISIS_TIER_UNDEFINED;
420 f->tier_calculation_timer = NULL;
421
422 tier = fabricd_calculate_fabric_tier(f->area);
423 if (tier == ISIS_TIER_UNDEFINED)
424 return 0;
425
426 zlog_info("OpenFabric: Got tier %" PRIu8 " from algorithm. Arming timer.",
427 tier);
428 f->tier_pending = tier;
429 thread_add_timer(master, fabricd_tier_set_timer, f,
430 f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
431 &f->tier_set_timer);
432
433 return 0;
434}
435
436static void fabricd_bump_tier_calculation_timer(struct fabricd *f)
437{
438 /* Cancel timer if we already know our tier */
439 if (f->tier != ISIS_TIER_UNDEFINED
440 || f->tier_set_timer) {
441 if (f->tier_calculation_timer) {
442 thread_cancel(f->tier_calculation_timer);
443 f->tier_calculation_timer = NULL;
444 }
445 return;
446 }
447
448 /* If we need to calculate the tier, wait some
449 * time for the topology to settle before running
450 * the calculation */
451 if (f->tier_calculation_timer) {
452 thread_cancel(f->tier_calculation_timer);
453 f->tier_calculation_timer = NULL;
454 }
455
456 thread_add_timer(master, fabricd_tier_calculation_cb, f,
457 2 * f->area->lsp_gen_interval[ISIS_LEVEL2 - 1],
458 &f->tier_calculation_timer);
459}
460
92ed0cde
CF
461static void fabricd_set_tier(struct fabricd *f, uint8_t tier)
462{
463 if (f->tier == tier)
464 return;
465
75e0ec94 466 zlog_info("OpenFabric: Set own tier to %" PRIu8, tier);
92ed0cde
CF
467 f->tier = tier;
468
75e0ec94 469 fabricd_bump_tier_calculation_timer(f);
92ed0cde
CF
470 lsp_regenerate_schedule(f->area, ISIS_LEVEL2, 0);
471}
472
b30e837b
CF
473void fabricd_run_spf(struct isis_area *area)
474{
475 struct fabricd *f = area->fabricd;
476
477 if (!f)
478 return;
479
480 isis_run_hopcount_spf(area, isis->sysid, f->spftree);
2cd971af 481 neighbors_neighbors_update(f);
75e0ec94 482 fabricd_bump_tier_calculation_timer(f);
b30e837b
CF
483}
484
485struct isis_spftree *fabricd_spftree(struct isis_area *area)
486{
487 struct fabricd *f = area->fabricd;
488
489 if (!f)
490 return NULL;
491
492 return f->spftree;
493}
92ed0cde
CF
494
495void fabricd_configure_tier(struct isis_area *area, uint8_t tier)
496{
497 struct fabricd *f = area->fabricd;
498
499 if (!f || f->tier_config == tier)
500 return;
501
502 f->tier_config = tier;
503 fabricd_set_tier(f, tier);
504}
505
506uint8_t fabricd_tier(struct isis_area *area)
507{
508 struct fabricd *f = area->fabricd;
509
510 if (!f)
511 return ISIS_TIER_UNDEFINED;
512
513 return f->tier;
514}
515
516int fabricd_write_settings(struct isis_area *area, struct vty *vty)
517{
518 struct fabricd *f = area->fabricd;
519 int written = 0;
520
521 if (!f)
522 return written;
523
524 if (f->tier_config != ISIS_TIER_UNDEFINED) {
525 vty_out(vty, " fabric-tier %" PRIu8 "\n", f->tier_config);
526 written++;
527 }
528
e923107c
CF
529 if (f->csnp_delay != FABRICD_DEFAULT_CSNP_DELAY
530 || f->always_send_csnp) {
531 vty_out(vty, " triggered-csnp-delay %d%s\n", f->csnp_delay,
532 f->always_send_csnp ? " always" : "");
533 }
534
92ed0cde
CF
535 return written;
536}
9d224819 537
dc0dacfc 538static void move_to_queue(struct isis_lsp *lsp, struct neighbor_entry *n,
1eb7c3a1 539 enum isis_tx_type type, struct isis_circuit *circuit)
9d224819 540{
9d224819 541 n->present = false;
d4cff91a 542
1eb7c3a1
CF
543 if (n->adj && n->adj->circuit == circuit)
544 return;
545
ddb33326 546 if (isis->debugs & DEBUG_FLOODING) {
dc0dacfc
CF
547 zlog_debug("OpenFabric: Adding %s to %s",
548 print_sys_hostname(n->id),
549 (type == TX_LSP_NORMAL) ? "RF" : "DNR");
d4cff91a
CF
550 }
551
dc0dacfc
CF
552 if (n->adj)
553 isis_tx_queue_add(n->adj->circuit->tx_queue, lsp, type);
1eb7c3a1 554
89cdc4df
RM
555 uint8_t *neighbor_id = XMALLOC(MTYPE_FABRICD_FLOODING_INFO,
556 sizeof(n->id));
1eb7c3a1
CF
557
558 memcpy(neighbor_id, n->id, sizeof(n->id));
559 listnode_add(lsp->flooding_neighbors[type], neighbor_id);
9d224819
CF
560}
561
562static void mark_neighbor_as_present(struct hash_backet *backet, void *arg)
563{
564 struct neighbor_entry *n = backet->data;
565
566 n->present = true;
567}
568
569static void handle_firsthops(struct hash_backet *backet, void *arg)
570{
571 struct isis_lsp *lsp = arg;
572 struct fabricd *f = lsp->area->fabricd;
573 struct isis_vertex *vertex = backet->data;
574
575 struct neighbor_entry *n;
576
577 n = neighbor_entry_lookup_list(f->neighbors, vertex->N.id);
d4cff91a 578 if (n) {
ddb33326 579 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a 580 zlog_debug("Removing %s from NL as its in the reverse path",
dc0dacfc 581 print_sys_hostname(n->id));
d4cff91a 582 }
9d224819 583 n->present = false;
d4cff91a 584 }
9d224819
CF
585
586 n = neighbor_entry_lookup_hash(f->neighbors_neighbors, vertex->N.id);
d4cff91a 587 if (n) {
ddb33326 588 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a 589 zlog_debug("Removing %s from NN as its in the reverse path",
dc0dacfc 590 print_sys_hostname(n->id));
d4cff91a 591 }
9d224819 592 n->present = false;
d4cff91a 593 }
9d224819
CF
594}
595
dc0dacfc
CF
596static struct isis_lsp *lsp_for_neighbor(struct fabricd *f,
597 struct neighbor_entry *n)
598{
599 uint8_t id[ISIS_SYS_ID_LEN + 1] = {0};
600
601 memcpy(id, n->id, sizeof(n->id));
602
603 struct isis_vertex vertex = {0};
604
605 isis_vertex_id_init(&vertex, id, VTYPE_NONPSEUDO_TE_IS);
606
607 return lsp_for_vertex(f->spftree, &vertex);
608}
609
1eb7c3a1
CF
610static void fabricd_free_lsp_flooding_info(void *val)
611{
612 XFREE(MTYPE_FABRICD_FLOODING_INFO, val);
613}
614
615static void fabricd_lsp_reset_flooding_info(struct isis_lsp *lsp,
616 struct isis_circuit *circuit)
617{
a6b60da9
CF
618 lsp->flooding_time = time(NULL);
619
1eb7c3a1
CF
620 XFREE(MTYPE_FABRICD_FLOODING_INFO, lsp->flooding_interface);
621 for (enum isis_tx_type type = TX_LSP_NORMAL;
622 type <= TX_LSP_CIRCUIT_SCOPED; type++) {
623 if (lsp->flooding_neighbors[type]) {
624 list_delete_all_node(lsp->flooding_neighbors[type]);
625 continue;
626 }
627
628 lsp->flooding_neighbors[type] = list_new();
89cdc4df
RM
629 lsp->flooding_neighbors[type]->del =
630 fabricd_free_lsp_flooding_info;
1eb7c3a1
CF
631 }
632
633 if (circuit) {
634 lsp->flooding_interface = XSTRDUP(MTYPE_FABRICD_FLOODING_INFO,
635 circuit->interface->name);
636 }
a6b60da9
CF
637
638 lsp->flooding_circuit_scoped = false;
1eb7c3a1
CF
639}
640
641void fabricd_lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit)
9d224819
CF
642{
643 struct fabricd *f = lsp->area->fabricd;
644 assert(f);
645
1eb7c3a1
CF
646 fabricd_lsp_reset_flooding_info(lsp, circuit);
647
9d224819
CF
648 void *cursor = NULL;
649 struct neighbor_entry *n;
650
e5b0aaf1 651 /* Mark all elements in NL as present */
89cdc4df 652 while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor))
9d224819 653 n->present = true;
9d224819
CF
654
655 /* Mark all elements in NN as present */
656 hash_iterate(f->neighbors_neighbors, mark_neighbor_as_present, NULL);
657
89cdc4df
RM
658 struct isis_vertex *originator =
659 isis_find_vertex(&f->spftree->paths,
660 lsp->hdr.lsp_id,
661 VTYPE_NONPSEUDO_TE_IS);
9d224819
CF
662
663 /* Remove all IS from NL and NN in the shortest path
664 * to the IS that originated the LSP */
665 if (originator)
666 hash_iterate(originator->firsthops, handle_firsthops, lsp);
667
668 /* Iterate over all remaining IS in NL */
669 cursor = NULL;
670 while (!skiplist_next(f->neighbors, NULL, (void **)&n, &cursor)) {
671 if (!n->present)
672 continue;
673
dc0dacfc 674 struct isis_lsp *nlsp = lsp_for_neighbor(f, n);
9d224819 675 if (!nlsp || !nlsp->tlvs) {
ddb33326 676 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a 677 zlog_debug("Moving %s to DNR as it has no LSP",
dc0dacfc 678 print_sys_hostname(n->id));
d4cff91a
CF
679 }
680
1eb7c3a1 681 move_to_queue(lsp, n, TX_LSP_CIRCUIT_SCOPED, circuit);
9d224819
CF
682 continue;
683 }
684
ddb33326 685 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a 686 zlog_debug("Considering %s from NL...",
dc0dacfc 687 print_sys_hostname(n->id));
d4cff91a
CF
688 }
689
9d224819
CF
690 /* For all neighbors of the NL IS check whether they are present
691 * in NN. If yes, remove from NN and set need_reflood. */
692 bool need_reflood = false;
693 struct isis_extended_reach *er;
694 for (er = (struct isis_extended_reach *)nlsp->tlvs->extended_reach.head;
695 er; er = er->next) {
696 struct neighbor_entry *nn;
697
698 nn = neighbor_entry_lookup_hash(f->neighbors_neighbors,
699 er->id);
700
701 if (nn) {
ddb33326 702 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a 703 zlog_debug("Found neighbor %s in NN, removing it from NN and setting reflood.",
dc0dacfc 704 print_sys_hostname(nn->id));
d4cff91a
CF
705 }
706
9d224819
CF
707 nn->present = false;
708 need_reflood = true;
709 }
710 }
711
dc0dacfc 712 move_to_queue(lsp, n, need_reflood ?
1eb7c3a1
CF
713 TX_LSP_NORMAL : TX_LSP_CIRCUIT_SCOPED,
714 circuit);
9d224819 715 }
d4cff91a 716
ddb33326 717 if (isis->debugs & DEBUG_FLOODING) {
d4cff91a
CF
718 zlog_debug("OpenFabric: Flooding algorithm complete.");
719 }
9d224819 720}
df0ba689 721
e923107c 722void fabricd_trigger_csnp(struct isis_area *area, bool circuit_scoped)
df0ba689
CF
723{
724 struct fabricd *f = area->fabricd;
725
726 if (!f)
727 return;
728
e923107c
CF
729 if (!circuit_scoped && !f->always_send_csnp)
730 return;
731
df0ba689
CF
732 struct listnode *node;
733 struct isis_circuit *circuit;
734
735 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
736 if (!circuit->t_send_csnp[1])
737 continue;
738
739 thread_cancel(circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
740 thread_add_timer_msec(master, send_l2_csnp, circuit,
e923107c 741 isis_jitter(f->csnp_delay, CSNP_JITTER),
df0ba689
CF
742 &circuit->t_send_csnp[ISIS_LEVEL2 - 1]);
743 }
744}
41415888
CF
745
746struct list *fabricd_ip_addrs(struct isis_circuit *circuit)
747{
748 if (circuit->ip_addrs && listcount(circuit->ip_addrs))
749 return circuit->ip_addrs;
750
751 if (!fabricd || !circuit->area || !circuit->area->circuit_list)
752 return NULL;
753
754 struct listnode *node;
755 struct isis_circuit *c;
756
757 for (ALL_LIST_ELEMENTS_RO(circuit->area->circuit_list, node, c)) {
758 if (c->circ_type != CIRCUIT_T_LOOPBACK)
759 continue;
760
761 if (!c->ip_addrs || !listcount(c->ip_addrs))
762 return NULL;
763
764 return c->ip_addrs;
765 }
766
767 return NULL;
768}
1eb7c3a1
CF
769
770void fabricd_lsp_free(struct isis_lsp *lsp)
771{
772 XFREE(MTYPE_FABRICD_FLOODING_INFO, lsp->flooding_interface);
773 for (enum isis_tx_type type = TX_LSP_NORMAL;
774 type <= TX_LSP_CIRCUIT_SCOPED; type++) {
775 if (!lsp->flooding_neighbors[type])
776 continue;
777
778 list_delete(&lsp->flooding_neighbors[type]);
779 }
780}
a6b60da9
CF
781
782void fabricd_update_lsp_no_flood(struct isis_lsp *lsp,
783 struct isis_circuit *circuit)
784{
785 if (!fabricd)
786 return;
787
788 fabricd_lsp_reset_flooding_info(lsp, circuit);
789 lsp->flooding_circuit_scoped = true;
790}
e923107c
CF
791
792void fabricd_configure_triggered_csnp(struct isis_area *area, int delay,
793 bool always_send_csnp)
794{
795 struct fabricd *f = area->fabricd;
796
797 if (!f)
798 return;
799
800 f->csnp_delay = delay;
801 f->always_send_csnp = always_send_csnp;
802}
2cd971af
CF
803
804void fabricd_init(void)
805{
806 hook_register(isis_adj_state_change_hook,
807 fabricd_handle_adj_state_change);
808}