]>
Commit | Line | Data |
---|---|---|
48454375 | 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 | |
ac4d0be5 | 17 | * along with GNU Zebra; see the file COPYING. If not, write to the |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | * Boston, MA 02111-1307, USA. | |
48454375 | 20 | */ |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | #include "log.h" | |
25 | #include "thread.h" | |
26 | #include "linklist.h" | |
27 | #include "vty.h" | |
1e05838a | 28 | #include "command.h" |
48454375 | 29 | |
30 | #include "ospf6d.h" | |
31 | #include "ospf6_proto.h" | |
32 | #include "ospf6_lsa.h" | |
33 | #include "ospf6_lsdb.h" | |
34 | #include "ospf6_message.h" | |
35 | #include "ospf6_route.h" | |
36 | #include "ospf6_spf.h" | |
37 | ||
38 | #include "ospf6_top.h" | |
39 | #include "ospf6_area.h" | |
40 | #include "ospf6_interface.h" | |
41 | #include "ospf6_neighbor.h" | |
42 | ||
6452df09 | 43 | #include "ospf6_flood.h" |
48454375 | 44 | |
1e05838a | 45 | unsigned char conf_debug_ospf6_flooding; |
46 | ||
ac4d0be5 | 47 | struct ospf6_lsdb *ospf6_get_scoped_lsdb(struct ospf6_lsa *lsa) |
48454375 | 48 | { |
ac4d0be5 | 49 | struct ospf6_lsdb *lsdb = NULL; |
50 | switch (OSPF6_LSA_SCOPE(lsa->header->type)) { | |
51 | case OSPF6_SCOPE_LINKLOCAL: | |
52 | lsdb = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb; | |
53 | break; | |
54 | case OSPF6_SCOPE_AREA: | |
55 | lsdb = OSPF6_AREA(lsa->lsdb->data)->lsdb; | |
56 | break; | |
57 | case OSPF6_SCOPE_AS: | |
58 | lsdb = OSPF6_PROCESS(lsa->lsdb->data)->lsdb; | |
59 | break; | |
60 | default: | |
61 | assert(0); | |
62 | break; | |
63 | } | |
64 | return lsdb; | |
48454375 | 65 | } |
66 | ||
ac4d0be5 | 67 | struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa) |
48454375 | 68 | { |
ac4d0be5 | 69 | struct ospf6_lsdb *lsdb_self = NULL; |
70 | switch (OSPF6_LSA_SCOPE(lsa->header->type)) { | |
71 | case OSPF6_SCOPE_LINKLOCAL: | |
72 | lsdb_self = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb_self; | |
73 | break; | |
74 | case OSPF6_SCOPE_AREA: | |
75 | lsdb_self = OSPF6_AREA(lsa->lsdb->data)->lsdb_self; | |
76 | break; | |
77 | case OSPF6_SCOPE_AS: | |
78 | lsdb_self = OSPF6_PROCESS(lsa->lsdb->data)->lsdb_self; | |
79 | break; | |
80 | default: | |
81 | assert(0); | |
82 | break; | |
83 | } | |
84 | return lsdb_self; | |
6452df09 | 85 | } |
86 | ||
ac4d0be5 | 87 | void ospf6_lsa_originate(struct ospf6_lsa *lsa) |
6452df09 | 88 | { |
ac4d0be5 | 89 | struct ospf6_lsa *old; |
90 | struct ospf6_lsdb *lsdb_self; | |
91 | ||
92 | /* find previous LSA */ | |
93 | old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
94 | lsa->header->adv_router, lsa->lsdb); | |
95 | ||
96 | /* if the new LSA does not differ from previous, | |
97 | suppress this update of the LSA */ | |
98 | if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)) { | |
99 | if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type)) | |
100 | zlog_debug("Suppress updating LSA: %s", lsa->name); | |
101 | ospf6_lsa_delete(lsa); | |
102 | return; | |
103 | } | |
104 | ||
105 | /* store it in the LSDB for self-originated LSAs */ | |
106 | lsdb_self = ospf6_get_scoped_lsdb_self(lsa); | |
107 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self); | |
108 | ||
109 | lsa->refresh = thread_add_timer(master, ospf6_lsa_refresh, lsa, | |
110 | OSPF_LS_REFRESH_TIME); | |
111 | ||
112 | if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type) | |
113 | || IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type)) { | |
114 | zlog_debug("LSA Originate:"); | |
115 | ospf6_lsa_header_print(lsa); | |
116 | } | |
117 | ||
118 | ospf6_install_lsa(lsa); | |
119 | ospf6_flood(NULL, lsa); | |
6452df09 | 120 | } |
3b4cd3a9 | 121 | |
ac4d0be5 | 122 | void ospf6_lsa_originate_process(struct ospf6_lsa *lsa, struct ospf6 *process) |
6452df09 | 123 | { |
ac4d0be5 | 124 | lsa->lsdb = process->lsdb; |
125 | ospf6_lsa_originate(lsa); | |
3b4cd3a9 | 126 | } |
127 | ||
ac4d0be5 | 128 | void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa) |
48454375 | 129 | { |
ac4d0be5 | 130 | lsa->lsdb = oa->lsdb; |
131 | ospf6_lsa_originate(lsa); | |
6452df09 | 132 | } |
133 | ||
ac4d0be5 | 134 | void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa, |
135 | struct ospf6_interface *oi) | |
6452df09 | 136 | { |
ac4d0be5 | 137 | lsa->lsdb = oi->lsdb; |
138 | ospf6_lsa_originate(lsa); | |
6452df09 | 139 | } |
48454375 | 140 | |
ac4d0be5 | 141 | void ospf6_lsa_purge(struct ospf6_lsa *lsa) |
6452df09 | 142 | { |
ac4d0be5 | 143 | struct ospf6_lsa *self; |
144 | struct ospf6_lsdb *lsdb_self; | |
145 | ||
146 | /* remove it from the LSDB for self-originated LSAs */ | |
147 | lsdb_self = ospf6_get_scoped_lsdb_self(lsa); | |
148 | self = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
149 | lsa->header->adv_router, lsdb_self); | |
150 | if (self) { | |
151 | THREAD_OFF(self->expire); | |
152 | THREAD_OFF(self->refresh); | |
153 | ospf6_lsdb_remove(self, lsdb_self); | |
154 | } | |
155 | ||
156 | ospf6_lsa_premature_aging(lsa); | |
6452df09 | 157 | } |
48454375 | 158 | |
48454375 | 159 | |
ac4d0be5 | 160 | void ospf6_increment_retrans_count(struct ospf6_lsa *lsa) |
6452df09 | 161 | { |
ac4d0be5 | 162 | /* The LSA must be the original one (see the description |
163 | in ospf6_decrement_retrans_count () below) */ | |
164 | lsa->retrans_count++; | |
6452df09 | 165 | } |
48454375 | 166 | |
ac4d0be5 | 167 | void ospf6_decrement_retrans_count(struct ospf6_lsa *lsa) |
6452df09 | 168 | { |
ac4d0be5 | 169 | struct ospf6_lsdb *lsdb; |
170 | struct ospf6_lsa *orig; | |
171 | ||
172 | /* The LSA must be on the retrans-list of a neighbor. It means | |
173 | the "lsa" is a copied one, and we have to decrement the | |
174 | retransmission count of the original one (instead of this "lsa"'s). | |
175 | In order to find the original LSA, first we have to find | |
176 | appropriate LSDB that have the original LSA. */ | |
177 | lsdb = ospf6_get_scoped_lsdb(lsa); | |
178 | ||
179 | /* Find the original LSA of which the retrans_count should be | |
180 | * decremented */ | |
181 | orig = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
182 | lsa->header->adv_router, lsdb); | |
183 | if (orig) { | |
184 | orig->retrans_count--; | |
185 | assert(orig->retrans_count >= 0); | |
186 | } | |
48454375 | 187 | } |
188 | ||
189 | /* RFC2328 section 13.2 Installing LSAs in the database */ | |
ac4d0be5 | 190 | void ospf6_install_lsa(struct ospf6_lsa *lsa) |
48454375 | 191 | { |
ac4d0be5 | 192 | struct timeval now; |
193 | struct ospf6_lsa *old; | |
194 | ||
195 | if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type) | |
196 | || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) | |
197 | zlog_debug("Install LSA: %s", lsa->name); | |
198 | ||
199 | /* Remove the old instance from all neighbors' Link state | |
200 | retransmission list (RFC2328 13.2 last paragraph) */ | |
201 | old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
202 | lsa->header->adv_router, lsa->lsdb); | |
203 | if (old) { | |
204 | THREAD_OFF(old->expire); | |
205 | THREAD_OFF(old->refresh); | |
206 | ospf6_flood_clear(old); | |
207 | } | |
208 | ||
209 | monotime(&now); | |
210 | if (!OSPF6_LSA_IS_MAXAGE(lsa)) | |
211 | lsa->expire = thread_add_timer( | |
212 | master, ospf6_lsa_expire, lsa, | |
213 | OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec); | |
214 | else | |
215 | lsa->expire = NULL; | |
216 | ||
217 | if (OSPF6_LSA_IS_SEQWRAP(lsa) | |
218 | && !(CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED) | |
219 | && lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) { | |
220 | if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) | |
221 | zlog_debug("lsa install wrapping: sequence 0x%x", | |
222 | ntohl(lsa->header->seqnum)); | |
223 | SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); | |
224 | /* in lieu of premature_aging, since we do not want to recreate | |
225 | * this lsa | |
226 | * and/or mess with timers etc, we just want to wrap the | |
227 | * sequence number | |
228 | * and reflood the lsa before continuing. | |
229 | * NOTE: Flood needs to be called right after this function | |
230 | * call, by the | |
231 | * caller | |
232 | */ | |
233 | lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER); | |
234 | lsa->header->age = htons(OSPF_LSA_MAXAGE); | |
235 | ospf6_lsa_checksum(lsa->header); | |
236 | } | |
237 | ||
238 | /* actually install */ | |
239 | lsa->installed = now; | |
240 | ospf6_lsdb_add(lsa, lsa->lsdb); | |
241 | ||
242 | return; | |
48454375 | 243 | } |
244 | ||
6452df09 | 245 | /* RFC2740 section 3.5.2. Sending Link State Update packets */ |
48454375 | 246 | /* RFC2328 section 13.3 Next step in the flooding procedure */ |
ac4d0be5 | 247 | static void ospf6_flood_interface(struct ospf6_neighbor *from, |
248 | struct ospf6_lsa *lsa, | |
249 | struct ospf6_interface *oi) | |
48454375 | 250 | { |
ac4d0be5 | 251 | struct listnode *node, *nnode; |
252 | struct ospf6_neighbor *on; | |
253 | struct ospf6_lsa *req; | |
254 | int retrans_added = 0; | |
255 | int is_debug = 0; | |
256 | ||
257 | if (IS_OSPF6_DEBUG_FLOODING | |
258 | || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) { | |
259 | is_debug++; | |
260 | zlog_debug("Flooding on %s: %s", oi->interface->name, | |
261 | lsa->name); | |
262 | } | |
263 | ||
264 | /* (1) For each neighbor */ | |
265 | for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) { | |
266 | if (is_debug) | |
267 | zlog_debug("To neighbor %s", on->name); | |
268 | ||
269 | /* (a) if neighbor state < Exchange, examin next */ | |
270 | if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { | |
271 | if (is_debug) | |
272 | zlog_debug( | |
273 | "Neighbor state less than ExChange, next neighbor"); | |
274 | continue; | |
275 | } | |
276 | ||
277 | /* (b) if neighbor not yet Full, check request-list */ | |
278 | if (on->state != OSPF6_NEIGHBOR_FULL) { | |
279 | if (is_debug) | |
280 | zlog_debug("Neighbor not yet Full"); | |
281 | ||
282 | req = ospf6_lsdb_lookup( | |
283 | lsa->header->type, lsa->header->id, | |
284 | lsa->header->adv_router, on->request_list); | |
285 | if (req == NULL) { | |
286 | if (is_debug) | |
287 | zlog_debug( | |
288 | "Not on request-list for this neighbor"); | |
289 | /* fall through */ | |
290 | } else { | |
291 | /* If new LSA less recent, examin next neighbor | |
292 | */ | |
293 | if (ospf6_lsa_compare(lsa, req) > 0) { | |
294 | if (is_debug) | |
295 | zlog_debug( | |
296 | "Requesting is older, next neighbor"); | |
297 | continue; | |
298 | } | |
299 | ||
300 | /* If the same instance, delete from | |
301 | request-list and | |
302 | examin next neighbor */ | |
303 | if (ospf6_lsa_compare(lsa, req) == 0) { | |
304 | if (is_debug) | |
305 | zlog_debug( | |
306 | "Requesting the same, remove it, next neighbor"); | |
307 | if (req == on->last_ls_req) { | |
308 | ospf6_lsa_unlock(req); | |
309 | on->last_ls_req = NULL; | |
310 | } | |
311 | ospf6_lsdb_remove(req, | |
312 | on->request_list); | |
313 | ospf6_check_nbr_loading(on); | |
314 | continue; | |
315 | } | |
316 | ||
317 | /* If the new LSA is more recent, delete from | |
318 | * request-list */ | |
319 | if (ospf6_lsa_compare(lsa, req) < 0) { | |
320 | if (is_debug) | |
321 | zlog_debug( | |
322 | "Received is newer, remove requesting"); | |
323 | if (req == on->last_ls_req) { | |
324 | ospf6_lsa_unlock(req); | |
325 | on->last_ls_req = NULL; | |
326 | } | |
327 | ospf6_lsdb_remove(req, | |
328 | on->request_list); | |
329 | ospf6_check_nbr_loading(on); | |
330 | /* fall through */ | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
335 | /* (c) If the new LSA was received from this neighbor, | |
336 | examin next neighbor */ | |
337 | if (from == on) { | |
338 | if (is_debug) | |
339 | zlog_debug( | |
340 | "Received is from the neighbor, next neighbor"); | |
341 | continue; | |
342 | } | |
343 | ||
344 | /* (d) add retrans-list, schedule retransmission */ | |
345 | if (is_debug) | |
346 | zlog_debug("Add retrans-list of this neighbor"); | |
347 | ospf6_increment_retrans_count(lsa); | |
348 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); | |
349 | if (on->thread_send_lsupdate == NULL) | |
350 | on->thread_send_lsupdate = thread_add_timer( | |
351 | master, ospf6_lsupdate_send_neighbor, on, | |
352 | on->ospf6_if->rxmt_interval); | |
353 | retrans_added++; | |
354 | } | |
355 | ||
356 | /* (2) examin next interface if not added to retrans-list */ | |
357 | if (retrans_added == 0) { | |
358 | if (is_debug) | |
359 | zlog_debug( | |
360 | "No retransmission scheduled, next interface"); | |
361 | return; | |
362 | } | |
363 | ||
364 | /* (3) If the new LSA was received on this interface, | |
365 | and it was from DR or BDR, examin next interface */ | |
366 | if (from && from->ospf6_if == oi | |
367 | && (from->router_id == oi->drouter | |
368 | || from->router_id == oi->bdrouter)) { | |
369 | if (is_debug) | |
370 | zlog_debug( | |
371 | "Received is from the I/F's DR or BDR, next interface"); | |
372 | return; | |
373 | } | |
374 | ||
375 | /* (4) If the new LSA was received on this interface, | |
376 | and the interface state is BDR, examin next interface */ | |
377 | if (from && from->ospf6_if == oi) { | |
378 | if (oi->state == OSPF6_INTERFACE_BDR) { | |
379 | if (is_debug) | |
380 | zlog_debug( | |
381 | "Received is from the I/F, itself BDR, next interface"); | |
382 | return; | |
383 | } | |
384 | SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK); | |
385 | } | |
386 | ||
387 | /* (5) flood the LSA out the interface. */ | |
388 | if (is_debug) | |
389 | zlog_debug("Schedule flooding for the interface"); | |
390 | if ((oi->type == OSPF_IFTYPE_BROADCAST) | |
391 | || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { | |
392 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsupdate_list); | |
393 | if (oi->thread_send_lsupdate == NULL) | |
394 | oi->thread_send_lsupdate = thread_add_event( | |
395 | master, ospf6_lsupdate_send_interface, oi, 0); | |
396 | } else { | |
397 | /* reschedule retransmissions to all neighbors */ | |
398 | for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) { | |
399 | THREAD_OFF(on->thread_send_lsupdate); | |
400 | on->thread_send_lsupdate = thread_add_event( | |
401 | master, ospf6_lsupdate_send_neighbor, on, 0); | |
402 | } | |
7cf99722 | 403 | } |
6452df09 | 404 | } |
405 | ||
ac4d0be5 | 406 | void ospf6_flood_area(struct ospf6_neighbor *from, struct ospf6_lsa *lsa, |
407 | struct ospf6_area *oa) | |
6452df09 | 408 | { |
ac4d0be5 | 409 | struct listnode *node, *nnode; |
410 | struct ospf6_interface *oi; | |
6452df09 | 411 | |
ac4d0be5 | 412 | for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) { |
413 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL | |
414 | && oi != OSPF6_INTERFACE(lsa->lsdb->data)) | |
415 | continue; | |
48454375 | 416 | |
6452df09 | 417 | #if 0 |
418 | if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && | |
419 | ospf6_is_interface_virtual_link (oi)) | |
48454375 | 420 | continue; |
ac4d0be5 | 421 | #endif /*0*/ |
6452df09 | 422 | |
ac4d0be5 | 423 | ospf6_flood_interface(from, lsa, oi); |
424 | } | |
6452df09 | 425 | } |
426 | ||
ac4d0be5 | 427 | static void ospf6_flood_process(struct ospf6_neighbor *from, |
428 | struct ospf6_lsa *lsa, struct ospf6 *process) | |
6452df09 | 429 | { |
ac4d0be5 | 430 | struct listnode *node, *nnode; |
431 | struct ospf6_area *oa; | |
432 | ||
433 | for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) { | |
434 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA | |
435 | && oa != OSPF6_AREA(lsa->lsdb->data)) | |
436 | continue; | |
437 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL | |
438 | && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area) | |
439 | continue; | |
440 | ||
441 | if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL | |
442 | && IS_AREA_STUB(oa)) | |
443 | continue; | |
444 | ||
445 | ospf6_flood_area(from, lsa, oa); | |
446 | } | |
6452df09 | 447 | } |
448 | ||
ac4d0be5 | 449 | void ospf6_flood(struct ospf6_neighbor *from, struct ospf6_lsa *lsa) |
6452df09 | 450 | { |
ac4d0be5 | 451 | ospf6_flood_process(from, lsa, ospf6); |
6452df09 | 452 | } |
453 | ||
ac4d0be5 | 454 | static void ospf6_flood_clear_interface(struct ospf6_lsa *lsa, |
455 | struct ospf6_interface *oi) | |
6452df09 | 456 | { |
ac4d0be5 | 457 | struct listnode *node, *nnode; |
458 | struct ospf6_neighbor *on; | |
459 | struct ospf6_lsa *rem; | |
460 | ||
461 | for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) { | |
462 | rem = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
463 | lsa->header->adv_router, | |
464 | on->retrans_list); | |
465 | if (rem && !ospf6_lsa_compare(rem, lsa)) { | |
466 | if (IS_OSPF6_DEBUG_FLOODING | |
467 | || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) | |
468 | zlog_debug("Remove %s from retrans_list of %s", | |
469 | rem->name, on->name); | |
470 | ospf6_decrement_retrans_count(rem); | |
471 | ospf6_lsdb_remove(rem, on->retrans_list); | |
472 | } | |
473 | } | |
6452df09 | 474 | } |
475 | ||
ac4d0be5 | 476 | static void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa) |
6452df09 | 477 | { |
ac4d0be5 | 478 | struct listnode *node, *nnode; |
479 | struct ospf6_interface *oi; | |
6452df09 | 480 | |
ac4d0be5 | 481 | for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) { |
482 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL | |
483 | && oi != OSPF6_INTERFACE(lsa->lsdb->data)) | |
484 | continue; | |
6452df09 | 485 | |
486 | #if 0 | |
487 | if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && | |
488 | ospf6_is_interface_virtual_link (oi)) | |
489 | continue; | |
ac4d0be5 | 490 | #endif /*0*/ |
6452df09 | 491 | |
ac4d0be5 | 492 | ospf6_flood_clear_interface(lsa, oi); |
493 | } | |
6452df09 | 494 | } |
495 | ||
ac4d0be5 | 496 | static void ospf6_flood_clear_process(struct ospf6_lsa *lsa, |
497 | struct ospf6 *process) | |
6452df09 | 498 | { |
ac4d0be5 | 499 | struct listnode *node, *nnode; |
500 | struct ospf6_area *oa; | |
501 | ||
502 | for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) { | |
503 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA | |
504 | && oa != OSPF6_AREA(lsa->lsdb->data)) | |
505 | continue; | |
506 | if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL | |
507 | && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area) | |
508 | continue; | |
509 | ||
510 | if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL | |
511 | && IS_AREA_STUB(oa)) | |
512 | continue; | |
513 | ||
514 | ospf6_flood_clear_area(lsa, oa); | |
515 | } | |
6452df09 | 516 | } |
517 | ||
ac4d0be5 | 518 | void ospf6_flood_clear(struct ospf6_lsa *lsa) |
6452df09 | 519 | { |
ac4d0be5 | 520 | ospf6_flood_clear_process(lsa, ospf6); |
48454375 | 521 | } |
522 | ||
6452df09 | 523 | |
48454375 | 524 | /* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */ |
ac4d0be5 | 525 | static void ospf6_acknowledge_lsa_bdrouter(struct ospf6_lsa *lsa, |
526 | int ismore_recent, | |
527 | struct ospf6_neighbor *from) | |
48454375 | 528 | { |
ac4d0be5 | 529 | struct ospf6_interface *oi; |
530 | int is_debug = 0; | |
531 | ||
532 | if (IS_OSPF6_DEBUG_FLOODING | |
533 | || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) | |
534 | is_debug++; | |
535 | ||
536 | assert(from && from->ospf6_if); | |
537 | oi = from->ospf6_if; | |
538 | ||
539 | /* LSA is more recent than database copy, but was not flooded | |
540 | back out receiving interface. Delayed acknowledgement sent | |
541 | if advertisement received from Designated Router, | |
542 | otherwide do nothing. */ | |
543 | if (ismore_recent < 0) { | |
544 | if (oi->drouter == from->router_id) { | |
545 | if (is_debug) | |
546 | zlog_debug( | |
547 | "Delayed acknowledgement (BDR & MoreRecent & from DR)"); | |
548 | /* Delayed acknowledgement */ | |
549 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list); | |
550 | if (oi->thread_send_lsack == NULL) | |
551 | oi->thread_send_lsack = thread_add_timer( | |
552 | master, ospf6_lsack_send_interface, oi, | |
553 | 3); | |
554 | } else { | |
555 | if (is_debug) | |
556 | zlog_debug( | |
557 | "No acknowledgement (BDR & MoreRecent & ! from DR)"); | |
558 | } | |
559 | return; | |
560 | } | |
561 | ||
562 | /* LSA is a duplicate, and was treated as an implied acknowledgement. | |
563 | Delayed acknowledgement sent if advertisement received from | |
564 | Designated Router, otherwise do nothing */ | |
565 | if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE) | |
566 | && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) { | |
567 | if (oi->drouter == from->router_id) { | |
568 | if (is_debug) | |
569 | zlog_debug( | |
570 | "Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)"); | |
571 | /* Delayed acknowledgement */ | |
572 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list); | |
573 | if (oi->thread_send_lsack == NULL) | |
574 | oi->thread_send_lsack = thread_add_timer( | |
575 | master, ospf6_lsack_send_interface, oi, | |
576 | 3); | |
577 | } else { | |
578 | if (is_debug) | |
579 | zlog_debug( | |
580 | "No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)"); | |
581 | } | |
582 | return; | |
583 | } | |
584 | ||
585 | /* LSA is a duplicate, and was not treated as an implied | |
586 | acknowledgement. | |
587 | Direct acknowledgement sent */ | |
588 | if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE) | |
589 | && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) { | |
590 | if (is_debug) | |
591 | zlog_debug("Direct acknowledgement (BDR & Duplicate)"); | |
592 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list); | |
593 | if (from->thread_send_lsack == NULL) | |
594 | from->thread_send_lsack = thread_add_event( | |
595 | master, ospf6_lsack_send_neighbor, from, 0); | |
596 | return; | |
597 | } | |
598 | ||
599 | /* LSA's LS age is equal to Maxage, and there is no current instance | |
600 | of the LSA in the link state database, and none of router's | |
601 | neighbors are in states Exchange or Loading */ | |
602 | /* Direct acknowledgement sent, but this case is handled in | |
603 | early of ospf6_receive_lsa () */ | |
48454375 | 604 | } |
605 | ||
ac4d0be5 | 606 | static void ospf6_acknowledge_lsa_allother(struct ospf6_lsa *lsa, |
607 | int ismore_recent, | |
608 | struct ospf6_neighbor *from) | |
48454375 | 609 | { |
ac4d0be5 | 610 | struct ospf6_interface *oi; |
611 | int is_debug = 0; | |
612 | ||
613 | if (IS_OSPF6_DEBUG_FLOODING | |
614 | || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) | |
615 | is_debug++; | |
616 | ||
617 | assert(from && from->ospf6_if); | |
618 | oi = from->ospf6_if; | |
619 | ||
620 | /* LSA has been flood back out receiving interface. | |
621 | No acknowledgement sent. */ | |
622 | if (CHECK_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK)) { | |
623 | if (is_debug) | |
624 | zlog_debug("No acknowledgement (AllOther & FloodBack)"); | |
625 | return; | |
626 | } | |
627 | ||
628 | /* LSA is more recent than database copy, but was not flooded | |
629 | back out receiving interface. Delayed acknowledgement sent. */ | |
630 | if (ismore_recent < 0) { | |
631 | if (is_debug) | |
632 | zlog_debug( | |
633 | "Delayed acknowledgement (AllOther & MoreRecent)"); | |
634 | /* Delayed acknowledgement */ | |
635 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list); | |
636 | if (oi->thread_send_lsack == NULL) | |
637 | oi->thread_send_lsack = thread_add_timer( | |
638 | master, ospf6_lsack_send_interface, oi, 3); | |
639 | return; | |
640 | } | |
641 | ||
642 | /* LSA is a duplicate, and was treated as an implied acknowledgement. | |
643 | No acknowledgement sent. */ | |
644 | if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE) | |
645 | && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) { | |
646 | if (is_debug) | |
647 | zlog_debug( | |
648 | "No acknowledgement (AllOther & Duplicate & ImpliedAck)"); | |
649 | return; | |
650 | } | |
651 | ||
652 | /* LSA is a duplicate, and was not treated as an implied | |
653 | acknowledgement. | |
654 | Direct acknowledgement sent */ | |
655 | if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE) | |
656 | && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) { | |
657 | if (is_debug) | |
658 | zlog_debug( | |
659 | "Direct acknowledgement (AllOther & Duplicate)"); | |
660 | ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list); | |
661 | if (from->thread_send_lsack == NULL) | |
662 | from->thread_send_lsack = thread_add_event( | |
663 | master, ospf6_lsack_send_neighbor, from, 0); | |
664 | return; | |
665 | } | |
666 | ||
667 | /* LSA's LS age is equal to Maxage, and there is no current instance | |
668 | of the LSA in the link state database, and none of router's | |
669 | neighbors are in states Exchange or Loading */ | |
670 | /* Direct acknowledgement sent, but this case is handled in | |
671 | early of ospf6_receive_lsa () */ | |
48454375 | 672 | } |
673 | ||
ac4d0be5 | 674 | static void ospf6_acknowledge_lsa(struct ospf6_lsa *lsa, int ismore_recent, |
675 | struct ospf6_neighbor *from) | |
48454375 | 676 | { |
ac4d0be5 | 677 | struct ospf6_interface *oi; |
48454375 | 678 | |
ac4d0be5 | 679 | assert(from && from->ospf6_if); |
680 | oi = from->ospf6_if; | |
48454375 | 681 | |
ac4d0be5 | 682 | if (oi->state == OSPF6_INTERFACE_BDR) |
683 | ospf6_acknowledge_lsa_bdrouter(lsa, ismore_recent, from); | |
684 | else | |
685 | ospf6_acknowledge_lsa_allother(lsa, ismore_recent, from); | |
48454375 | 686 | } |
687 | ||
688 | /* RFC2328 section 13 (4): | |
689 | if MaxAge LSA and if we have no instance, and no neighbor | |
690 | is in states Exchange or Loading | |
691 | returns 1 if match this case, else returns 0 */ | |
ac4d0be5 | 692 | static int ospf6_is_maxage_lsa_drop(struct ospf6_lsa *lsa, |
693 | struct ospf6_neighbor *from) | |
48454375 | 694 | { |
ac4d0be5 | 695 | struct ospf6_neighbor *on; |
696 | struct ospf6_interface *oi; | |
697 | struct ospf6_area *oa; | |
698 | struct ospf6 *process = NULL; | |
699 | struct listnode *i, *j, *k; | |
700 | int count = 0; | |
701 | ||
702 | if (!OSPF6_LSA_IS_MAXAGE(lsa)) | |
703 | return 0; | |
704 | ||
705 | if (ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, | |
706 | lsa->header->adv_router, lsa->lsdb)) | |
707 | return 0; | |
708 | ||
709 | process = from->ospf6_if->area->ospf6; | |
710 | ||
711 | for (ALL_LIST_ELEMENTS_RO(process->area_list, i, oa)) | |
712 | for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) | |
713 | for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) | |
714 | if (on->state == OSPF6_NEIGHBOR_EXCHANGE | |
715 | || on->state == OSPF6_NEIGHBOR_LOADING) | |
716 | count++; | |
717 | ||
718 | if (count == 0) | |
719 | return 1; | |
720 | return 0; | |
48454375 | 721 | } |
722 | ||
723 | /* RFC2328 section 13 The Flooding Procedure */ | |
ac4d0be5 | 724 | void ospf6_receive_lsa(struct ospf6_neighbor *from, |
725 | struct ospf6_lsa_header *lsa_header) | |
48454375 | 726 | { |
ac4d0be5 | 727 | struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; |
728 | int ismore_recent; | |
729 | int is_debug = 0; | |
730 | unsigned int time_delta_ms; | |
731 | ||
732 | ismore_recent = 1; | |
733 | assert(from); | |
734 | ||
735 | /* make lsa structure for received lsa */ | |
736 | new = ospf6_lsa_create(lsa_header); | |
737 | ||
738 | if (IS_OSPF6_DEBUG_FLOODING | |
739 | || IS_OSPF6_DEBUG_FLOOD_TYPE(new->header->type)) { | |
740 | is_debug++; | |
741 | zlog_debug("LSA Receive from %s", from->name); | |
742 | ospf6_lsa_header_print(new); | |
743 | } | |
744 | ||
745 | /* (1) LSA Checksum */ | |
746 | if (!ospf6_lsa_checksum_valid(new->header)) { | |
747 | if (is_debug) | |
748 | zlog_debug("Wrong LSA Checksum, discard"); | |
749 | ospf6_lsa_delete(new); | |
750 | return; | |
751 | } | |
752 | ||
753 | /* (2) Examine the LSA's LS type. | |
754 | RFC2470 3.5.1. Receiving Link State Update packets */ | |
755 | if (IS_AREA_STUB(from->ospf6_if->area) | |
756 | && OSPF6_LSA_SCOPE(new->header->type) == OSPF6_SCOPE_AS) { | |
757 | if (is_debug) | |
758 | zlog_debug( | |
759 | "AS-External-LSA (or AS-scope LSA) in stub area, discard"); | |
760 | ospf6_lsa_delete(new); | |
761 | return; | |
762 | } | |
763 | ||
764 | /* (3) LSA which have reserved scope is discarded | |
765 | RFC2470 3.5.1. Receiving Link State Update packets */ | |
766 | /* Flooding scope check. LSAs with unknown scope are discarded here. | |
767 | Set appropriate LSDB for the LSA */ | |
768 | switch (OSPF6_LSA_SCOPE(new->header->type)) { | |
769 | case OSPF6_SCOPE_LINKLOCAL: | |
770 | new->lsdb = from->ospf6_if->lsdb; | |
771 | break; | |
772 | case OSPF6_SCOPE_AREA: | |
773 | new->lsdb = from->ospf6_if->area->lsdb; | |
774 | break; | |
775 | case OSPF6_SCOPE_AS: | |
776 | new->lsdb = from->ospf6_if->area->ospf6->lsdb; | |
777 | break; | |
778 | default: | |
779 | if (is_debug) | |
780 | zlog_debug("LSA has reserved scope, discard"); | |
781 | ospf6_lsa_delete(new); | |
782 | return; | |
783 | } | |
784 | ||
785 | /* (4) if MaxAge LSA and if we have no instance, and no neighbor | |
786 | is in states Exchange or Loading */ | |
787 | if (ospf6_is_maxage_lsa_drop(new, from)) { | |
788 | /* log */ | |
789 | if (is_debug) | |
790 | zlog_debug( | |
791 | "Drop MaxAge LSA with direct acknowledgement."); | |
792 | ||
793 | /* a) Acknowledge back to neighbor (Direct acknowledgement, | |
794 | * 13.5) */ | |
795 | ospf6_lsdb_add(ospf6_lsa_copy(new), from->lsack_list); | |
796 | if (from->thread_send_lsack == NULL) | |
797 | from->thread_send_lsack = thread_add_event( | |
798 | master, ospf6_lsack_send_neighbor, from, 0); | |
799 | ||
800 | /* b) Discard */ | |
801 | ospf6_lsa_delete(new); | |
802 | return; | |
803 | } | |
804 | ||
805 | /* (5) */ | |
806 | /* lookup the same database copy in lsdb */ | |
807 | old = ospf6_lsdb_lookup(new->header->type, new->header->id, | |
808 | new->header->adv_router, new->lsdb); | |
809 | if (old) { | |
810 | ismore_recent = ospf6_lsa_compare(new, old); | |
811 | if (ntohl(new->header->seqnum) == ntohl(old->header->seqnum)) { | |
812 | if (is_debug) | |
813 | zlog_debug("Received is duplicated LSA"); | |
814 | SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE); | |
815 | } | |
816 | } | |
817 | ||
818 | /* if no database copy or received is more recent */ | |
819 | if (old == NULL || ismore_recent < 0) { | |
820 | /* in case we have no database copy */ | |
821 | ismore_recent = -1; | |
822 | ||
823 | /* (a) MinLSArrival check */ | |
824 | if (old) { | |
825 | struct timeval now, res; | |
826 | monotime(&now); | |
827 | timersub(&now, &old->installed, &res); | |
828 | time_delta_ms = | |
829 | (res.tv_sec * 1000) + (int)(res.tv_usec / 1000); | |
830 | if (time_delta_ms | |
831 | < from->ospf6_if->area->ospf6->lsa_minarrival) { | |
832 | if (is_debug) | |
833 | zlog_debug( | |
834 | "LSA can't be updated within MinLSArrival, %dms < %dms, discard", | |
835 | time_delta_ms, | |
836 | from->ospf6_if->area->ospf6 | |
837 | ->lsa_minarrival); | |
838 | ospf6_lsa_delete(new); | |
839 | return; /* examin next lsa */ | |
840 | } | |
841 | } | |
842 | ||
843 | monotime(&new->received); | |
844 | ||
845 | if (is_debug) | |
846 | zlog_debug( | |
847 | "Install, Flood, Possibly acknowledge the received LSA"); | |
848 | ||
849 | /* Remove older copies of this LSA from retx lists */ | |
850 | if (old) | |
851 | ospf6_flood_clear(old); | |
852 | ||
853 | /* (b) immediately flood and (c) remove from all retrans-list */ | |
854 | /* Prevent self-originated LSA to be flooded. this is to make | |
855 | reoriginated instance of the LSA not to be rejected by other | |
856 | routers | |
857 | due to MinLSArrival. */ | |
858 | if (new->header->adv_router | |
859 | != from->ospf6_if->area->ospf6->router_id) | |
860 | ospf6_flood(from, new); | |
861 | ||
862 | /* (d), installing lsdb, which may cause routing | |
863 | table calculation (replacing database copy) */ | |
864 | ospf6_install_lsa(new); | |
865 | ||
866 | if (OSPF6_LSA_IS_MAXAGE(new)) | |
867 | ospf6_maxage_remove(from->ospf6_if->area->ospf6); | |
868 | ||
869 | /* (e) possibly acknowledge */ | |
870 | ospf6_acknowledge_lsa(new, ismore_recent, from); | |
871 | ||
872 | /* (f) Self Originated LSA, section 13.4 */ | |
873 | if (new->header->adv_router | |
874 | == from->ospf6_if->area->ospf6->router_id) { | |
875 | /* Self-originated LSA (newer than ours) is received | |
876 | from | |
877 | another router. We have to make a new instance of the | |
878 | LSA | |
879 | or have to flush this LSA. */ | |
880 | if (is_debug) { | |
881 | zlog_debug( | |
882 | "Newer instance of the self-originated LSA"); | |
883 | zlog_debug("Schedule reorigination"); | |
884 | } | |
885 | new->refresh = thread_add_event( | |
886 | master, ospf6_lsa_refresh, new, 0); | |
887 | } | |
888 | ||
889 | return; | |
890 | } | |
891 | ||
892 | /* (6) if there is instance on sending neighbor's request list */ | |
893 | if (ospf6_lsdb_lookup(new->header->type, new->header->id, | |
894 | new->header->adv_router, from->request_list)) { | |
895 | /* if no database copy, should go above state (5) */ | |
896 | assert(old); | |
897 | ||
898 | if (is_debug) { | |
899 | zlog_debug( | |
900 | "Received is not newer, on the neighbor's request-list"); | |
901 | zlog_debug("BadLSReq, discard the received LSA"); | |
902 | } | |
903 | ||
904 | /* BadLSReq */ | |
905 | thread_add_event(master, bad_lsreq, from, 0); | |
906 | ||
907 | ospf6_lsa_delete(new); | |
908 | return; | |
909 | } | |
910 | ||
911 | /* (7) if neither one is more recent */ | |
912 | if (ismore_recent == 0) { | |
913 | if (is_debug) | |
914 | zlog_debug( | |
915 | "The same instance as database copy (neither recent)"); | |
916 | ||
917 | /* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack | |
918 | */ | |
919 | rem = ospf6_lsdb_lookup(new->header->type, new->header->id, | |
920 | new->header->adv_router, | |
921 | from->retrans_list); | |
922 | if (rem) { | |
923 | if (is_debug) { | |
924 | zlog_debug( | |
925 | "It is on the neighbor's retrans-list."); | |
926 | zlog_debug( | |
927 | "Treat as an Implied acknowledgement"); | |
928 | } | |
929 | SET_FLAG(new->flag, OSPF6_LSA_IMPLIEDACK); | |
930 | ospf6_decrement_retrans_count(rem); | |
931 | ospf6_lsdb_remove(rem, from->retrans_list); | |
932 | } | |
933 | ||
934 | if (is_debug) | |
935 | zlog_debug("Possibly acknowledge and then discard"); | |
936 | ||
937 | /* (b) possibly acknowledge */ | |
938 | ospf6_acknowledge_lsa(new, ismore_recent, from); | |
939 | ||
940 | ospf6_lsa_delete(new); | |
941 | return; | |
942 | } | |
943 | ||
944 | /* (8) previous database copy is more recent */ | |
945 | { | |
946 | assert(old); | |
947 | ||
948 | /* If database copy is in 'Seqnumber Wrapping', | |
949 | simply discard the received LSA */ | |
950 | if (OSPF6_LSA_IS_MAXAGE(old) | |
951 | && old->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) { | |
952 | if (is_debug) { | |
953 | zlog_debug("The LSA is in Seqnumber Wrapping"); | |
954 | zlog_debug("MaxAge & MaxSeqNum, discard"); | |
955 | } | |
956 | ospf6_lsa_delete(new); | |
957 | return; | |
958 | } | |
959 | ||
960 | /* Otherwise, Send database copy of this LSA to this neighbor */ | |
961 | { | |
962 | if (is_debug) { | |
963 | zlog_debug("Database copy is more recent."); | |
964 | zlog_debug( | |
965 | "Send back directly and then discard"); | |
966 | } | |
967 | ||
968 | /* XXX, MinLSArrival check !? RFC 2328 13 (8) */ | |
969 | ||
970 | ospf6_lsdb_add(ospf6_lsa_copy(old), | |
971 | from->lsupdate_list); | |
972 | if (from->thread_send_lsupdate == NULL) | |
973 | from->thread_send_lsupdate = thread_add_event( | |
974 | master, ospf6_lsupdate_send_neighbor, | |
975 | from, 0); | |
976 | ospf6_lsa_delete(new); | |
977 | return; | |
978 | } | |
979 | return; | |
980 | } | |
48454375 | 981 | } |
982 | ||
983 | ||
1e05838a | 984 | DEFUN (debug_ospf6_flooding, |
985 | debug_ospf6_flooding_cmd, | |
986 | "debug ospf6 flooding", | |
987 | DEBUG_STR | |
988 | OSPF6_STR | |
989 | "Debug OSPFv3 flooding function\n" | |
990 | ) | |
991 | { | |
ac4d0be5 | 992 | OSPF6_DEBUG_FLOODING_ON(); |
993 | return CMD_SUCCESS; | |
1e05838a | 994 | } |
995 | ||
996 | DEFUN (no_debug_ospf6_flooding, | |
997 | no_debug_ospf6_flooding_cmd, | |
998 | "no debug ospf6 flooding", | |
999 | NO_STR | |
1000 | DEBUG_STR | |
1001 | OSPF6_STR | |
1002 | "Debug OSPFv3 flooding function\n" | |
1003 | ) | |
1004 | { | |
ac4d0be5 | 1005 | OSPF6_DEBUG_FLOODING_OFF(); |
1006 | return CMD_SUCCESS; | |
1e05838a | 1007 | } |
1008 | ||
ac4d0be5 | 1009 | int config_write_ospf6_debug_flood(struct vty *vty) |
1e05838a | 1010 | { |
ac4d0be5 | 1011 | if (IS_OSPF6_DEBUG_FLOODING) |
1012 | vty_out(vty, "debug ospf6 flooding%s", VNL); | |
1013 | return 0; | |
1e05838a | 1014 | } |
1015 | ||
ac4d0be5 | 1016 | void install_element_ospf6_debug_flood(void) |
1e05838a | 1017 | { |
ac4d0be5 | 1018 | install_element(ENABLE_NODE, &debug_ospf6_flooding_cmd); |
1019 | install_element(ENABLE_NODE, &no_debug_ospf6_flooding_cmd); | |
1020 | install_element(CONFIG_NODE, &debug_ospf6_flooding_cmd); | |
1021 | install_element(CONFIG_NODE, &no_debug_ospf6_flooding_cmd); | |
1e05838a | 1022 | } |