]>
Commit | Line | Data |
---|---|---|
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 | |
35 | DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric") | |
1f5be499 | 36 | DEFINE_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 | */ | |
43 | enum fabricd_sync_state { | |
44 | FABRICD_SYNC_PENDING, | |
45 | FABRICD_SYNC_STARTED, | |
46 | FABRICD_SYNC_COMPLETE | |
47 | }; | |
48 | ||
49 | struct 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 | ||
70 | struct neighbor_entry { | |
71 | struct isis_vertex *vertex; | |
72 | bool present; | |
73 | }; | |
74 | ||
75 | static 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 | ||
83 | static void neighbor_entry_del(struct neighbor_entry *neighbor) | |
84 | { | |
85 | XFREE(MTYPE_FABRICD_NEIGHBOR, neighbor); | |
86 | } | |
87 | ||
88 | static void neighbor_entry_del_void(void *arg) | |
89 | { | |
90 | neighbor_entry_del((struct neighbor_entry *)arg); | |
91 | } | |
92 | ||
93 | static 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 | ||
101 | static 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 | 108 | static 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 | ||
115 | static 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 |
122 | static 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 | ||
143 | static 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 |
161 | static 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 | 186 | struct 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 |
204 | void 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 |
221 | static 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 | ||
233 | void 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 | ||
260 | bool 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 |
274 | bool 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 |
284 | struct 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 | ||
293 | void 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 |
311 | static void fabricd_bump_tier_calculation_timer(struct fabricd *f); |
312 | static void fabricd_set_tier(struct fabricd *f, uint8_t tier); | |
313 | ||
314 | static 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 | ||
374 | static 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 | ||
383 | static 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 | ||
403 | static 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 |
428 | static 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 |
440 | void 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 | ||
452 | struct 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 | |
462 | void 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 | ||
473 | uint8_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 | ||
483 | int 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 | |
499 | static 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 | ||
517 | static 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 | ||
535 | static 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 | ||
542 | static 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 | ||
571 | void 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 | |
676 | void 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 | |
697 | struct 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 | } |