]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_flood.c
ospf6d: introduce support for Graceful Restart (restarting mode)
[mirror_frr.git] / ospf6d / ospf6_flood.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "thread.h"
25 #include "linklist.h"
26 #include "vty.h"
27 #include "command.h"
28
29 #include "ospf6d.h"
30 #include "ospf6_proto.h"
31 #include "ospf6_lsa.h"
32 #include "ospf6_lsdb.h"
33 #include "ospf6_message.h"
34 #include "ospf6_route.h"
35 #include "ospf6_spf.h"
36
37 #include "ospf6_top.h"
38 #include "ospf6_area.h"
39 #include "ospf6_interface.h"
40 #include "ospf6_neighbor.h"
41
42 #include "ospf6_flood.h"
43 #include "ospf6_nssa.h"
44 #include "ospf6_gr.h"
45
46 unsigned char conf_debug_ospf6_flooding;
47
48 struct ospf6_lsdb *ospf6_get_scoped_lsdb(struct ospf6_lsa *lsa)
49 {
50 struct ospf6_lsdb *lsdb = NULL;
51 switch (OSPF6_LSA_SCOPE(lsa->header->type)) {
52 case OSPF6_SCOPE_LINKLOCAL:
53 lsdb = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb;
54 break;
55 case OSPF6_SCOPE_AREA:
56 lsdb = OSPF6_AREA(lsa->lsdb->data)->lsdb;
57 break;
58 case OSPF6_SCOPE_AS:
59 lsdb = OSPF6_PROCESS(lsa->lsdb->data)->lsdb;
60 break;
61 default:
62 assert(0);
63 break;
64 }
65 return lsdb;
66 }
67
68 struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa)
69 {
70 struct ospf6_lsdb *lsdb_self = NULL;
71 switch (OSPF6_LSA_SCOPE(lsa->header->type)) {
72 case OSPF6_SCOPE_LINKLOCAL:
73 lsdb_self = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb_self;
74 break;
75 case OSPF6_SCOPE_AREA:
76 lsdb_self = OSPF6_AREA(lsa->lsdb->data)->lsdb_self;
77 break;
78 case OSPF6_SCOPE_AS:
79 lsdb_self = OSPF6_PROCESS(lsa->lsdb->data)->lsdb_self;
80 break;
81 default:
82 assert(0);
83 break;
84 }
85 return lsdb_self;
86 }
87
88 void ospf6_lsa_originate(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
89 {
90 struct ospf6_lsa *old;
91 struct ospf6_lsdb *lsdb_self;
92
93 if (lsa->header->adv_router == INADDR_ANY) {
94 if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
95 zlog_debug(
96 "Refusing to originate LSA (zero router ID): %s",
97 lsa->name);
98
99 ospf6_lsa_delete(lsa);
100 return;
101 }
102
103 /* find previous LSA */
104 old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
105 lsa->header->adv_router, lsa->lsdb);
106
107 /* if the new LSA does not differ from previous,
108 suppress this update of the LSA */
109 if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)
110 && !ospf6->gr_info.finishing_restart) {
111 if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
112 zlog_debug("Suppress updating LSA: %s", lsa->name);
113 ospf6_lsa_delete(lsa);
114 return;
115 }
116
117 /* store it in the LSDB for self-originated LSAs */
118 lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
119 ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self);
120
121 THREAD_OFF(lsa->refresh);
122 thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME,
123 &lsa->refresh);
124
125 if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
126 || IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type)) {
127 zlog_debug("LSA Originate:");
128 ospf6_lsa_header_print(lsa);
129 }
130
131 ospf6_install_lsa(lsa);
132 ospf6_flood(NULL, lsa);
133 }
134
135 void ospf6_lsa_originate_process(struct ospf6_lsa *lsa, struct ospf6 *process)
136 {
137 lsa->lsdb = process->lsdb;
138 ospf6_lsa_originate(process, lsa);
139 }
140
141 void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
142 {
143 lsa->lsdb = oa->lsdb;
144 ospf6_lsa_originate(oa->ospf6, lsa);
145 }
146
147 void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
148 struct ospf6_interface *oi)
149 {
150 lsa->lsdb = oi->lsdb;
151 ospf6_lsa_originate(oi->area->ospf6, lsa);
152 }
153
154 void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
155 uint32_t id)
156 {
157 struct prefix prefix_id;
158 struct route_node *node;
159
160 /* remove binding in external_id_table */
161 prefix_id.family = AF_INET;
162 prefix_id.prefixlen = 32;
163 prefix_id.u.prefix4.s_addr = id;
164 node = route_node_lookup(ospf6->external_id_table, &prefix_id);
165 assert(node);
166 node->info = NULL;
167 route_unlock_node(node); /* to free the lookup lock */
168 route_unlock_node(node); /* to free the original lock */
169
170 }
171
172 void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
173 {
174 uint32_t id = lsa->header->id;
175 struct ospf6_area *oa;
176 struct listnode *lnode;
177
178 ospf6_lsa_purge(lsa);
179
180 ospf6_remove_id_from_external_id_table(ospf6, id);
181
182 /* Delete the corresponding NSSA LSA */
183 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
184 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), id,
185 ospf6->router_id, oa->lsdb);
186 if (lsa) {
187 if (IS_OSPF6_DEBUG_NSSA)
188 zlog_debug("withdraw type 7 lsa, LS ID: %u",
189 htonl(id));
190
191 ospf6_lsa_purge(lsa);
192 }
193 }
194 }
195
196 void ospf6_lsa_purge(struct ospf6_lsa *lsa)
197 {
198 struct ospf6_lsa *self;
199 struct ospf6_lsdb *lsdb_self;
200
201 /* remove it from the LSDB for self-originated LSAs */
202 lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
203 self = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
204 lsa->header->adv_router, lsdb_self);
205 if (self) {
206 THREAD_OFF(self->expire);
207 THREAD_OFF(self->refresh);
208 ospf6_lsdb_remove(self, lsdb_self);
209 }
210
211 ospf6_lsa_premature_aging(lsa);
212 }
213
214 /* Puring Multi Link-State IDs LSAs:
215 * Same Advertising Router with Multiple Link-State IDs
216 * LSAs, purging require to traverse all Link-State IDs
217 */
218 void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa, struct ospf6_lsa *lsa)
219 {
220 int ls_id = 0;
221 struct ospf6_lsa *lsa_next;
222 uint16_t type;
223
224 type = lsa->header->type;
225
226 ospf6_lsa_purge(lsa);
227
228 lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
229 oa->ospf6->router_id, oa->lsdb);
230 while (lsa_next) {
231 ospf6_lsa_purge(lsa_next);
232 lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
233 oa->ospf6->router_id, oa->lsdb);
234 }
235 }
236
237 void ospf6_increment_retrans_count(struct ospf6_lsa *lsa)
238 {
239 /* The LSA must be the original one (see the description
240 in ospf6_decrement_retrans_count () below) */
241 lsa->retrans_count++;
242 }
243
244 void ospf6_decrement_retrans_count(struct ospf6_lsa *lsa)
245 {
246 struct ospf6_lsdb *lsdb;
247 struct ospf6_lsa *orig;
248
249 /* The LSA must be on the retrans-list of a neighbor. It means
250 the "lsa" is a copied one, and we have to decrement the
251 retransmission count of the original one (instead of this "lsa"'s).
252 In order to find the original LSA, first we have to find
253 appropriate LSDB that have the original LSA. */
254 lsdb = ospf6_get_scoped_lsdb(lsa);
255
256 /* Find the original LSA of which the retrans_count should be
257 * decremented */
258 orig = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
259 lsa->header->adv_router, lsdb);
260 if (orig) {
261 orig->retrans_count--;
262 assert(orig->retrans_count >= 0);
263 }
264 }
265
266 /* RFC2328 section 13.2 Installing LSAs in the database */
267 void ospf6_install_lsa(struct ospf6_lsa *lsa)
268 {
269 struct timeval now;
270 struct ospf6_lsa *old;
271 struct ospf6_area *area = NULL;
272
273 /* Remove the old instance from all neighbors' Link state
274 retransmission list (RFC2328 13.2 last paragraph) */
275 old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
276 lsa->header->adv_router, lsa->lsdb);
277 if (old) {
278 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
279 if (IS_OSPF6_DEBUG_NSSA)
280 zlog_debug("%s : old LSA %s", __func__,
281 lsa->name);
282 lsa->external_lsa_id = old->external_lsa_id;
283 }
284 THREAD_OFF(old->expire);
285 THREAD_OFF(old->refresh);
286 ospf6_flood_clear(old);
287 }
288
289 monotime(&now);
290 if (!OSPF6_LSA_IS_MAXAGE(lsa)) {
291 lsa->expire = NULL;
292 thread_add_timer(master, ospf6_lsa_expire, lsa,
293 OSPF_LSA_MAXAGE + lsa->birth.tv_sec
294 - now.tv_sec,
295 &lsa->expire);
296 } else
297 lsa->expire = NULL;
298
299 if (OSPF6_LSA_IS_SEQWRAP(lsa)
300 && !(CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)
301 && lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) {
302 if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
303 zlog_debug("lsa install wrapping: sequence 0x%x",
304 ntohl(lsa->header->seqnum));
305 SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
306 /* in lieu of premature_aging, since we do not want to recreate
307 * this lsa
308 * and/or mess with timers etc, we just want to wrap the
309 * sequence number
310 * and reflood the lsa before continuing.
311 * NOTE: Flood needs to be called right after this function
312 * call, by the
313 * caller
314 */
315 lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER);
316 lsa->header->age = htons(OSPF_LSA_MAXAGE);
317 ospf6_lsa_checksum(lsa->header);
318 }
319
320 if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
321 || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
322 zlog_debug("%s Install LSA: %s age %d seqnum %x in LSDB.",
323 __func__, lsa->name, ntohs(lsa->header->age),
324 ntohl(lsa->header->seqnum));
325
326 /* actually install */
327 lsa->installed = now;
328
329 /* Topo change handling */
330 if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))
331 && !CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)) {
332
333 /* check if it is new lsa ? or existing lsa got modified ?*/
334 if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) {
335 struct ospf6 *ospf6;
336
337 ospf6 = ospf6_get_by_lsdb(lsa);
338
339 assert(ospf6);
340
341 ospf6_helper_handle_topo_chg(ospf6, lsa);
342 }
343 }
344
345 ospf6_lsdb_add(lsa, lsa->lsdb);
346
347 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
348 area = OSPF6_AREA(lsa->lsdb->data);
349 ospf6_translated_nssa_refresh(area, lsa, NULL);
350 ospf6_schedule_abr_task(area->ospf6);
351 }
352
353 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
354 area = OSPF6_AREA(lsa->lsdb->data);
355 if (old == NULL) {
356 if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
357 || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
358 zlog_debug("%s: New router LSA %s", __func__,
359 lsa->name);
360 ospf6_abr_nssa_check_status(area->ospf6);
361 }
362 }
363 return;
364 }
365
366 /* RFC2740 section 3.5.2. Sending Link State Update packets */
367 /* RFC2328 section 13.3 Next step in the flooding procedure */
368 void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
369 struct ospf6_interface *oi)
370 {
371 struct listnode *node, *nnode;
372 struct ospf6_neighbor *on;
373 struct ospf6_lsa *req, *old;
374 int retrans_added = 0;
375 int is_debug = 0;
376
377 if (IS_OSPF6_DEBUG_FLOODING
378 || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) {
379 is_debug++;
380 zlog_debug("Flooding on %s: %s", oi->interface->name,
381 lsa->name);
382 }
383
384 /* (1) For each neighbor */
385 for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
386 if (is_debug)
387 zlog_debug("To neighbor %s", on->name);
388
389 /* (a) if neighbor state < Exchange, examin next */
390 if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
391 if (is_debug)
392 zlog_debug(
393 "Neighbor state less than ExChange, next neighbor");
394 continue;
395 }
396
397 /* (b) if neighbor not yet Full, check request-list */
398 if (on->state != OSPF6_NEIGHBOR_FULL) {
399 if (is_debug)
400 zlog_debug("Neighbor not yet Full");
401
402 req = ospf6_lsdb_lookup(
403 lsa->header->type, lsa->header->id,
404 lsa->header->adv_router, on->request_list);
405 if (req == NULL) {
406 if (is_debug)
407 zlog_debug(
408 "Not on request-list for this neighbor");
409 /* fall through */
410 } else {
411 /* If new LSA less recent, examin next neighbor
412 */
413 if (ospf6_lsa_compare(lsa, req) > 0) {
414 if (is_debug)
415 zlog_debug(
416 "Requesting is older, next neighbor");
417 continue;
418 }
419
420 /* If the same instance, delete from
421 request-list and
422 examin next neighbor */
423 if (ospf6_lsa_compare(lsa, req) == 0) {
424 if (is_debug)
425 zlog_debug(
426 "Requesting the same, remove it, next neighbor");
427 if (req == on->last_ls_req) {
428 /* sanity check refcount */
429 assert(req->lock >= 2);
430 req = ospf6_lsa_unlock(req);
431 on->last_ls_req = NULL;
432 }
433 if (req)
434 ospf6_lsdb_remove(
435 req, on->request_list);
436 ospf6_check_nbr_loading(on);
437 continue;
438 }
439
440 /* If the new LSA is more recent, delete from
441 * request-list */
442 if (ospf6_lsa_compare(lsa, req) < 0) {
443 if (is_debug)
444 zlog_debug(
445 "Received is newer, remove requesting");
446 if (req == on->last_ls_req) {
447 req = ospf6_lsa_unlock(req);
448 on->last_ls_req = NULL;
449 }
450 if (req)
451 ospf6_lsdb_remove(req,
452 on->request_list);
453 ospf6_check_nbr_loading(on);
454 /* fall through */
455 }
456 }
457 }
458
459 /* (c) If the new LSA was received from this neighbor,
460 examin next neighbor */
461 if (from == on) {
462 if (is_debug)
463 zlog_debug(
464 "Received is from the neighbor, next neighbor");
465 continue;
466 }
467
468 if ((oi->area->ospf6->inst_shutdown)
469 || CHECK_FLAG(lsa->flag, OSPF6_LSA_FLUSH)) {
470 if (is_debug)
471 zlog_debug(
472 "%s: Send LSA %s (age %d) update now",
473 __func__, lsa->name,
474 ntohs(lsa->header->age));
475 ospf6_lsupdate_send_neighbor_now(on, lsa);
476 continue;
477 } else {
478 /* (d) add retrans-list, schedule retransmission */
479 if (is_debug)
480 zlog_debug("Add retrans-list of neighbor %s ",
481 on->name);
482
483 /* Do not increment the retrans count if the lsa is
484 * already present in the retrans list.
485 */
486 old = ospf6_lsdb_lookup(
487 lsa->header->type, lsa->header->id,
488 lsa->header->adv_router, on->retrans_list);
489 if (!old) {
490 if (is_debug)
491 zlog_debug(
492 "Increment %s from retrans_list of %s",
493 lsa->name, on->name);
494 ospf6_increment_retrans_count(lsa);
495 ospf6_lsdb_add(ospf6_lsa_copy(lsa),
496 on->retrans_list);
497 thread_add_timer(
498 master, ospf6_lsupdate_send_neighbor,
499 on, on->ospf6_if->rxmt_interval,
500 &on->thread_send_lsupdate);
501 retrans_added++;
502 }
503 }
504 }
505
506 /* (2) examin next interface if not added to retrans-list */
507 if (retrans_added == 0) {
508 if (is_debug)
509 zlog_debug(
510 "No retransmission scheduled, next interface %s",
511 oi->interface->name);
512 return;
513 }
514
515 /* (3) If the new LSA was received on this interface,
516 and it was from DR or BDR, examin next interface */
517 if (from && from->ospf6_if == oi
518 && (from->router_id == oi->drouter
519 || from->router_id == oi->bdrouter)) {
520 if (is_debug)
521 zlog_debug(
522 "Received is from the I/F's DR or BDR, next interface");
523 return;
524 }
525
526 /* (4) If the new LSA was received on this interface,
527 and the interface state is BDR, examin next interface */
528 if (from && from->ospf6_if == oi) {
529 if (oi->state == OSPF6_INTERFACE_BDR) {
530 if (is_debug)
531 zlog_debug(
532 "Received is from the I/F, itself BDR, next interface");
533 return;
534 }
535 SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK);
536 }
537
538 /* (5) flood the LSA out the interface. */
539 if (is_debug)
540 zlog_debug("Schedule flooding for the interface");
541 if ((oi->type == OSPF_IFTYPE_BROADCAST)
542 || (oi->type == OSPF_IFTYPE_POINTOPOINT)) {
543 ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsupdate_list);
544 thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0,
545 &oi->thread_send_lsupdate);
546 } else {
547 /* reschedule retransmissions to all neighbors */
548 for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
549 THREAD_OFF(on->thread_send_lsupdate);
550 on->thread_send_lsupdate = NULL;
551 thread_add_event(master, ospf6_lsupdate_send_neighbor,
552 on, 0, &on->thread_send_lsupdate);
553 }
554 }
555 }
556
557 void ospf6_flood_area(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
558 struct ospf6_area *oa)
559 {
560 struct listnode *node, *nnode;
561 struct ospf6_interface *oi;
562
563 for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
564 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
565 && oi != OSPF6_INTERFACE(lsa->lsdb->data))
566 continue;
567
568 ospf6_flood_interface(from, lsa, oi);
569 }
570 }
571
572 static void ospf6_flood_process(struct ospf6_neighbor *from,
573 struct ospf6_lsa *lsa, struct ospf6 *process)
574 {
575 struct listnode *node, *nnode;
576 struct ospf6_area *oa;
577
578 for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) {
579
580 /* If unknown LSA and U-bit clear, treat as link local
581 * flooding scope
582 */
583 if (!OSPF6_LSA_IS_KNOWN(lsa->header->type)
584 && !(ntohs(lsa->header->type) & OSPF6_LSTYPE_UBIT_MASK)
585 && (oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)) {
586
587 if (IS_OSPF6_DEBUG_FLOODING)
588 zlog_debug("Unknown LSA, do not flood");
589 continue;
590 }
591
592 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA
593 && oa != OSPF6_AREA(lsa->lsdb->data))
594 continue;
595 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
596 && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)
597 continue;
598
599 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
600 && (IS_AREA_STUB(oa) || IS_AREA_NSSA(oa)))
601 continue;
602
603 /* Check for NSSA LSA */
604 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
605 && !IS_AREA_NSSA(oa) && !OSPF6_LSA_IS_MAXAGE(lsa))
606 continue;
607
608 ospf6_flood_area(from, lsa, oa);
609 }
610 }
611
612 void ospf6_flood(struct ospf6_neighbor *from, struct ospf6_lsa *lsa)
613 {
614 struct ospf6 *ospf6;
615
616 ospf6 = ospf6_get_by_lsdb(lsa);
617 if (ospf6 == NULL)
618 return;
619
620 ospf6_flood_process(from, lsa, ospf6);
621 }
622
623 static void ospf6_flood_clear_interface(struct ospf6_lsa *lsa,
624 struct ospf6_interface *oi)
625 {
626 struct listnode *node, *nnode;
627 struct ospf6_neighbor *on;
628 struct ospf6_lsa *rem;
629
630 for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
631 rem = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
632 lsa->header->adv_router,
633 on->retrans_list);
634 if (rem && !ospf6_lsa_compare(rem, lsa)) {
635 if (IS_OSPF6_DEBUG_FLOODING
636 || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
637 zlog_debug("Remove %s from retrans_list of %s",
638 rem->name, on->name);
639 ospf6_decrement_retrans_count(rem);
640 ospf6_lsdb_remove(rem, on->retrans_list);
641 }
642 }
643 }
644
645 void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
646 {
647 struct listnode *node, *nnode;
648 struct ospf6_interface *oi;
649
650 for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
651 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
652 && oi != OSPF6_INTERFACE(lsa->lsdb->data))
653 continue;
654
655 ospf6_flood_clear_interface(lsa, oi);
656 }
657 }
658
659 static void ospf6_flood_clear_process(struct ospf6_lsa *lsa,
660 struct ospf6 *process)
661 {
662 struct listnode *node, *nnode;
663 struct ospf6_area *oa;
664
665 for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) {
666 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA
667 && oa != OSPF6_AREA(lsa->lsdb->data))
668 continue;
669 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
670 && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)
671 continue;
672
673 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
674 && (IS_AREA_STUB(oa) || (IS_AREA_NSSA(oa))))
675 continue;
676 /* Check for NSSA LSA */
677 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
678 && !IS_AREA_NSSA(oa))
679 continue;
680
681 ospf6_flood_clear_area(lsa, oa);
682 }
683 }
684
685 void ospf6_flood_clear(struct ospf6_lsa *lsa)
686 {
687 struct ospf6 *ospf6;
688
689 ospf6 = ospf6_get_by_lsdb(lsa);
690 if (ospf6 == NULL)
691 return;
692 ospf6_flood_clear_process(lsa, ospf6);
693 }
694
695
696 /* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */
697 static void ospf6_acknowledge_lsa_bdrouter(struct ospf6_lsa *lsa,
698 int ismore_recent,
699 struct ospf6_neighbor *from)
700 {
701 struct ospf6_interface *oi;
702 int is_debug = 0;
703
704 if (IS_OSPF6_DEBUG_FLOODING
705 || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
706 is_debug++;
707
708 assert(from && from->ospf6_if);
709 oi = from->ospf6_if;
710
711 /* LSA is more recent than database copy, but was not flooded
712 back out receiving interface. Delayed acknowledgement sent
713 if advertisement received from Designated Router,
714 otherwide do nothing. */
715 if (ismore_recent < 0) {
716 if (oi->drouter == from->router_id) {
717 if (is_debug)
718 zlog_debug(
719 "Delayed acknowledgement (BDR & MoreRecent & from DR)");
720 /* Delayed acknowledgement */
721 ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
722 thread_add_timer(master, ospf6_lsack_send_interface, oi,
723 3, &oi->thread_send_lsack);
724 } else {
725 if (is_debug)
726 zlog_debug(
727 "No acknowledgement (BDR & MoreRecent & ! from DR)");
728 }
729 return;
730 }
731
732 /* LSA is a duplicate, and was treated as an implied acknowledgement.
733 Delayed acknowledgement sent if advertisement received from
734 Designated Router, otherwise do nothing */
735 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
736 && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
737 if (oi->drouter == from->router_id) {
738 if (is_debug)
739 zlog_debug(
740 "Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)");
741 /* Delayed acknowledgement */
742 ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
743 thread_add_timer(master, ospf6_lsack_send_interface, oi,
744 3, &oi->thread_send_lsack);
745 } else {
746 if (is_debug)
747 zlog_debug(
748 "No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)");
749 }
750 return;
751 }
752
753 /* LSA is a duplicate, and was not treated as an implied
754 acknowledgement.
755 Direct acknowledgement sent */
756 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
757 && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
758 if (is_debug)
759 zlog_debug("Direct acknowledgement (BDR & Duplicate)");
760 ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list);
761 thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
762 &from->thread_send_lsack);
763 return;
764 }
765
766 /* LSA's LS age is equal to Maxage, and there is no current instance
767 of the LSA in the link state database, and none of router's
768 neighbors are in states Exchange or Loading */
769 /* Direct acknowledgement sent, but this case is handled in
770 early of ospf6_receive_lsa () */
771 }
772
773 static void ospf6_acknowledge_lsa_allother(struct ospf6_lsa *lsa,
774 int ismore_recent,
775 struct ospf6_neighbor *from)
776 {
777 struct ospf6_interface *oi;
778 int is_debug = 0;
779
780 if (IS_OSPF6_DEBUG_FLOODING
781 || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
782 is_debug++;
783
784 assert(from && from->ospf6_if);
785 oi = from->ospf6_if;
786
787 /* LSA has been flood back out receiving interface.
788 No acknowledgement sent. */
789 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK)) {
790 if (is_debug)
791 zlog_debug("No acknowledgement (AllOther & FloodBack)");
792 return;
793 }
794
795 /* LSA is more recent than database copy, but was not flooded
796 back out receiving interface. Delayed acknowledgement sent. */
797 if (ismore_recent < 0) {
798 if (is_debug)
799 zlog_debug(
800 "Delayed acknowledgement (AllOther & MoreRecent)");
801 /* Delayed acknowledgement */
802 ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
803 thread_add_timer(master, ospf6_lsack_send_interface, oi, 3,
804 &oi->thread_send_lsack);
805 return;
806 }
807
808 /* LSA is a duplicate, and was treated as an implied acknowledgement.
809 No acknowledgement sent. */
810 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
811 && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
812 if (is_debug)
813 zlog_debug(
814 "No acknowledgement (AllOther & Duplicate & ImpliedAck)");
815 return;
816 }
817
818 /* LSA is a duplicate, and was not treated as an implied
819 acknowledgement.
820 Direct acknowledgement sent */
821 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
822 && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
823 if (is_debug)
824 zlog_debug(
825 "Direct acknowledgement (AllOther & Duplicate)");
826 ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list);
827 thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
828 &from->thread_send_lsack);
829 return;
830 }
831
832 /* LSA's LS age is equal to Maxage, and there is no current instance
833 of the LSA in the link state database, and none of router's
834 neighbors are in states Exchange or Loading */
835 /* Direct acknowledgement sent, but this case is handled in
836 early of ospf6_receive_lsa () */
837 }
838
839 static void ospf6_acknowledge_lsa(struct ospf6_lsa *lsa, int ismore_recent,
840 struct ospf6_neighbor *from)
841 {
842 struct ospf6_interface *oi;
843
844 assert(from && from->ospf6_if);
845 oi = from->ospf6_if;
846
847 if (oi->state == OSPF6_INTERFACE_BDR)
848 ospf6_acknowledge_lsa_bdrouter(lsa, ismore_recent, from);
849 else
850 ospf6_acknowledge_lsa_allother(lsa, ismore_recent, from);
851 }
852
853 /* RFC2328 section 13 (4):
854 if MaxAge LSA and if we have no instance, and no neighbor
855 is in states Exchange or Loading
856 returns 1 if match this case, else returns 0 */
857 static int ospf6_is_maxage_lsa_drop(struct ospf6_lsa *lsa,
858 struct ospf6_neighbor *from)
859 {
860 struct ospf6_neighbor *on;
861 struct ospf6_interface *oi;
862 struct ospf6_area *oa;
863 struct ospf6 *process = NULL;
864 struct listnode *i, *j, *k;
865 int count = 0;
866
867 if (!OSPF6_LSA_IS_MAXAGE(lsa))
868 return 0;
869
870 if (ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
871 lsa->header->adv_router, lsa->lsdb))
872 return 0;
873
874 process = from->ospf6_if->area->ospf6;
875
876 for (ALL_LIST_ELEMENTS_RO(process->area_list, i, oa))
877 for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
878 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on))
879 if (on->state == OSPF6_NEIGHBOR_EXCHANGE
880 || on->state == OSPF6_NEIGHBOR_LOADING)
881 count++;
882
883 if (count == 0)
884 return 1;
885 return 0;
886 }
887
888 /* RFC2328 section 13 The Flooding Procedure */
889 void ospf6_receive_lsa(struct ospf6_neighbor *from,
890 struct ospf6_lsa_header *lsa_header)
891 {
892 struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
893 int ismore_recent;
894 int is_debug = 0;
895 unsigned int time_delta_ms;
896
897 ismore_recent = 1;
898 assert(from);
899
900 /* if we receive a LSA with invalid seqnum drop it */
901 if (ntohl(lsa_header->seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) {
902 if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa_header->type)) {
903 zlog_debug(
904 "received lsa [%s Id:%pI4 Adv:%pI4] with invalid seqnum 0x%x, ignore",
905 ospf6_lstype_name(lsa_header->type),
906 &lsa_header->id, &lsa_header->adv_router,
907 ntohl(lsa_header->seqnum));
908 }
909 return;
910 }
911
912 /* make lsa structure for received lsa */
913 new = ospf6_lsa_create(lsa_header);
914
915 if (IS_OSPF6_DEBUG_FLOODING
916 || IS_OSPF6_DEBUG_FLOOD_TYPE(new->header->type)) {
917 is_debug++;
918 zlog_debug("LSA Receive from %s", from->name);
919 ospf6_lsa_header_print(new);
920 }
921
922 /* (1) LSA Checksum */
923 if (!ospf6_lsa_checksum_valid(new->header)) {
924 if (is_debug)
925 zlog_debug("Wrong LSA Checksum, discard");
926 ospf6_lsa_delete(new);
927 return;
928 }
929
930 /* (2) Examine the LSA's LS type.
931 RFC2470 3.5.1. Receiving Link State Update packets */
932 if (IS_AREA_STUB(from->ospf6_if->area)
933 && OSPF6_LSA_SCOPE(new->header->type) == OSPF6_SCOPE_AS) {
934 if (is_debug)
935 zlog_debug(
936 "AS-External-LSA (or AS-scope LSA) in stub area, discard");
937 ospf6_lsa_delete(new);
938 return;
939 }
940
941 /* (3) LSA which have reserved scope is discarded
942 RFC2470 3.5.1. Receiving Link State Update packets */
943 /* Flooding scope check. LSAs with unknown scope are discarded here.
944 Set appropriate LSDB for the LSA */
945 switch (OSPF6_LSA_SCOPE(new->header->type)) {
946 case OSPF6_SCOPE_LINKLOCAL:
947 new->lsdb = from->ospf6_if->lsdb;
948 break;
949 case OSPF6_SCOPE_AREA:
950 new->lsdb = from->ospf6_if->area->lsdb;
951 break;
952 case OSPF6_SCOPE_AS:
953 new->lsdb = from->ospf6_if->area->ospf6->lsdb;
954 break;
955 default:
956 if (is_debug)
957 zlog_debug("LSA has reserved scope, discard");
958 ospf6_lsa_delete(new);
959 return;
960 }
961
962 /* (4) if MaxAge LSA and if we have no instance, and no neighbor
963 is in states Exchange or Loading */
964 if (ospf6_is_maxage_lsa_drop(new, from)) {
965 /* log */
966 if (is_debug)
967 zlog_debug(
968 "Drop MaxAge LSA with direct acknowledgement.");
969
970 /* a) Acknowledge back to neighbor (Direct acknowledgement,
971 * 13.5) */
972 ospf6_lsdb_add(ospf6_lsa_copy(new), from->lsack_list);
973 thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
974 &from->thread_send_lsack);
975
976 /* b) Discard */
977 ospf6_lsa_delete(new);
978 return;
979 }
980
981 /* (5) */
982 /* lookup the same database copy in lsdb */
983 old = ospf6_lsdb_lookup(new->header->type, new->header->id,
984 new->header->adv_router, new->lsdb);
985 if (old) {
986 ismore_recent = ospf6_lsa_compare(new, old);
987 if (ntohl(new->header->seqnum) == ntohl(old->header->seqnum)) {
988 if (is_debug)
989 zlog_debug("Received is duplicated LSA");
990 SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
991 }
992 }
993
994 /* if no database copy or received is more recent */
995 if (old == NULL || ismore_recent < 0) {
996 bool self_originated;
997
998 /* in case we have no database copy */
999 ismore_recent = -1;
1000
1001 /* (a) MinLSArrival check */
1002 if (old) {
1003 struct timeval now, res;
1004 monotime(&now);
1005 timersub(&now, &old->installed, &res);
1006 time_delta_ms =
1007 (res.tv_sec * 1000) + (int)(res.tv_usec / 1000);
1008 if (time_delta_ms
1009 < from->ospf6_if->area->ospf6->lsa_minarrival) {
1010 if (is_debug)
1011 zlog_debug(
1012 "LSA can't be updated within MinLSArrival, %dms < %dms, discard",
1013 time_delta_ms,
1014 from->ospf6_if->area->ospf6
1015 ->lsa_minarrival);
1016 ospf6_lsa_delete(new);
1017 return; /* examin next lsa */
1018 }
1019 }
1020
1021 monotime(&new->received);
1022
1023 if (is_debug)
1024 zlog_debug(
1025 "Install, Flood, Possibly acknowledge the received LSA");
1026
1027 /* Remove older copies of this LSA from retx lists */
1028 if (old)
1029 ospf6_flood_clear(old);
1030
1031 /* (b) immediately flood and (c) remove from all retrans-list */
1032 /* Prevent self-originated LSA to be flooded. this is to make
1033 reoriginated instance of the LSA not to be rejected by other
1034 routers
1035 due to MinLSArrival. */
1036 self_originated = (new->header->adv_router
1037 == from->ospf6_if->area->ospf6->router_id);
1038 if (!self_originated)
1039 ospf6_flood(from, new);
1040
1041 /* Received non-self-originated Grace LSA. */
1042 if (IS_GRACE_LSA(new) && !self_originated) {
1043 struct ospf6 *ospf6;
1044
1045 ospf6 = ospf6_get_by_lsdb(new);
1046
1047 assert(ospf6);
1048
1049 if (OSPF6_LSA_IS_MAXAGE(new)) {
1050
1051 if (IS_DEBUG_OSPF6_GR)
1052 zlog_debug(
1053 "%s, Received a maxage GraceLSA from router %pI4",
1054 __func__,
1055 &new->header->adv_router);
1056 if (old) {
1057 ospf6_process_maxage_grace_lsa(
1058 ospf6, new, from);
1059 } else {
1060 if (IS_DEBUG_OSPF6_GR)
1061 zlog_debug(
1062 "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA",
1063 __func__);
1064 return;
1065 }
1066 } else {
1067
1068 if (IS_DEBUG_OSPF6_GR)
1069 zlog_debug(
1070 "%s, Received a GraceLSA from router %pI4",
1071 __func__,
1072 &new->header->adv_router);
1073
1074 if (ospf6_process_grace_lsa(ospf6, new, from)
1075 == OSPF6_GR_NOT_HELPER) {
1076 if (IS_DEBUG_OSPF6_GR)
1077 zlog_debug(
1078 "%s, Not moving to HELPER role, So dicarding GraceLSA",
1079 __func__);
1080 return;
1081 }
1082 }
1083 }
1084
1085 /* (d), installing lsdb, which may cause routing
1086 table calculation (replacing database copy) */
1087 ospf6_install_lsa(new);
1088
1089 if (OSPF6_LSA_IS_MAXAGE(new))
1090 ospf6_maxage_remove(from->ospf6_if->area->ospf6);
1091
1092 /* (e) possibly acknowledge */
1093 ospf6_acknowledge_lsa(new, ismore_recent, from);
1094
1095 /* (f) Self Originated LSA, section 13.4 */
1096 if (self_originated) {
1097 if (from->ospf6_if->area->ospf6->gr_info
1098 .restart_in_progress) {
1099 if (IS_DEBUG_OSPF6_GR)
1100 zlog_debug(
1101 "Graceful Restart in progress -- not flushing self-originated LSA: %s",
1102 new->name);
1103 return;
1104 }
1105
1106 /* Self-originated LSA (newer than ours) is received
1107 from
1108 another router. We have to make a new instance of the
1109 LSA
1110 or have to flush this LSA. */
1111 if (is_debug) {
1112 zlog_debug(
1113 "Newer instance of the self-originated LSA");
1114 zlog_debug("Schedule reorigination");
1115 }
1116 new->refresh = NULL;
1117 thread_add_event(master, ospf6_lsa_refresh, new, 0,
1118 &new->refresh);
1119 }
1120
1121 struct ospf6 *ospf6 = from->ospf6_if->area->ospf6;
1122 struct ospf6_area *area = from->ospf6_if->area;
1123 if (ospf6->gr_info.restart_in_progress)
1124 ospf6_gr_check_lsdb_consistency(ospf6, area);
1125
1126 return;
1127 }
1128
1129 /* (6) if there is instance on sending neighbor's request list */
1130 if (ospf6_lsdb_lookup(new->header->type, new->header->id,
1131 new->header->adv_router, from->request_list)) {
1132 /* if no database copy, should go above state (5) */
1133 assert(old);
1134
1135 zlog_warn(
1136 "Received is not newer, on the neighbor %s request-list",
1137 from->name);
1138 zlog_warn(
1139 "BadLSReq, discard the received LSA lsa %s send badLSReq",
1140 new->name);
1141
1142 /* BadLSReq */
1143 thread_add_event(master, bad_lsreq, from, 0, NULL);
1144
1145 ospf6_lsa_delete(new);
1146 return;
1147 }
1148
1149 /* (7) if neither one is more recent */
1150 if (ismore_recent == 0) {
1151 if (is_debug)
1152 zlog_debug(
1153 "The same instance as database copy (neither recent)");
1154
1155 /* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack
1156 */
1157 rem = ospf6_lsdb_lookup(new->header->type, new->header->id,
1158 new->header->adv_router,
1159 from->retrans_list);
1160 if (rem) {
1161 if (is_debug) {
1162 zlog_debug(
1163 "It is on the neighbor's retrans-list.");
1164 zlog_debug(
1165 "Treat as an Implied acknowledgement");
1166 }
1167 SET_FLAG(new->flag, OSPF6_LSA_IMPLIEDACK);
1168 ospf6_decrement_retrans_count(rem);
1169 ospf6_lsdb_remove(rem, from->retrans_list);
1170 }
1171
1172 if (is_debug)
1173 zlog_debug("Possibly acknowledge and then discard");
1174
1175 /* (b) possibly acknowledge */
1176 ospf6_acknowledge_lsa(new, ismore_recent, from);
1177
1178 ospf6_lsa_delete(new);
1179 return;
1180 }
1181
1182 /* (8) previous database copy is more recent */
1183 {
1184 assert(old);
1185
1186 /* If database copy is in 'Seqnumber Wrapping',
1187 simply discard the received LSA */
1188 if (OSPF6_LSA_IS_MAXAGE(old)
1189 && old->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) {
1190 if (is_debug) {
1191 zlog_debug("The LSA is in Seqnumber Wrapping");
1192 zlog_debug("MaxAge & MaxSeqNum, discard");
1193 }
1194 ospf6_lsa_delete(new);
1195 return;
1196 }
1197
1198 /* Otherwise, Send database copy of this LSA to this neighbor */
1199 {
1200 if (is_debug) {
1201 zlog_debug("Database copy is more recent.");
1202 zlog_debug(
1203 "Send back directly and then discard");
1204 }
1205
1206 /* Neighbor router sent recent age for LSA,
1207 * Router could be restarted while current copy is
1208 * MAXAGEd and not removed.*/
1209 if (OSPF6_LSA_IS_MAXAGE(old)
1210 && !OSPF6_LSA_IS_MAXAGE(new)) {
1211 if (new->header->adv_router
1212 != from->ospf6_if->area->ospf6->router_id) {
1213 if (is_debug)
1214 zlog_debug(
1215 "%s: Current copy of LSA %s is MAXAGE, but new has recent age, flooding/installing.",
1216 __PRETTY_FUNCTION__, old->name);
1217 ospf6_lsa_purge(old);
1218 ospf6_flood(from, new);
1219 ospf6_install_lsa(new);
1220 return;
1221 }
1222 /* For self-originated LSA, only trust
1223 * ourselves. Fall through and send
1224 * LS Update with our current copy.
1225 */
1226 if (is_debug)
1227 zlog_debug(
1228 "%s: Current copy of self-originated LSA %s is MAXAGE, but new has recent age, re-sending current one.",
1229 __PRETTY_FUNCTION__, old->name);
1230 }
1231
1232 /* XXX, MinLSArrival check !? RFC 2328 13 (8) */
1233
1234 ospf6_lsdb_add(ospf6_lsa_copy(old),
1235 from->lsupdate_list);
1236 thread_add_event(master, ospf6_lsupdate_send_neighbor,
1237 from, 0, &from->thread_send_lsupdate);
1238
1239 ospf6_lsa_delete(new);
1240 return;
1241 }
1242 return;
1243 }
1244 }
1245
1246 DEFUN (debug_ospf6_flooding,
1247 debug_ospf6_flooding_cmd,
1248 "debug ospf6 flooding",
1249 DEBUG_STR
1250 OSPF6_STR
1251 "Debug OSPFv3 flooding function\n"
1252 )
1253 {
1254 OSPF6_DEBUG_FLOODING_ON();
1255 return CMD_SUCCESS;
1256 }
1257
1258 DEFUN (no_debug_ospf6_flooding,
1259 no_debug_ospf6_flooding_cmd,
1260 "no debug ospf6 flooding",
1261 NO_STR
1262 DEBUG_STR
1263 OSPF6_STR
1264 "Debug OSPFv3 flooding function\n"
1265 )
1266 {
1267 OSPF6_DEBUG_FLOODING_OFF();
1268 return CMD_SUCCESS;
1269 }
1270
1271 int config_write_ospf6_debug_flood(struct vty *vty)
1272 {
1273 if (IS_OSPF6_DEBUG_FLOODING)
1274 vty_out(vty, "debug ospf6 flooding\n");
1275 return 0;
1276 }
1277
1278 void install_element_ospf6_debug_flood(void)
1279 {
1280 install_element(ENABLE_NODE, &debug_ospf6_flooding_cmd);
1281 install_element(ENABLE_NODE, &no_debug_ospf6_flooding_cmd);
1282 install_element(CONFIG_NODE, &debug_ospf6_flooding_cmd);
1283 install_element(CONFIG_NODE, &no_debug_ospf6_flooding_cmd);
1284 }