]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
508e53e2 | 2 | * Copyright (C) 2003 Yasuhiro Ohara |
718e3744 | 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 | |
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. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | /* Include other stuffs */ | |
718e3744 | 25 | #include "log.h" |
718e3744 | 26 | #include "linklist.h" |
1e05838a | 27 | #include "vector.h" |
28 | #include "vty.h" | |
718e3744 | 29 | #include "command.h" |
30 | #include "memory.h" | |
718e3744 | 31 | #include "thread.h" |
d8a4e42b | 32 | #include "checksum.h" |
718e3744 | 33 | |
34 | #include "ospf6_proto.h" | |
718e3744 | 35 | #include "ospf6_lsa.h" |
36 | #include "ospf6_lsdb.h" | |
37 | #include "ospf6_message.h" | |
718e3744 | 38 | |
39 | #include "ospf6_top.h" | |
40 | #include "ospf6_area.h" | |
41 | #include "ospf6_interface.h" | |
42 | #include "ospf6_neighbor.h" | |
718e3744 | 43 | |
508e53e2 | 44 | #include "ospf6_flood.h" |
049207c3 | 45 | #include "ospf6d.h" |
718e3744 | 46 | |
1e05838a | 47 | vector ospf6_lsa_handler_vector; |
718e3744 | 48 | |
6ac29a51 | 49 | static int |
1e05838a | 50 | ospf6_unknown_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) |
51 | { | |
52 | u_char *start, *end, *current; | |
53 | char byte[4]; | |
54 | ||
03d52f8d | 55 | start = (u_char *) lsa->header + sizeof (struct ospf6_lsa_header); |
56 | end = (u_char *) lsa->header + ntohs (lsa->header->length); | |
1e05838a | 57 | |
58 | vty_out (vty, " Unknown contents:%s", VNL); | |
59 | for (current = start; current < end; current ++) | |
60 | { | |
61 | if ((current - start) % 16 == 0) | |
62 | vty_out (vty, "%s ", VNL); | |
63 | else if ((current - start) % 4 == 0) | |
64 | vty_out (vty, " "); | |
718e3744 | 65 | |
1e05838a | 66 | snprintf (byte, sizeof (byte), "%02x", *current); |
67 | vty_out (vty, "%s", byte); | |
68 | } | |
69 | ||
70 | vty_out (vty, "%s%s", VNL, VNL); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | struct ospf6_lsa_handler unknown_handler = | |
75 | { | |
76 | OSPF6_LSTYPE_UNKNOWN, | |
e68a6767 DD |
77 | "Unknown", |
78 | "Unk", | |
1e05838a | 79 | ospf6_unknown_lsa_show, |
e68a6767 | 80 | NULL, |
1e05838a | 81 | OSPF6_LSA_DEBUG, |
82 | }; | |
83 | ||
84 | void | |
85 | ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler) | |
86 | { | |
87 | /* type in handler is host byte order */ | |
88 | int index = handler->type & OSPF6_LSTYPE_FCODE_MASK; | |
89 | vector_set_index (ospf6_lsa_handler_vector, index, handler); | |
90 | } | |
91 | ||
92 | struct ospf6_lsa_handler * | |
93 | ospf6_get_lsa_handler (u_int16_t type) | |
94 | { | |
95 | struct ospf6_lsa_handler *handler = NULL; | |
0c083ee9 | 96 | unsigned int index = ntohs (type) & OSPF6_LSTYPE_FCODE_MASK; |
1e05838a | 97 | |
55468c86 | 98 | if (index >= vector_active (ospf6_lsa_handler_vector)) |
1e05838a | 99 | handler = &unknown_handler; |
100 | else | |
101 | handler = vector_slot (ospf6_lsa_handler_vector, index); | |
102 | ||
2680aa2b | 103 | if (handler == NULL) |
104 | handler = &unknown_handler; | |
105 | ||
1e05838a | 106 | return handler; |
107 | } | |
718e3744 | 108 | |
0c083ee9 | 109 | const char * |
508e53e2 | 110 | ospf6_lstype_name (u_int16_t type) |
111 | { | |
112 | static char buf[8]; | |
1e05838a | 113 | struct ospf6_lsa_handler *handler; |
508e53e2 | 114 | |
1e05838a | 115 | handler = ospf6_get_lsa_handler (type); |
116 | if (handler && handler != &unknown_handler) | |
117 | return handler->name; | |
718e3744 | 118 | |
508e53e2 | 119 | snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); |
120 | return buf; | |
718e3744 | 121 | } |
122 | ||
e68a6767 DD |
123 | const char * |
124 | ospf6_lstype_short_name (u_int16_t type) | |
125 | { | |
126 | static char buf[8]; | |
127 | struct ospf6_lsa_handler *handler; | |
128 | ||
129 | handler = ospf6_get_lsa_handler (type); | |
130 | if (handler && handler != &unknown_handler) | |
131 | return handler->short_name; | |
132 | ||
133 | snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); | |
134 | return buf; | |
135 | } | |
136 | ||
1e05838a | 137 | u_char |
138 | ospf6_lstype_debug (u_int16_t type) | |
139 | { | |
140 | struct ospf6_lsa_handler *handler; | |
141 | handler = ospf6_get_lsa_handler (type); | |
142 | return handler->debug; | |
143 | } | |
144 | ||
718e3744 | 145 | /* RFC2328: Section 13.2 */ |
146 | int | |
508e53e2 | 147 | ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, |
148 | struct ospf6_lsa *lsa2) | |
718e3744 | 149 | { |
508e53e2 | 150 | int len; |
718e3744 | 151 | |
508e53e2 | 152 | assert (OSPF6_LSA_IS_SAME (lsa1, lsa2)); |
718e3744 | 153 | |
508e53e2 | 154 | /* XXX, Options ??? */ |
718e3744 | 155 | |
156 | ospf6_lsa_age_current (lsa1); | |
157 | ospf6_lsa_age_current (lsa2); | |
8551e6da DD |
158 | if (ntohs (lsa1->header->age) == OSPF_LSA_MAXAGE && |
159 | ntohs (lsa2->header->age) != OSPF_LSA_MAXAGE) | |
718e3744 | 160 | return 1; |
8551e6da DD |
161 | if (ntohs (lsa1->header->age) != OSPF_LSA_MAXAGE && |
162 | ntohs (lsa2->header->age) == OSPF_LSA_MAXAGE) | |
718e3744 | 163 | return 1; |
164 | ||
165 | /* compare body */ | |
166 | if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) | |
167 | return 1; | |
168 | ||
508e53e2 | 169 | len = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header); |
170 | return memcmp (lsa1->header + 1, lsa2->header + 1, len); | |
718e3744 | 171 | } |
172 | ||
173 | int | |
508e53e2 | 174 | ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, |
175 | struct ospf6_lsa *lsa2) | |
718e3744 | 176 | { |
508e53e2 | 177 | int length; |
718e3744 | 178 | |
508e53e2 | 179 | if (OSPF6_LSA_IS_MAXAGE (lsa1) ^ OSPF6_LSA_IS_MAXAGE (lsa2)) |
180 | return 1; | |
181 | if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) | |
182 | return 1; | |
09395e2a DO |
183 | /* Going beyond LSA headers to compare the payload only makes sense, when both LSAs aren't header-only. */ |
184 | if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY) != CHECK_FLAG (lsa2->flag, OSPF6_LSA_HEADERONLY)) | |
185 | { | |
186 | zlog_warn ("%s: only one of two (%s, %s) LSAs compared is header-only", __func__, lsa1->name, lsa2->name); | |
187 | return 1; | |
188 | } | |
189 | if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY)) | |
190 | return 0; | |
718e3744 | 191 | |
508e53e2 | 192 | length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header); |
09395e2a DO |
193 | /* Once upper layer verifies LSAs received, length underrun should become a warning. */ |
194 | if (length <= 0) | |
195 | return 0; | |
718e3744 | 196 | |
508e53e2 | 197 | return memcmp (OSPF6_LSA_HEADER_END (lsa1->header), |
198 | OSPF6_LSA_HEADER_END (lsa2->header), length); | |
718e3744 | 199 | } |
200 | ||
201 | /* ospf6 age functions */ | |
3b68735f | 202 | /* calculate birth */ |
718e3744 | 203 | static void |
204 | ospf6_lsa_age_set (struct ospf6_lsa *lsa) | |
205 | { | |
206 | struct timeval now; | |
207 | ||
208 | assert (lsa && lsa->header); | |
209 | ||
86f72dcb TS |
210 | if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) |
211 | zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", | |
6099b3b5 | 212 | safe_strerror (errno)); |
718e3744 | 213 | |
214 | lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age); | |
215 | lsa->birth.tv_usec = now.tv_usec; | |
3b68735f | 216 | |
718e3744 | 217 | return; |
218 | } | |
219 | ||
220 | /* this function calculates current age from its birth, | |
221 | then update age field of LSA header. return value is current age */ | |
222 | u_int16_t | |
223 | ospf6_lsa_age_current (struct ospf6_lsa *lsa) | |
224 | { | |
225 | struct timeval now; | |
226 | u_int32_t ulage; | |
227 | u_int16_t age; | |
228 | ||
229 | assert (lsa); | |
230 | assert (lsa->header); | |
231 | ||
232 | /* current time */ | |
86f72dcb TS |
233 | if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) |
234 | zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", | |
6099b3b5 | 235 | safe_strerror (errno)); |
718e3744 | 236 | |
8551e6da | 237 | if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE) |
9b4ef258 | 238 | { |
aabbb1ae TH |
239 | /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using |
240 | relative time, we cannot compare against lsa birth time, so | |
241 | we catch this special case here. */ | |
8551e6da DD |
242 | lsa->header->age = htons (OSPF_LSA_MAXAGE); |
243 | return OSPF_LSA_MAXAGE; | |
9b4ef258 | 244 | } |
718e3744 | 245 | /* calculate age */ |
246 | ulage = now.tv_sec - lsa->birth.tv_sec; | |
247 | ||
248 | /* if over MAXAGE, set to it */ | |
8551e6da | 249 | age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage); |
718e3744 | 250 | |
251 | lsa->header->age = htons (age); | |
252 | return age; | |
253 | } | |
254 | ||
255 | /* update age field of LSA header with adding InfTransDelay */ | |
256 | void | |
257 | ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) | |
258 | { | |
259 | unsigned short age; | |
260 | ||
261 | age = ospf6_lsa_age_current (lsa) + transdelay; | |
8551e6da DD |
262 | if (age > OSPF_LSA_MAXAGE) |
263 | age = OSPF_LSA_MAXAGE; | |
718e3744 | 264 | lsa->header->age = htons (age); |
718e3744 | 265 | } |
266 | ||
267 | void | |
268 | ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) | |
269 | { | |
270 | /* log */ | |
1e05838a | 271 | if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) |
c6487d61 | 272 | zlog_debug ("LSA: Premature aging: %s", lsa->name); |
718e3744 | 273 | |
508e53e2 | 274 | THREAD_OFF (lsa->expire); |
275 | THREAD_OFF (lsa->refresh); | |
718e3744 | 276 | |
ac58e143 DD |
277 | /* |
278 | * We clear the LSA from the neighbor retx lists now because it | |
279 | * will not get deleted later. Essentially, changing the age to | |
280 | * MaxAge will prevent this LSA from being matched with its | |
281 | * existing entries in the retx list thereby causing those entries | |
282 | * to be silently replaced with its MaxAged version, but with ever | |
283 | * increasing retx count causing this LSA to remain forever and | |
284 | * for the MaxAge remover thread to be called forever too. | |
285 | * | |
286 | * The reason the previous entry silently disappears is that when | |
287 | * entry is added to a neighbor's retx list, it replaces the existing | |
288 | * entry. But since the ospf6_lsdb_add() routine is generic and not aware | |
289 | * of the special semantics of retx count, the retx count is not | |
290 | * decremented when its replaced. Attempting to add the incr and decr | |
291 | * retx count routines as the hook_add and hook_remove for the retx lists | |
292 | * have a problem because the hook_remove routine is called for MaxAge | |
293 | * entries (as will be the case in a traditional LSDB, unlike in this case | |
294 | * where an LSDB is used as an efficient tree structure to store all kinds | |
295 | * of data) that are added instead of calling the hook_add routine. | |
296 | */ | |
297 | ||
298 | ospf6_flood_clear (lsa); | |
299 | ||
8551e6da | 300 | lsa->header->age = htons (OSPF_LSA_MAXAGE); |
718e3744 | 301 | thread_execute (master, ospf6_lsa_expire, lsa, 0); |
302 | } | |
303 | ||
304 | /* check which is more recent. if a is more recent, return -1; | |
305 | if the same, return 0; otherwise(b is more recent), return 1 */ | |
306 | int | |
508e53e2 | 307 | ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) |
718e3744 | 308 | { |
64bf3ab7 | 309 | int seqnuma, seqnumb; |
718e3744 | 310 | u_int16_t cksuma, cksumb; |
311 | u_int16_t agea, ageb; | |
312 | ||
313 | assert (a && a->header); | |
314 | assert (b && b->header); | |
508e53e2 | 315 | assert (OSPF6_LSA_IS_SAME (a, b)); |
718e3744 | 316 | |
64bf3ab7 OZ |
317 | seqnuma = (int) ntohl (a->header->seqnum); |
318 | seqnumb = (int) ntohl (b->header->seqnum); | |
718e3744 | 319 | |
320 | /* compare by sequence number */ | |
718e3744 | 321 | if (seqnuma > seqnumb) |
322 | return -1; | |
64bf3ab7 | 323 | if (seqnuma < seqnumb) |
718e3744 | 324 | return 1; |
325 | ||
326 | /* Checksum */ | |
327 | cksuma = ntohs (a->header->checksum); | |
328 | cksumb = ntohs (b->header->checksum); | |
329 | if (cksuma > cksumb) | |
330 | return -1; | |
331 | if (cksuma < cksumb) | |
332 | return 0; | |
333 | ||
508e53e2 | 334 | /* Update Age */ |
718e3744 | 335 | agea = ospf6_lsa_age_current (a); |
336 | ageb = ospf6_lsa_age_current (b); | |
337 | ||
508e53e2 | 338 | /* MaxAge check */ |
8551e6da | 339 | if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE) |
718e3744 | 340 | return -1; |
8551e6da | 341 | else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE) |
718e3744 | 342 | return 1; |
343 | ||
508e53e2 | 344 | /* Age check */ |
8551e6da | 345 | if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF) |
718e3744 | 346 | return 1; |
8551e6da | 347 | else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF) |
718e3744 | 348 | return -1; |
349 | ||
350 | /* neither recent */ | |
718e3744 | 351 | return 0; |
352 | } | |
353 | ||
508e53e2 | 354 | char * |
355 | ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size) | |
718e3744 | 356 | { |
508e53e2 | 357 | char id[16], adv_router[16]; |
358 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); | |
359 | inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, | |
360 | sizeof (adv_router)); | |
361 | snprintf (buf, size, "[%s Id:%s Adv:%s]", | |
1e05838a | 362 | ospf6_lstype_name (lsa->header->type), id, adv_router); |
508e53e2 | 363 | return buf; |
718e3744 | 364 | } |
365 | ||
508e53e2 | 366 | void |
367 | ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header) | |
718e3744 | 368 | { |
508e53e2 | 369 | char id[16], adv_router[16]; |
370 | inet_ntop (AF_INET, &header->id, id, sizeof (id)); | |
371 | inet_ntop (AF_INET, &header->adv_router, adv_router, | |
372 | sizeof (adv_router)); | |
c6487d61 | 373 | zlog_debug (" [%s Id:%s Adv:%s]", |
374 | ospf6_lstype_name (header->type), id, adv_router); | |
375 | zlog_debug (" Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d", | |
376 | ntohs (header->age), (u_long) ntohl (header->seqnum), | |
377 | ntohs (header->checksum), ntohs (header->length)); | |
718e3744 | 378 | } |
379 | ||
508e53e2 | 380 | void |
381 | ospf6_lsa_header_print (struct ospf6_lsa *lsa) | |
718e3744 | 382 | { |
508e53e2 | 383 | ospf6_lsa_age_current (lsa); |
384 | ospf6_lsa_header_print_raw (lsa->header); | |
718e3744 | 385 | } |
386 | ||
718e3744 | 387 | void |
388 | ospf6_lsa_show_summary_header (struct vty *vty) | |
389 | { | |
e68a6767 | 390 | vty_out (vty, "%-4s %-15s%-15s%4s %8s %30s%s", |
718e3744 | 391 | "Type", "LSId", "AdvRouter", "Age", "SeqNum", |
e68a6767 | 392 | "Payload", VNL); |
718e3744 | 393 | } |
394 | ||
395 | void | |
396 | ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) | |
397 | { | |
508e53e2 | 398 | char adv_router[16], id[16]; |
e68a6767 DD |
399 | int type; |
400 | struct ospf6_lsa_handler *handler; | |
401 | char buf[64], tmpbuf[80]; | |
402 | int cnt = 0; | |
718e3744 | 403 | |
404 | assert (lsa); | |
405 | assert (lsa->header); | |
406 | ||
718e3744 | 407 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); |
408 | inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, | |
409 | sizeof (adv_router)); | |
410 | ||
e68a6767 DD |
411 | type = ntohs(lsa->header->type); |
412 | handler = ospf6_get_lsa_handler (lsa->header->type); | |
413 | if ((type == OSPF6_LSTYPE_INTER_PREFIX) || | |
414 | (type == OSPF6_LSTYPE_INTER_ROUTER) || | |
415 | (type == OSPF6_LSTYPE_AS_EXTERNAL)) | |
416 | { | |
417 | vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s", | |
418 | ospf6_lstype_short_name (lsa->header->type), | |
419 | id, adv_router, ospf6_lsa_age_current (lsa), | |
420 | (u_long) ntohl (lsa->header->seqnum), | |
421 | handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL); | |
422 | } | |
423 | else if (type != OSPF6_LSTYPE_UNKNOWN) | |
424 | { | |
425 | sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx", | |
426 | ospf6_lstype_short_name (lsa->header->type), | |
427 | id, adv_router, ospf6_lsa_age_current (lsa), | |
428 | (u_long) ntohl (lsa->header->seqnum)); | |
429 | ||
430 | while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) | |
431 | { | |
432 | vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL); | |
433 | cnt++; | |
434 | } | |
435 | } | |
436 | else | |
437 | { | |
438 | vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s", | |
439 | ospf6_lstype_short_name (lsa->header->type), | |
440 | id, adv_router, ospf6_lsa_age_current (lsa), | |
441 | (u_long) ntohl (lsa->header->seqnum), VNL); | |
442 | } | |
718e3744 | 443 | } |
444 | ||
445 | void | |
446 | ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) | |
447 | { | |
448 | u_char *start, *end, *current; | |
449 | char byte[4]; | |
450 | ||
03d52f8d | 451 | start = (u_char *) lsa->header; |
452 | end = (u_char *) lsa->header + ntohs (lsa->header->length); | |
718e3744 | 453 | |
049207c3 | 454 | vty_out (vty, "%s", VNL); |
455 | vty_out (vty, "%s:%s", lsa->name, VNL); | |
718e3744 | 456 | |
457 | for (current = start; current < end; current ++) | |
458 | { | |
459 | if ((current - start) % 16 == 0) | |
049207c3 | 460 | vty_out (vty, "%s ", VNL); |
718e3744 | 461 | else if ((current - start) % 4 == 0) |
462 | vty_out (vty, " "); | |
463 | ||
464 | snprintf (byte, sizeof (byte), "%02x", *current); | |
465 | vty_out (vty, "%s", byte); | |
466 | } | |
467 | ||
049207c3 | 468 | vty_out (vty, "%s%s", VNL, VNL); |
6452df09 | 469 | return; |
718e3744 | 470 | } |
471 | ||
508e53e2 | 472 | void |
473 | ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) | |
474 | { | |
475 | char adv_router[64], id[64]; | |
476 | ||
477 | assert (lsa && lsa->header); | |
478 | ||
479 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); | |
480 | inet_ntop (AF_INET, &lsa->header->adv_router, | |
481 | adv_router, sizeof (adv_router)); | |
482 | ||
049207c3 | 483 | vty_out (vty, "%s", VNL); |
508e53e2 | 484 | vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), |
1e05838a | 485 | ospf6_lstype_name (lsa->header->type), VNL); |
049207c3 | 486 | vty_out (vty, "Link State ID: %s%s", id, VNL); |
487 | vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); | |
508e53e2 | 488 | vty_out (vty, "LS Sequence Number: %#010lx%s", |
049207c3 | 489 | (u_long) ntohl (lsa->header->seqnum), VNL); |
508e53e2 | 490 | vty_out (vty, "CheckSum: %#06hx Length: %hu%s", |
491 | ntohs (lsa->header->checksum), | |
049207c3 | 492 | ntohs (lsa->header->length), VNL); |
8ae454e7 DD |
493 | vty_out (vty, "Flag: %x %s", lsa->flag, VNL); |
494 | vty_out (vty, "Lock: %d %s", lsa->lock, VNL); | |
495 | vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); | |
ee046671 DS |
496 | vty_out (vty, "Threads: Expire: %p, Refresh: %p %s", |
497 | lsa->expire, lsa->refresh, VNL); | |
049207c3 | 498 | vty_out (vty, "%s", VNL); |
6452df09 | 499 | return; |
508e53e2 | 500 | } |
501 | ||
6452df09 | 502 | void |
503 | ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) | |
504 | { | |
505 | char adv_router[64], id[64]; | |
1e05838a | 506 | struct ospf6_lsa_handler *handler; |
e68a6767 DD |
507 | struct timeval now, res; |
508 | char duration[16]; | |
6452df09 | 509 | |
510 | assert (lsa && lsa->header); | |
718e3744 | 511 | |
6452df09 | 512 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); |
513 | inet_ntop (AF_INET, &lsa->header->adv_router, | |
514 | adv_router, sizeof (adv_router)); | |
515 | ||
e68a6767 DD |
516 | quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); |
517 | timersub (&now, &lsa->installed, &res); | |
518 | timerstring (&res, duration, sizeof (duration)); | |
519 | ||
6452df09 | 520 | vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), |
1e05838a | 521 | ospf6_lstype_name (lsa->header->type), VNL); |
6452df09 | 522 | vty_out (vty, "Link State ID: %s%s", id, VNL); |
523 | vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); | |
524 | vty_out (vty, "LS Sequence Number: %#010lx%s", | |
525 | (u_long) ntohl (lsa->header->seqnum), VNL); | |
526 | vty_out (vty, "CheckSum: %#06hx Length: %hu%s", | |
527 | ntohs (lsa->header->checksum), | |
528 | ntohs (lsa->header->length), VNL); | |
e68a6767 | 529 | vty_out (vty, "Duration: %s%s", duration, VNL); |
6452df09 | 530 | |
1e05838a | 531 | handler = ospf6_get_lsa_handler (lsa->header->type); |
532 | if (handler->show == NULL) | |
533 | handler = &unknown_handler; | |
534 | (*handler->show) (vty, lsa); | |
6452df09 | 535 | |
536 | vty_out (vty, "%s", VNL); | |
537 | } | |
538 | ||
539 | /* OSPFv3 LSA creation/deletion function */ | |
718e3744 | 540 | struct ospf6_lsa * |
508e53e2 | 541 | ospf6_lsa_create (struct ospf6_lsa_header *header) |
718e3744 | 542 | { |
543 | struct ospf6_lsa *lsa = NULL; | |
508e53e2 | 544 | struct ospf6_lsa_header *new_header = NULL; |
718e3744 | 545 | u_int16_t lsa_size = 0; |
718e3744 | 546 | |
508e53e2 | 547 | /* size of the entire LSA */ |
548 | lsa_size = ntohs (header->length); /* XXX vulnerable */ | |
718e3744 | 549 | |
550 | /* allocate memory for this LSA */ | |
508e53e2 | 551 | new_header = (struct ospf6_lsa_header *) |
718e3744 | 552 | XMALLOC (MTYPE_OSPF6_LSA, lsa_size); |
718e3744 | 553 | |
508e53e2 | 554 | /* copy LSA from original header */ |
555 | memcpy (new_header, header, lsa_size); | |
718e3744 | 556 | |
557 | /* LSA information structure */ | |
558 | /* allocate memory */ | |
559 | lsa = (struct ospf6_lsa *) | |
393deb9b | 560 | XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); |
718e3744 | 561 | |
508e53e2 | 562 | lsa->header = (struct ospf6_lsa_header *) new_header; |
718e3744 | 563 | |
564 | /* dump string */ | |
508e53e2 | 565 | ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); |
718e3744 | 566 | |
3b68735f | 567 | /* calculate birth of this lsa */ |
718e3744 | 568 | ospf6_lsa_age_set (lsa); |
569 | ||
718e3744 | 570 | return lsa; |
571 | } | |
572 | ||
573 | struct ospf6_lsa * | |
508e53e2 | 574 | ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header) |
718e3744 | 575 | { |
576 | struct ospf6_lsa *lsa = NULL; | |
508e53e2 | 577 | struct ospf6_lsa_header *new_header = NULL; |
718e3744 | 578 | |
579 | /* allocate memory for this LSA */ | |
508e53e2 | 580 | new_header = (struct ospf6_lsa_header *) |
581 | XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_header)); | |
718e3744 | 582 | |
508e53e2 | 583 | /* copy LSA from original header */ |
584 | memcpy (new_header, header, sizeof (struct ospf6_lsa_header)); | |
718e3744 | 585 | |
586 | /* LSA information structure */ | |
587 | /* allocate memory */ | |
588 | lsa = (struct ospf6_lsa *) | |
393deb9b | 589 | XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); |
718e3744 | 590 | |
508e53e2 | 591 | lsa->header = (struct ospf6_lsa_header *) new_header; |
6452df09 | 592 | SET_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY); |
718e3744 | 593 | |
594 | /* dump string */ | |
508e53e2 | 595 | ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); |
718e3744 | 596 | |
3b68735f | 597 | /* calculate birth of this lsa */ |
718e3744 | 598 | ospf6_lsa_age_set (lsa); |
599 | ||
718e3744 | 600 | return lsa; |
601 | } | |
602 | ||
603 | void | |
604 | ospf6_lsa_delete (struct ospf6_lsa *lsa) | |
605 | { | |
508e53e2 | 606 | assert (lsa->lock == 0); |
718e3744 | 607 | |
608 | /* cancel threads */ | |
508e53e2 | 609 | THREAD_OFF (lsa->expire); |
610 | THREAD_OFF (lsa->refresh); | |
718e3744 | 611 | |
718e3744 | 612 | /* do free */ |
508e53e2 | 613 | XFREE (MTYPE_OSPF6_LSA, lsa->header); |
614 | XFREE (MTYPE_OSPF6_LSA, lsa); | |
615 | } | |
718e3744 | 616 | |
508e53e2 | 617 | struct ospf6_lsa * |
618 | ospf6_lsa_copy (struct ospf6_lsa *lsa) | |
619 | { | |
620 | struct ospf6_lsa *copy = NULL; | |
621 | ||
508e53e2 | 622 | ospf6_lsa_age_current (lsa); |
6452df09 | 623 | if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) |
508e53e2 | 624 | copy = ospf6_lsa_create_headeronly (lsa->header); |
718e3744 | 625 | else |
508e53e2 | 626 | copy = ospf6_lsa_create (lsa->header); |
627 | assert (copy->lock == 0); | |
628 | ||
3b68735f | 629 | copy->birth = lsa->birth; |
508e53e2 | 630 | copy->originated = lsa->originated; |
ccb59b11 | 631 | copy->received = lsa->received; |
632 | copy->installed = lsa->installed; | |
6452df09 | 633 | copy->lsdb = lsa->lsdb; |
a765eb93 | 634 | copy->rn = NULL; |
508e53e2 | 635 | |
508e53e2 | 636 | return copy; |
718e3744 | 637 | } |
638 | ||
508e53e2 | 639 | /* increment reference counter of struct ospf6_lsa */ |
718e3744 | 640 | void |
641 | ospf6_lsa_lock (struct ospf6_lsa *lsa) | |
642 | { | |
643 | lsa->lock++; | |
644 | return; | |
645 | } | |
646 | ||
508e53e2 | 647 | /* decrement reference counter of struct ospf6_lsa */ |
718e3744 | 648 | void |
649 | ospf6_lsa_unlock (struct ospf6_lsa *lsa) | |
650 | { | |
651 | /* decrement reference counter */ | |
508e53e2 | 652 | assert (lsa->lock > 0); |
653 | lsa->lock--; | |
718e3744 | 654 | |
508e53e2 | 655 | if (lsa->lock != 0) |
656 | return; | |
657 | ||
508e53e2 | 658 | ospf6_lsa_delete (lsa); |
718e3744 | 659 | } |
660 | ||
6b0655a2 | 661 | |
508e53e2 | 662 | /* ospf6 lsa expiry */ |
718e3744 | 663 | int |
664 | ospf6_lsa_expire (struct thread *thread) | |
665 | { | |
666 | struct ospf6_lsa *lsa; | |
718e3744 | 667 | |
668 | lsa = (struct ospf6_lsa *) THREAD_ARG (thread); | |
718e3744 | 669 | |
508e53e2 | 670 | assert (lsa && lsa->header); |
671 | assert (OSPF6_LSA_IS_MAXAGE (lsa)); | |
672 | assert (! lsa->refresh); | |
718e3744 | 673 | |
674 | lsa->expire = (struct thread *) NULL; | |
675 | ||
1e05838a | 676 | if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) |
718e3744 | 677 | { |
c6487d61 | 678 | zlog_debug ("LSA Expire:"); |
508e53e2 | 679 | ospf6_lsa_header_print (lsa); |
680 | } | |
718e3744 | 681 | |
6452df09 | 682 | if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) |
508e53e2 | 683 | return 0; /* dbexchange will do something ... */ |
718e3744 | 684 | |
508e53e2 | 685 | /* reinstall lsa */ |
3b68735f | 686 | ospf6_install_lsa (lsa); |
508e53e2 | 687 | |
bf986da7 DD |
688 | /* reflood lsa */ |
689 | ospf6_flood (NULL, lsa); | |
690 | ||
508e53e2 | 691 | /* schedule maxage remover */ |
692 | ospf6_maxage_remove (ospf6); | |
718e3744 | 693 | |
694 | return 0; | |
695 | } | |
696 | ||
697 | int | |
698 | ospf6_lsa_refresh (struct thread *thread) | |
699 | { | |
6452df09 | 700 | struct ospf6_lsa *old, *self, *new; |
701 | struct ospf6_lsdb *lsdb_self; | |
718e3744 | 702 | |
703 | assert (thread); | |
6452df09 | 704 | old = (struct ospf6_lsa *) THREAD_ARG (thread); |
705 | assert (old && old->header); | |
718e3744 | 706 | |
6452df09 | 707 | old->refresh = (struct thread *) NULL; |
708 | ||
709 | lsdb_self = ospf6_get_scoped_lsdb_self (old); | |
710 | self = ospf6_lsdb_lookup (old->header->type, old->header->id, | |
711 | old->header->adv_router, lsdb_self); | |
712 | if (self == NULL) | |
713 | { | |
1e05838a | 714 | if (IS_OSPF6_DEBUG_LSA_TYPE (old->header->type)) |
c6487d61 | 715 | zlog_debug ("Refresh: could not find self LSA, flush %s", old->name); |
6452df09 | 716 | ospf6_lsa_premature_aging (old); |
717 | return 0; | |
718 | } | |
719 | ||
720 | /* Reset age, increment LS sequence number. */ | |
721 | self->header->age = htons (0); | |
722 | self->header->seqnum = | |
723 | ospf6_new_ls_seqnum (self->header->type, self->header->id, | |
724 | self->header->adv_router, old->lsdb); | |
725 | ospf6_lsa_checksum (self->header); | |
726 | ||
727 | new = ospf6_lsa_create (self->header); | |
728 | new->lsdb = old->lsdb; | |
729 | new->refresh = thread_add_timer (master, ospf6_lsa_refresh, new, | |
8551e6da | 730 | OSPF_LS_REFRESH_TIME); |
718e3744 | 731 | |
6452df09 | 732 | /* store it in the LSDB for self-originated LSAs */ |
733 | ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self); | |
718e3744 | 734 | |
1e05838a | 735 | if (IS_OSPF6_DEBUG_LSA_TYPE (new->header->type)) |
718e3744 | 736 | { |
c6487d61 | 737 | zlog_debug ("LSA Refresh:"); |
6452df09 | 738 | ospf6_lsa_header_print (new); |
718e3744 | 739 | } |
740 | ||
6452df09 | 741 | ospf6_install_lsa (new); |
bf986da7 | 742 | ospf6_flood (NULL, new); |
6452df09 | 743 | |
508e53e2 | 744 | return 0; |
718e3744 | 745 | } |
746 | ||
6b0655a2 | 747 | |
718e3744 | 748 | |
d8a4e42b | 749 | /* Fletcher Checksum -- Refer to RFC1008. */ |
718e3744 | 750 | |
d8a4e42b JR |
751 | /* All the offsets are zero-based. The offsets in the RFC1008 are |
752 | one-based. */ | |
718e3744 | 753 | unsigned short |
754 | ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) | |
755 | { | |
d8a4e42b JR |
756 | u_char *buffer = (u_char *) &lsa_header->type; |
757 | int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ | |
718e3744 | 758 | |
d8a4e42b JR |
759 | /* Skip the AGE field */ |
760 | u_int16_t len = ntohs(lsa_header->length) - type_offset; | |
718e3744 | 761 | |
d8a4e42b JR |
762 | /* Checksum offset starts from "type" field, not the beginning of the |
763 | lsa_header struct. The offset is 14, rather than 16. */ | |
764 | int checksum_offset = (u_char *) &lsa_header->checksum - buffer; | |
765 | ||
766 | return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); | |
767 | } | |
718e3744 | 768 | |
d8a4e42b JR |
769 | int |
770 | ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) | |
771 | { | |
772 | u_char *buffer = (u_char *) &lsa_header->type; | |
773 | int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ | |
718e3744 | 774 | |
d8a4e42b JR |
775 | /* Skip the AGE field */ |
776 | u_int16_t len = ntohs(lsa_header->length) - type_offset; | |
718e3744 | 777 | |
d8a4e42b | 778 | return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); |
718e3744 | 779 | } |
780 | ||
6452df09 | 781 | void |
6ac29a51 | 782 | ospf6_lsa_init (void) |
6452df09 | 783 | { |
1e05838a | 784 | ospf6_lsa_handler_vector = vector_init (0); |
6452df09 | 785 | ospf6_install_lsa_handler (&unknown_handler); |
718e3744 | 786 | } |
787 | ||
ae2254aa TG |
788 | void |
789 | ospf6_lsa_terminate (void) | |
790 | { | |
791 | vector_free (ospf6_lsa_handler_vector); | |
792 | } | |
6b0655a2 | 793 | |
6ac29a51 | 794 | static char * |
1e05838a | 795 | ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) |
796 | { | |
797 | static char buf[64]; | |
0c083ee9 | 798 | unsigned int i; |
799 | unsigned int size = strlen (h->name); | |
1e05838a | 800 | |
09df4574 | 801 | if (!strcmp(h->name, "unknown") && |
1e05838a | 802 | h->type != OSPF6_LSTYPE_UNKNOWN) |
803 | { | |
804 | snprintf (buf, sizeof (buf), "%#04hx", h->type); | |
805 | return buf; | |
806 | } | |
807 | ||
808 | for (i = 0; i < MIN (size, sizeof (buf)); i++) | |
809 | { | |
6b629fe3 DL |
810 | if (! islower ((unsigned char)h->name[i])) |
811 | buf[i] = tolower ((unsigned char)h->name[i]); | |
1e05838a | 812 | else |
813 | buf[i] = h->name[i]; | |
814 | } | |
815 | buf[size] = '\0'; | |
816 | return buf; | |
817 | } | |
718e3744 | 818 | |
1e05838a | 819 | DEFUN (debug_ospf6_lsa_type, |
820 | debug_ospf6_lsa_hex_cmd, | |
09df4574 | 821 | "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", |
508e53e2 | 822 | DEBUG_STR |
823 | OSPF6_STR | |
824 | "Debug Link State Advertisements (LSAs)\n" | |
1e05838a | 825 | "Specify LS type as Hexadecimal\n" |
508e53e2 | 826 | ) |
827 | { | |
0c083ee9 | 828 | unsigned int i; |
1e05838a | 829 | struct ospf6_lsa_handler *handler = NULL; |
1e05838a | 830 | |
831 | assert (argc); | |
508e53e2 | 832 | |
55468c86 | 833 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
718e3744 | 834 | { |
1e05838a | 835 | handler = vector_slot (ospf6_lsa_handler_vector, i); |
836 | if (handler == NULL) | |
837 | continue; | |
09df4574 | 838 | if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) |
1e05838a | 839 | break; |
840 | if (! strcasecmp (argv[0], handler->name)) | |
841 | break; | |
842 | handler = NULL; | |
508e53e2 | 843 | } |
844 | ||
1e05838a | 845 | if (handler == NULL) |
846 | handler = &unknown_handler; | |
847 | ||
848 | if (argc >= 2) | |
849 | { | |
850 | if (! strcmp (argv[1], "originate")) | |
851 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); | |
09df4574 | 852 | if (! strcmp (argv[1], "examine")) |
1e05838a | 853 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); |
854 | if (! strcmp (argv[1], "flooding")) | |
855 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); | |
856 | } | |
857 | else | |
858 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG); | |
859 | ||
508e53e2 | 860 | return CMD_SUCCESS; |
861 | } | |
862 | ||
09df4574 DD |
863 | ALIAS (debug_ospf6_lsa_type, |
864 | debug_ospf6_lsa_hex_detail_cmd, | |
865 | "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", | |
866 | DEBUG_STR | |
867 | OSPF6_STR | |
868 | "Debug Link State Advertisements (LSAs)\n" | |
869 | "Specify LS type as Hexadecimal\n" | |
870 | ) | |
871 | ||
1e05838a | 872 | DEFUN (no_debug_ospf6_lsa_type, |
873 | no_debug_ospf6_lsa_hex_cmd, | |
09df4574 | 874 | "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", |
508e53e2 | 875 | NO_STR |
876 | DEBUG_STR | |
877 | OSPF6_STR | |
878 | "Debug Link State Advertisements (LSAs)\n" | |
1e05838a | 879 | "Specify LS type as Hexadecimal\n" |
508e53e2 | 880 | ) |
881 | { | |
0c083ee9 | 882 | u_int i; |
1e05838a | 883 | struct ospf6_lsa_handler *handler = NULL; |
508e53e2 | 884 | |
1e05838a | 885 | assert (argc); |
886 | ||
55468c86 | 887 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
1e05838a | 888 | { |
889 | handler = vector_slot (ospf6_lsa_handler_vector, i); | |
890 | if (handler == NULL) | |
891 | continue; | |
09df4574 | 892 | if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) |
1e05838a | 893 | break; |
894 | if (! strcasecmp (argv[0], handler->name)) | |
895 | break; | |
896 | } | |
897 | ||
898 | if (handler == NULL) | |
899 | return CMD_SUCCESS; | |
900 | ||
901 | if (argc >= 2) | |
902 | { | |
903 | if (! strcmp (argv[1], "originate")) | |
904 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); | |
09df4574 | 905 | if (! strcmp (argv[1], "examine")) |
1e05838a | 906 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); |
907 | if (! strcmp (argv[1], "flooding")) | |
908 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); | |
718e3744 | 909 | } |
718e3744 | 910 | else |
1e05838a | 911 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); |
912 | ||
508e53e2 | 913 | return CMD_SUCCESS; |
718e3744 | 914 | } |
915 | ||
09df4574 DD |
916 | ALIAS (no_debug_ospf6_lsa_type, |
917 | no_debug_ospf6_lsa_hex_detail_cmd, | |
918 | "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", | |
919 | NO_STR | |
920 | DEBUG_STR | |
921 | OSPF6_STR | |
922 | "Debug Link State Advertisements (LSAs)\n" | |
923 | "Specify LS type as Hexadecimal\n" | |
924 | ) | |
718e3744 | 925 | |
1e05838a | 926 | void |
6ac29a51 | 927 | install_element_ospf6_debug_lsa (void) |
718e3744 | 928 | { |
1e05838a | 929 | install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); |
09df4574 | 930 | install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd); |
1e05838a | 931 | install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); |
09df4574 | 932 | install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); |
1e05838a | 933 | install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); |
09df4574 | 934 | install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd); |
1e05838a | 935 | install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); |
09df4574 | 936 | install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); |
718e3744 | 937 | } |
938 | ||
1e05838a | 939 | int |
940 | config_write_ospf6_debug_lsa (struct vty *vty) | |
718e3744 | 941 | { |
0c083ee9 | 942 | u_int i; |
1e05838a | 943 | struct ospf6_lsa_handler *handler; |
944 | ||
55468c86 | 945 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
1e05838a | 946 | { |
947 | handler = vector_slot (ospf6_lsa_handler_vector, i); | |
948 | if (handler == NULL) | |
949 | continue; | |
950 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG)) | |
951 | vty_out (vty, "debug ospf6 lsa %s%s", | |
952 | ospf6_lsa_handler_name (handler), VNL); | |
953 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE)) | |
954 | vty_out (vty, "debug ospf6 lsa %s originate%s", | |
955 | ospf6_lsa_handler_name (handler), VNL); | |
956 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN)) | |
09df4574 | 957 | vty_out (vty, "debug ospf6 lsa %s examine%s", |
1e05838a | 958 | ospf6_lsa_handler_name (handler), VNL); |
959 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) | |
960 | vty_out (vty, "debug ospf6 lsa %s flooding%s", | |
961 | ospf6_lsa_handler_name (handler), VNL); | |
962 | } | |
963 | ||
964 | return 0; | |
718e3744 | 965 | } |
966 | ||
718e3744 | 967 |