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