2 * IS-IS Rout(e)ing protocol - OpenFabric extensions
4 * Copyright (C) 2018 Christian Franke
6 * This file is part of FreeRangeRouting (FRR)
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
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.
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
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"
29 #include "isisd/isis_spf.h"
30 #include "isisd/isis_tlvs.h"
31 #include "isisd/isis_lsp.h"
32 #include "isisd/isis_spf_private.h"
33 #include "isisd/isis_tx_queue.h"
34 #include "isisd/isis_csm.h"
36 DEFINE_MTYPE_STATIC(ISISD
, FABRICD_STATE
, "ISIS OpenFabric")
37 DEFINE_MTYPE_STATIC(ISISD
, FABRICD_NEIGHBOR
, "ISIS OpenFabric Neighbor Entry")
38 DEFINE_MTYPE_STATIC(ISISD
, FABRICD_FLOODING_INFO
, "ISIS OpenFabric Flooding Log")
40 /* Tracks initial synchronization as per section 2.4
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.
45 enum fabricd_sync_state
{
52 struct isis_area
*area
;
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
;
59 struct isis_spftree
*spftree
;
60 struct skiplist
*neighbors
;
61 struct hash
*neighbors_neighbors
;
66 struct thread
*tier_calculation_timer
;
67 struct thread
*tier_set_timer
;
70 bool always_send_csnp
;
73 /* Code related to maintaining the neighbor lists */
75 struct neighbor_entry
{
76 uint8_t id
[ISIS_SYS_ID_LEN
];
77 struct isis_adjacency
*adj
;
81 static struct neighbor_entry
*neighbor_entry_new(const uint8_t *id
,
82 struct isis_adjacency
*adj
)
84 struct neighbor_entry
*rv
= XMALLOC(MTYPE_FABRICD_NEIGHBOR
, sizeof(*rv
));
86 memcpy(rv
->id
, id
, sizeof(rv
->id
));
92 static void neighbor_entry_del(struct neighbor_entry
*neighbor
)
94 XFREE(MTYPE_FABRICD_NEIGHBOR
, neighbor
);
97 static void neighbor_entry_del_void(void *arg
)
99 neighbor_entry_del((struct neighbor_entry
*)arg
);
102 static void neighbor_lists_clear(struct fabricd
*f
)
104 while (!skiplist_empty(f
->neighbors
))
105 skiplist_delete_first(f
->neighbors
);
107 hash_clean(f
->neighbors_neighbors
, neighbor_entry_del_void
);
110 static unsigned neighbor_entry_hash_key(void *np
)
112 struct neighbor_entry
*n
= np
;
114 return jhash(n
->id
, sizeof(n
->id
), 0x55aa5a5a);
117 static bool neighbor_entry_hash_cmp(const void *a
, const void *b
)
119 const struct neighbor_entry
*na
= a
, *nb
= b
;
121 return memcmp(na
->id
, nb
->id
, sizeof(na
->id
)) == 0;
124 static int neighbor_entry_list_cmp(void *a
, void *b
)
126 struct neighbor_entry
*na
= a
, *nb
= b
;
128 return -memcmp(na
->id
, nb
->id
, sizeof(na
->id
));
131 static struct neighbor_entry
*neighbor_entry_lookup_list(struct skiplist
*list
,
134 struct neighbor_entry n
= {{0}};
136 memcpy(n
.id
, id
, sizeof(n
.id
));
138 struct neighbor_entry
*rv
;
140 if (skiplist_search(list
, &n
, (void**)&rv
))
149 static struct neighbor_entry
*neighbor_entry_lookup_hash(struct hash
*hash
,
152 struct neighbor_entry n
= {{0}};
154 memcpy(n
.id
, id
, sizeof(n
.id
));
156 struct neighbor_entry
*rv
= hash_lookup(hash
, &n
);
158 if (!rv
|| !rv
->present
)
164 static void neighbor_lists_update(struct fabricd
*f
)
166 neighbor_lists_clear(f
);
168 struct listnode
*node
;
169 struct isis_circuit
*circuit
;
171 for (ALL_LIST_ELEMENTS_RO(f
->area
->circuit_list
, node
, circuit
)) {
172 if (circuit
->state
!= C_STATE_UP
)
175 struct isis_adjacency
*adj
= circuit
->u
.p2p
.neighbor
;
177 if (!adj
|| adj
->adj_state
!= ISIS_ADJ_UP
)
180 struct neighbor_entry
*n
= neighbor_entry_new(adj
->sysid
, adj
);
182 skiplist_insert(f
->neighbors
, n
, n
);
185 struct isis_vertex
*v
;
187 for (ALL_QUEUE_ELEMENTS_RO(&f
->spftree
->paths
, node
, v
)) {
188 if (v
->d_N
< 2 || !VTYPE_IS(v
->type
))
194 struct neighbor_entry
*n
= neighbor_entry_new(v
->N
.id
, NULL
);
195 struct neighbor_entry
*inserted
;
196 inserted
= hash_get(f
->neighbors_neighbors
, n
,
198 assert(inserted
== n
);
202 struct fabricd
*fabricd_new(struct isis_area
*area
)
204 struct fabricd
*rv
= XCALLOC(MTYPE_FABRICD_STATE
, sizeof(*rv
));
207 rv
->initial_sync_state
= FABRICD_SYNC_PENDING
;
209 rv
->spftree
= isis_spftree_new(area
);
210 rv
->neighbors
= skiplist_new(0, neighbor_entry_list_cmp
,
211 neighbor_entry_del_void
);
212 rv
->neighbors_neighbors
= hash_create(neighbor_entry_hash_key
,
213 neighbor_entry_hash_cmp
,
214 "Fabricd Neighbors");
216 rv
->tier
= rv
->tier_config
= ISIS_TIER_UNDEFINED
;
218 rv
->csnp_delay
= FABRICD_DEFAULT_CSNP_DELAY
;
222 void fabricd_finish(struct fabricd
*f
)
224 if (f
->initial_sync_timeout
)
225 thread_cancel(f
->initial_sync_timeout
);
227 if (f
->tier_calculation_timer
)
228 thread_cancel(f
->tier_calculation_timer
);
230 if (f
->tier_set_timer
)
231 thread_cancel(f
->tier_set_timer
);
233 isis_spftree_del(f
->spftree
);
234 neighbor_lists_clear(f
);
235 skiplist_free(f
->neighbors
);
236 hash_free(f
->neighbors_neighbors
);
239 static int fabricd_initial_sync_timeout(struct thread
*thread
)
241 struct fabricd
*f
= THREAD_ARG(thread
);
243 zlog_info("OpenFabric: Initial synchronization on %s timed out!",
244 f
->initial_sync_circuit
->interface
->name
);
245 f
->initial_sync_state
= FABRICD_SYNC_PENDING
;
246 f
->initial_sync_circuit
= NULL
;
247 f
->initial_sync_timeout
= NULL
;
251 void fabricd_initial_sync_hello(struct isis_circuit
*circuit
)
253 struct fabricd
*f
= circuit
->area
->fabricd
;
258 if (f
->initial_sync_state
> FABRICD_SYNC_PENDING
)
261 f
->initial_sync_state
= FABRICD_SYNC_STARTED
;
263 long timeout
= 2 * circuit
->hello_interval
[1] * circuit
->hello_multiplier
[1];
265 f
->initial_sync_circuit
= circuit
;
266 if (f
->initial_sync_timeout
)
269 thread_add_timer(master
, fabricd_initial_sync_timeout
, f
,
270 timeout
, &f
->initial_sync_timeout
);
271 f
->initial_sync_start
= monotime(NULL
);
273 zlog_info("OpenFabric: Started initial synchronization with %s on %s",
274 sysid_print(circuit
->u
.p2p
.neighbor
->sysid
),
275 circuit
->interface
->name
);
278 bool fabricd_initial_sync_is_in_progress(struct isis_area
*area
)
280 struct fabricd
*f
= area
->fabricd
;
285 if (f
->initial_sync_state
> FABRICD_SYNC_PENDING
286 && f
->initial_sync_state
< FABRICD_SYNC_COMPLETE
)
292 bool fabricd_initial_sync_is_complete(struct isis_area
*area
)
294 struct fabricd
*f
= area
->fabricd
;
299 return f
->initial_sync_state
== FABRICD_SYNC_COMPLETE
;
302 struct isis_circuit
*fabricd_initial_sync_circuit(struct isis_area
*area
)
304 struct fabricd
*f
= area
->fabricd
;
308 return f
->initial_sync_circuit
;
311 void fabricd_initial_sync_finish(struct isis_area
*area
)
313 struct fabricd
*f
= area
->fabricd
;
318 if (monotime(NULL
) - f
->initial_sync_start
< 5)
321 zlog_info("OpenFabric: Initial synchronization on %s complete.",
322 f
->initial_sync_circuit
->interface
->name
);
323 f
->initial_sync_state
= FABRICD_SYNC_COMPLETE
;
324 f
->initial_sync_circuit
= NULL
;
325 thread_cancel(f
->initial_sync_timeout
);
326 f
->initial_sync_timeout
= NULL
;
329 static void fabricd_bump_tier_calculation_timer(struct fabricd
*f
);
330 static void fabricd_set_tier(struct fabricd
*f
, uint8_t tier
);
332 static uint8_t fabricd_calculate_fabric_tier(struct isis_area
*area
)
334 struct isis_spftree
*local_tree
= fabricd_spftree(area
);
335 struct listnode
*node
;
337 struct isis_vertex
*furthest_t0
= NULL
,
338 *second_furthest_t0
= NULL
;
340 struct isis_vertex
*v
;
342 for (ALL_QUEUE_ELEMENTS_RO(&local_tree
->paths
, node
, v
)) {
343 struct isis_lsp
*lsp
= lsp_for_vertex(local_tree
, v
);
345 if (!lsp
|| !lsp
->tlvs
346 || !lsp
->tlvs
->spine_leaf
347 || !lsp
->tlvs
->spine_leaf
->has_tier
348 || lsp
->tlvs
->spine_leaf
->tier
!= 0)
351 second_furthest_t0
= furthest_t0
;
355 if (!second_furthest_t0
) {
356 zlog_info("OpenFabric: Could not find two T0 routers");
357 return ISIS_TIER_UNDEFINED
;
360 zlog_info("OpenFabric: Found %s as furthest t0 from local system, dist == %"
361 PRIu32
, rawlspid_print(furthest_t0
->N
.id
), furthest_t0
->d_N
);
363 struct isis_spftree
*remote_tree
=
364 isis_run_hopcount_spf(area
, furthest_t0
->N
.id
, NULL
);
366 struct isis_vertex
*furthest_from_remote
=
367 isis_vertex_queue_last(&remote_tree
->paths
);
369 if (!furthest_from_remote
) {
370 zlog_info("OpenFabric: Found no furthest node in remote spf");
371 isis_spftree_del(remote_tree
);
372 return ISIS_TIER_UNDEFINED
;
374 zlog_info("OpenFabric: Found %s as furthest from remote dist == %"
375 PRIu32
, rawlspid_print(furthest_from_remote
->N
.id
),
376 furthest_from_remote
->d_N
);
379 int64_t tier
= furthest_from_remote
->d_N
- furthest_t0
->d_N
;
380 isis_spftree_del(remote_tree
);
382 if (tier
< 0 || tier
>= ISIS_TIER_UNDEFINED
) {
383 zlog_info("OpenFabric: Calculated tier %" PRId64
" seems implausible",
385 return ISIS_TIER_UNDEFINED
;
388 zlog_info("OpenFabric: Calculated %" PRId64
" as tier", tier
);
392 static int fabricd_tier_set_timer(struct thread
*thread
)
394 struct fabricd
*f
= THREAD_ARG(thread
);
395 f
->tier_set_timer
= NULL
;
397 fabricd_set_tier(f
, f
->tier_pending
);
401 static int fabricd_tier_calculation_cb(struct thread
*thread
)
403 struct fabricd
*f
= THREAD_ARG(thread
);
404 uint8_t tier
= ISIS_TIER_UNDEFINED
;
405 f
->tier_calculation_timer
= NULL
;
407 tier
= fabricd_calculate_fabric_tier(f
->area
);
408 if (tier
== ISIS_TIER_UNDEFINED
)
411 zlog_info("OpenFabric: Got tier %" PRIu8
" from algorithm. Arming timer.",
413 f
->tier_pending
= tier
;
414 thread_add_timer(master
, fabricd_tier_set_timer
, f
,
415 f
->area
->lsp_gen_interval
[ISIS_LEVEL2
- 1],
421 static void fabricd_bump_tier_calculation_timer(struct fabricd
*f
)
423 /* Cancel timer if we already know our tier */
424 if (f
->tier
!= ISIS_TIER_UNDEFINED
425 || f
->tier_set_timer
) {
426 if (f
->tier_calculation_timer
) {
427 thread_cancel(f
->tier_calculation_timer
);
428 f
->tier_calculation_timer
= NULL
;
433 /* If we need to calculate the tier, wait some
434 * time for the topology to settle before running
436 if (f
->tier_calculation_timer
) {
437 thread_cancel(f
->tier_calculation_timer
);
438 f
->tier_calculation_timer
= NULL
;
441 thread_add_timer(master
, fabricd_tier_calculation_cb
, f
,
442 2 * f
->area
->lsp_gen_interval
[ISIS_LEVEL2
- 1],
443 &f
->tier_calculation_timer
);
446 static void fabricd_set_tier(struct fabricd
*f
, uint8_t tier
)
451 zlog_info("OpenFabric: Set own tier to %" PRIu8
, tier
);
454 fabricd_bump_tier_calculation_timer(f
);
455 lsp_regenerate_schedule(f
->area
, ISIS_LEVEL2
, 0);
458 void fabricd_run_spf(struct isis_area
*area
)
460 struct fabricd
*f
= area
->fabricd
;
465 isis_run_hopcount_spf(area
, isis
->sysid
, f
->spftree
);
466 neighbor_lists_update(f
);
467 fabricd_bump_tier_calculation_timer(f
);
470 struct isis_spftree
*fabricd_spftree(struct isis_area
*area
)
472 struct fabricd
*f
= area
->fabricd
;
480 void fabricd_configure_tier(struct isis_area
*area
, uint8_t tier
)
482 struct fabricd
*f
= area
->fabricd
;
484 if (!f
|| f
->tier_config
== tier
)
487 f
->tier_config
= tier
;
488 fabricd_set_tier(f
, tier
);
491 uint8_t fabricd_tier(struct isis_area
*area
)
493 struct fabricd
*f
= area
->fabricd
;
496 return ISIS_TIER_UNDEFINED
;
501 int fabricd_write_settings(struct isis_area
*area
, struct vty
*vty
)
503 struct fabricd
*f
= area
->fabricd
;
509 if (f
->tier_config
!= ISIS_TIER_UNDEFINED
) {
510 vty_out(vty
, " fabric-tier %" PRIu8
"\n", f
->tier_config
);
514 if (f
->csnp_delay
!= FABRICD_DEFAULT_CSNP_DELAY
515 || f
->always_send_csnp
) {
516 vty_out(vty
, " triggered-csnp-delay %d%s\n", f
->csnp_delay
,
517 f
->always_send_csnp
? " always" : "");
523 static void move_to_queue(struct isis_lsp
*lsp
, struct neighbor_entry
*n
,
524 enum isis_tx_type type
, struct isis_circuit
*circuit
)
528 if (n
->adj
&& n
->adj
->circuit
== circuit
)
531 if (isis
->debugs
& DEBUG_FLOODING
) {
532 zlog_debug("OpenFabric: Adding %s to %s",
533 print_sys_hostname(n
->id
),
534 (type
== TX_LSP_NORMAL
) ? "RF" : "DNR");
538 isis_tx_queue_add(n
->adj
->circuit
->tx_queue
, lsp
, type
);
540 uint8_t *neighbor_id
= XMALLOC(MTYPE_FABRICD_FLOODING_INFO
, sizeof(n
->id
));
542 memcpy(neighbor_id
, n
->id
, sizeof(n
->id
));
543 listnode_add(lsp
->flooding_neighbors
[type
], neighbor_id
);
546 static void mark_neighbor_as_present(struct hash_backet
*backet
, void *arg
)
548 struct neighbor_entry
*n
= backet
->data
;
553 static void handle_firsthops(struct hash_backet
*backet
, void *arg
)
555 struct isis_lsp
*lsp
= arg
;
556 struct fabricd
*f
= lsp
->area
->fabricd
;
557 struct isis_vertex
*vertex
= backet
->data
;
559 struct neighbor_entry
*n
;
561 n
= neighbor_entry_lookup_list(f
->neighbors
, vertex
->N
.id
);
563 if (isis
->debugs
& DEBUG_FLOODING
) {
564 zlog_debug("Removing %s from NL as its in the reverse path",
565 print_sys_hostname(n
->id
));
570 n
= neighbor_entry_lookup_hash(f
->neighbors_neighbors
, vertex
->N
.id
);
572 if (isis
->debugs
& DEBUG_FLOODING
) {
573 zlog_debug("Removing %s from NN as its in the reverse path",
574 print_sys_hostname(n
->id
));
580 static struct isis_lsp
*lsp_for_neighbor(struct fabricd
*f
,
581 struct neighbor_entry
*n
)
583 uint8_t id
[ISIS_SYS_ID_LEN
+ 1] = {0};
585 memcpy(id
, n
->id
, sizeof(n
->id
));
587 struct isis_vertex vertex
= {0};
589 isis_vertex_id_init(&vertex
, id
, VTYPE_NONPSEUDO_TE_IS
);
591 return lsp_for_vertex(f
->spftree
, &vertex
);
594 static void fabricd_free_lsp_flooding_info(void *val
)
596 XFREE(MTYPE_FABRICD_FLOODING_INFO
, val
);
599 static void fabricd_lsp_reset_flooding_info(struct isis_lsp
*lsp
,
600 struct isis_circuit
*circuit
)
602 lsp
->flooding_time
= time(NULL
);
604 XFREE(MTYPE_FABRICD_FLOODING_INFO
, lsp
->flooding_interface
);
605 for (enum isis_tx_type type
= TX_LSP_NORMAL
;
606 type
<= TX_LSP_CIRCUIT_SCOPED
; type
++) {
607 if (lsp
->flooding_neighbors
[type
]) {
608 list_delete_all_node(lsp
->flooding_neighbors
[type
]);
612 lsp
->flooding_neighbors
[type
] = list_new();
613 lsp
->flooding_neighbors
[type
]->del
= fabricd_free_lsp_flooding_info
;
617 lsp
->flooding_interface
= XSTRDUP(MTYPE_FABRICD_FLOODING_INFO
,
618 circuit
->interface
->name
);
621 lsp
->flooding_circuit_scoped
= false;
624 void fabricd_lsp_flood(struct isis_lsp
*lsp
, struct isis_circuit
*circuit
)
626 struct fabricd
*f
= lsp
->area
->fabricd
;
629 fabricd_lsp_reset_flooding_info(lsp
, circuit
);
632 struct neighbor_entry
*n
;
634 /* Mark all elements in NL as present and move T0s into DNR */
635 while (!skiplist_next(f
->neighbors
, NULL
, (void **)&n
, &cursor
)) {
638 struct isis_lsp
*node_lsp
= lsp_for_neighbor(f
, n
);
641 || !node_lsp
->tlvs
->spine_leaf
642 || !node_lsp
->tlvs
->spine_leaf
->has_tier
643 || node_lsp
->tlvs
->spine_leaf
->tier
!= 0) {
647 if (isis
->debugs
& DEBUG_FLOODING
) {
648 zlog_debug("Moving %s to DNR because it's T0",
649 rawlspid_print(node_lsp
->hdr
.lsp_id
));
652 move_to_queue(lsp
, n
, TX_LSP_CIRCUIT_SCOPED
, circuit
);
655 /* Mark all elements in NN as present */
656 hash_iterate(f
->neighbors_neighbors
, mark_neighbor_as_present
, NULL
);
658 struct isis_vertex
*originator
= isis_find_vertex(&f
->spftree
->paths
,
660 VTYPE_NONPSEUDO_TE_IS
);
662 /* Remove all IS from NL and NN in the shortest path
663 * to the IS that originated the LSP */
665 hash_iterate(originator
->firsthops
, handle_firsthops
, lsp
);
667 /* Iterate over all remaining IS in NL */
669 while (!skiplist_next(f
->neighbors
, NULL
, (void **)&n
, &cursor
)) {
673 struct isis_lsp
*nlsp
= lsp_for_neighbor(f
, n
);
674 if (!nlsp
|| !nlsp
->tlvs
) {
675 if (isis
->debugs
& DEBUG_FLOODING
) {
676 zlog_debug("Moving %s to DNR as it has no LSP",
677 print_sys_hostname(n
->id
));
680 move_to_queue(lsp
, n
, TX_LSP_CIRCUIT_SCOPED
, circuit
);
684 if (isis
->debugs
& DEBUG_FLOODING
) {
685 zlog_debug("Considering %s from NL...",
686 print_sys_hostname(n
->id
));
689 /* For all neighbors of the NL IS check whether they are present
690 * in NN. If yes, remove from NN and set need_reflood. */
691 bool need_reflood
= false;
692 struct isis_extended_reach
*er
;
693 for (er
= (struct isis_extended_reach
*)nlsp
->tlvs
->extended_reach
.head
;
695 struct neighbor_entry
*nn
;
697 nn
= neighbor_entry_lookup_hash(f
->neighbors_neighbors
,
701 if (isis
->debugs
& DEBUG_FLOODING
) {
702 zlog_debug("Found neighbor %s in NN, removing it from NN and setting reflood.",
703 print_sys_hostname(nn
->id
));
711 move_to_queue(lsp
, n
, need_reflood
?
712 TX_LSP_NORMAL
: TX_LSP_CIRCUIT_SCOPED
,
716 if (isis
->debugs
& DEBUG_FLOODING
) {
717 zlog_debug("OpenFabric: Flooding algorithm complete.");
721 void fabricd_trigger_csnp(struct isis_area
*area
, bool circuit_scoped
)
723 struct fabricd
*f
= area
->fabricd
;
728 if (!circuit_scoped
&& !f
->always_send_csnp
)
731 struct listnode
*node
;
732 struct isis_circuit
*circuit
;
734 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
)) {
735 if (!circuit
->t_send_csnp
[1])
738 thread_cancel(circuit
->t_send_csnp
[ISIS_LEVEL2
- 1]);
739 thread_add_timer_msec(master
, send_l2_csnp
, circuit
,
740 isis_jitter(f
->csnp_delay
, CSNP_JITTER
),
741 &circuit
->t_send_csnp
[ISIS_LEVEL2
- 1]);
745 struct list
*fabricd_ip_addrs(struct isis_circuit
*circuit
)
747 if (circuit
->ip_addrs
&& listcount(circuit
->ip_addrs
))
748 return circuit
->ip_addrs
;
750 if (!fabricd
|| !circuit
->area
|| !circuit
->area
->circuit_list
)
753 struct listnode
*node
;
754 struct isis_circuit
*c
;
756 for (ALL_LIST_ELEMENTS_RO(circuit
->area
->circuit_list
, node
, c
)) {
757 if (c
->circ_type
!= CIRCUIT_T_LOOPBACK
)
760 if (!c
->ip_addrs
|| !listcount(c
->ip_addrs
))
769 void fabricd_lsp_free(struct isis_lsp
*lsp
)
771 XFREE(MTYPE_FABRICD_FLOODING_INFO
, lsp
->flooding_interface
);
772 for (enum isis_tx_type type
= TX_LSP_NORMAL
;
773 type
<= TX_LSP_CIRCUIT_SCOPED
; type
++) {
774 if (!lsp
->flooding_neighbors
[type
])
777 list_delete(&lsp
->flooding_neighbors
[type
]);
781 void fabricd_update_lsp_no_flood(struct isis_lsp
*lsp
,
782 struct isis_circuit
*circuit
)
787 fabricd_lsp_reset_flooding_info(lsp
, circuit
);
788 lsp
->flooding_circuit_scoped
= true;
791 void fabricd_configure_triggered_csnp(struct isis_area
*area
, int delay
,
792 bool always_send_csnp
)
794 struct fabricd
*f
= area
->fabricd
;
799 f
->csnp_delay
= delay
;
800 f
->always_send_csnp
= always_send_csnp
;