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