]>
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 | ||
cf672a86 | 210 | monotime(&now); |
718e3744 | 211 | |
212 | lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age); | |
213 | lsa->birth.tv_usec = now.tv_usec; | |
3b68735f | 214 | |
718e3744 | 215 | return; |
216 | } | |
217 | ||
218 | /* this function calculates current age from its birth, | |
219 | then update age field of LSA header. return value is current age */ | |
220 | u_int16_t | |
221 | ospf6_lsa_age_current (struct ospf6_lsa *lsa) | |
222 | { | |
223 | struct timeval now; | |
224 | u_int32_t ulage; | |
225 | u_int16_t age; | |
226 | ||
227 | assert (lsa); | |
228 | assert (lsa->header); | |
229 | ||
230 | /* current time */ | |
cf672a86 | 231 | monotime(&now); |
718e3744 | 232 | |
8551e6da | 233 | if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE) |
9b4ef258 | 234 | { |
aabbb1ae TH |
235 | /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using |
236 | relative time, we cannot compare against lsa birth time, so | |
237 | we catch this special case here. */ | |
8551e6da DD |
238 | lsa->header->age = htons (OSPF_LSA_MAXAGE); |
239 | return OSPF_LSA_MAXAGE; | |
9b4ef258 | 240 | } |
718e3744 | 241 | /* calculate age */ |
242 | ulage = now.tv_sec - lsa->birth.tv_sec; | |
243 | ||
244 | /* if over MAXAGE, set to it */ | |
8551e6da | 245 | age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage); |
718e3744 | 246 | |
247 | lsa->header->age = htons (age); | |
248 | return age; | |
249 | } | |
250 | ||
251 | /* update age field of LSA header with adding InfTransDelay */ | |
252 | void | |
253 | ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) | |
254 | { | |
255 | unsigned short age; | |
256 | ||
257 | age = ospf6_lsa_age_current (lsa) + transdelay; | |
8551e6da DD |
258 | if (age > OSPF_LSA_MAXAGE) |
259 | age = OSPF_LSA_MAXAGE; | |
718e3744 | 260 | lsa->header->age = htons (age); |
718e3744 | 261 | } |
262 | ||
263 | void | |
264 | ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) | |
265 | { | |
266 | /* log */ | |
1e05838a | 267 | if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) |
c6487d61 | 268 | zlog_debug ("LSA: Premature aging: %s", lsa->name); |
718e3744 | 269 | |
508e53e2 | 270 | THREAD_OFF (lsa->expire); |
271 | THREAD_OFF (lsa->refresh); | |
718e3744 | 272 | |
ac58e143 DD |
273 | /* |
274 | * We clear the LSA from the neighbor retx lists now because it | |
275 | * will not get deleted later. Essentially, changing the age to | |
276 | * MaxAge will prevent this LSA from being matched with its | |
277 | * existing entries in the retx list thereby causing those entries | |
278 | * to be silently replaced with its MaxAged version, but with ever | |
279 | * increasing retx count causing this LSA to remain forever and | |
280 | * for the MaxAge remover thread to be called forever too. | |
281 | * | |
282 | * The reason the previous entry silently disappears is that when | |
283 | * entry is added to a neighbor's retx list, it replaces the existing | |
284 | * entry. But since the ospf6_lsdb_add() routine is generic and not aware | |
285 | * of the special semantics of retx count, the retx count is not | |
286 | * decremented when its replaced. Attempting to add the incr and decr | |
287 | * retx count routines as the hook_add and hook_remove for the retx lists | |
288 | * have a problem because the hook_remove routine is called for MaxAge | |
289 | * entries (as will be the case in a traditional LSDB, unlike in this case | |
290 | * where an LSDB is used as an efficient tree structure to store all kinds | |
291 | * of data) that are added instead of calling the hook_add routine. | |
292 | */ | |
293 | ||
294 | ospf6_flood_clear (lsa); | |
295 | ||
8551e6da | 296 | lsa->header->age = htons (OSPF_LSA_MAXAGE); |
718e3744 | 297 | thread_execute (master, ospf6_lsa_expire, lsa, 0); |
298 | } | |
299 | ||
300 | /* check which is more recent. if a is more recent, return -1; | |
301 | if the same, return 0; otherwise(b is more recent), return 1 */ | |
302 | int | |
508e53e2 | 303 | ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) |
718e3744 | 304 | { |
52cf4a51 | 305 | int32_t seqnuma, seqnumb; |
718e3744 | 306 | u_int16_t cksuma, cksumb; |
307 | u_int16_t agea, ageb; | |
308 | ||
309 | assert (a && a->header); | |
310 | assert (b && b->header); | |
508e53e2 | 311 | assert (OSPF6_LSA_IS_SAME (a, b)); |
718e3744 | 312 | |
52cf4a51 YO |
313 | seqnuma = (int32_t) ntohl (a->header->seqnum); |
314 | seqnumb = (int32_t) ntohl (b->header->seqnum); | |
718e3744 | 315 | |
316 | /* compare by sequence number */ | |
718e3744 | 317 | if (seqnuma > seqnumb) |
318 | return -1; | |
64bf3ab7 | 319 | if (seqnuma < seqnumb) |
718e3744 | 320 | return 1; |
321 | ||
322 | /* Checksum */ | |
323 | cksuma = ntohs (a->header->checksum); | |
324 | cksumb = ntohs (b->header->checksum); | |
325 | if (cksuma > cksumb) | |
326 | return -1; | |
327 | if (cksuma < cksumb) | |
328 | return 0; | |
329 | ||
508e53e2 | 330 | /* Update Age */ |
718e3744 | 331 | agea = ospf6_lsa_age_current (a); |
332 | ageb = ospf6_lsa_age_current (b); | |
333 | ||
508e53e2 | 334 | /* MaxAge check */ |
8551e6da | 335 | if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE) |
718e3744 | 336 | return -1; |
8551e6da | 337 | else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE) |
718e3744 | 338 | return 1; |
339 | ||
508e53e2 | 340 | /* Age check */ |
8551e6da | 341 | if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF) |
718e3744 | 342 | return 1; |
8551e6da | 343 | else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF) |
718e3744 | 344 | return -1; |
345 | ||
346 | /* neither recent */ | |
718e3744 | 347 | return 0; |
348 | } | |
349 | ||
508e53e2 | 350 | char * |
351 | ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size) | |
718e3744 | 352 | { |
508e53e2 | 353 | char id[16], adv_router[16]; |
354 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); | |
355 | inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, | |
356 | sizeof (adv_router)); | |
357 | snprintf (buf, size, "[%s Id:%s Adv:%s]", | |
1e05838a | 358 | ospf6_lstype_name (lsa->header->type), id, adv_router); |
508e53e2 | 359 | return buf; |
718e3744 | 360 | } |
361 | ||
508e53e2 | 362 | void |
363 | ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header) | |
718e3744 | 364 | { |
508e53e2 | 365 | char id[16], adv_router[16]; |
366 | inet_ntop (AF_INET, &header->id, id, sizeof (id)); | |
367 | inet_ntop (AF_INET, &header->adv_router, adv_router, | |
368 | sizeof (adv_router)); | |
c6487d61 | 369 | zlog_debug (" [%s Id:%s Adv:%s]", |
370 | ospf6_lstype_name (header->type), id, adv_router); | |
371 | zlog_debug (" Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d", | |
372 | ntohs (header->age), (u_long) ntohl (header->seqnum), | |
373 | ntohs (header->checksum), ntohs (header->length)); | |
718e3744 | 374 | } |
375 | ||
508e53e2 | 376 | void |
377 | ospf6_lsa_header_print (struct ospf6_lsa *lsa) | |
718e3744 | 378 | { |
508e53e2 | 379 | ospf6_lsa_age_current (lsa); |
380 | ospf6_lsa_header_print_raw (lsa->header); | |
718e3744 | 381 | } |
382 | ||
718e3744 | 383 | void |
384 | ospf6_lsa_show_summary_header (struct vty *vty) | |
385 | { | |
e68a6767 | 386 | vty_out (vty, "%-4s %-15s%-15s%4s %8s %30s%s", |
718e3744 | 387 | "Type", "LSId", "AdvRouter", "Age", "SeqNum", |
e68a6767 | 388 | "Payload", VNL); |
718e3744 | 389 | } |
390 | ||
391 | void | |
392 | ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) | |
393 | { | |
508e53e2 | 394 | char adv_router[16], id[16]; |
e68a6767 DD |
395 | int type; |
396 | struct ospf6_lsa_handler *handler; | |
397 | char buf[64], tmpbuf[80]; | |
398 | int cnt = 0; | |
718e3744 | 399 | |
400 | assert (lsa); | |
401 | assert (lsa->header); | |
402 | ||
718e3744 | 403 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); |
404 | inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, | |
405 | sizeof (adv_router)); | |
406 | ||
e68a6767 DD |
407 | type = ntohs(lsa->header->type); |
408 | handler = ospf6_get_lsa_handler (lsa->header->type); | |
409 | if ((type == OSPF6_LSTYPE_INTER_PREFIX) || | |
410 | (type == OSPF6_LSTYPE_INTER_ROUTER) || | |
411 | (type == OSPF6_LSTYPE_AS_EXTERNAL)) | |
412 | { | |
413 | vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s", | |
414 | ospf6_lstype_short_name (lsa->header->type), | |
415 | id, adv_router, ospf6_lsa_age_current (lsa), | |
416 | (u_long) ntohl (lsa->header->seqnum), | |
417 | handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL); | |
418 | } | |
419 | else if (type != OSPF6_LSTYPE_UNKNOWN) | |
420 | { | |
421 | sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx", | |
422 | ospf6_lstype_short_name (lsa->header->type), | |
423 | id, adv_router, ospf6_lsa_age_current (lsa), | |
424 | (u_long) ntohl (lsa->header->seqnum)); | |
425 | ||
426 | while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) | |
427 | { | |
428 | vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL); | |
429 | cnt++; | |
430 | } | |
431 | } | |
432 | else | |
433 | { | |
434 | vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s", | |
435 | ospf6_lstype_short_name (lsa->header->type), | |
436 | id, adv_router, ospf6_lsa_age_current (lsa), | |
437 | (u_long) ntohl (lsa->header->seqnum), VNL); | |
438 | } | |
718e3744 | 439 | } |
440 | ||
441 | void | |
442 | ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) | |
443 | { | |
444 | u_char *start, *end, *current; | |
445 | char byte[4]; | |
446 | ||
03d52f8d | 447 | start = (u_char *) lsa->header; |
448 | end = (u_char *) lsa->header + ntohs (lsa->header->length); | |
718e3744 | 449 | |
049207c3 | 450 | vty_out (vty, "%s", VNL); |
451 | vty_out (vty, "%s:%s", lsa->name, VNL); | |
718e3744 | 452 | |
453 | for (current = start; current < end; current ++) | |
454 | { | |
455 | if ((current - start) % 16 == 0) | |
049207c3 | 456 | vty_out (vty, "%s ", VNL); |
718e3744 | 457 | else if ((current - start) % 4 == 0) |
458 | vty_out (vty, " "); | |
459 | ||
460 | snprintf (byte, sizeof (byte), "%02x", *current); | |
461 | vty_out (vty, "%s", byte); | |
462 | } | |
463 | ||
049207c3 | 464 | vty_out (vty, "%s%s", VNL, VNL); |
6452df09 | 465 | return; |
718e3744 | 466 | } |
467 | ||
508e53e2 | 468 | void |
469 | ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) | |
470 | { | |
471 | char adv_router[64], id[64]; | |
472 | ||
473 | assert (lsa && lsa->header); | |
474 | ||
475 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); | |
476 | inet_ntop (AF_INET, &lsa->header->adv_router, | |
477 | adv_router, sizeof (adv_router)); | |
478 | ||
049207c3 | 479 | vty_out (vty, "%s", VNL); |
508e53e2 | 480 | vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), |
1e05838a | 481 | ospf6_lstype_name (lsa->header->type), VNL); |
049207c3 | 482 | vty_out (vty, "Link State ID: %s%s", id, VNL); |
483 | vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); | |
508e53e2 | 484 | vty_out (vty, "LS Sequence Number: %#010lx%s", |
049207c3 | 485 | (u_long) ntohl (lsa->header->seqnum), VNL); |
508e53e2 | 486 | vty_out (vty, "CheckSum: %#06hx Length: %hu%s", |
487 | ntohs (lsa->header->checksum), | |
049207c3 | 488 | ntohs (lsa->header->length), VNL); |
8ae454e7 DD |
489 | vty_out (vty, "Flag: %x %s", lsa->flag, VNL); |
490 | vty_out (vty, "Lock: %d %s", lsa->lock, VNL); | |
491 | vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); | |
6c4f4e6e DL |
492 | vty_out (vty, "Threads: Expire: 0x%p, Refresh: 0x%p %s", |
493 | (void *)lsa->expire, (void *)lsa->refresh, VNL); | |
049207c3 | 494 | vty_out (vty, "%s", VNL); |
6452df09 | 495 | return; |
508e53e2 | 496 | } |
497 | ||
6452df09 | 498 | void |
499 | ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) | |
500 | { | |
501 | char adv_router[64], id[64]; | |
1e05838a | 502 | struct ospf6_lsa_handler *handler; |
e68a6767 DD |
503 | struct timeval now, res; |
504 | char duration[16]; | |
6452df09 | 505 | |
506 | assert (lsa && lsa->header); | |
718e3744 | 507 | |
6452df09 | 508 | inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); |
509 | inet_ntop (AF_INET, &lsa->header->adv_router, | |
510 | adv_router, sizeof (adv_router)); | |
511 | ||
cf672a86 | 512 | monotime(&now); |
e68a6767 DD |
513 | timersub (&now, &lsa->installed, &res); |
514 | timerstring (&res, duration, sizeof (duration)); | |
515 | ||
6452df09 | 516 | vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), |
1e05838a | 517 | ospf6_lstype_name (lsa->header->type), VNL); |
6452df09 | 518 | vty_out (vty, "Link State ID: %s%s", id, VNL); |
519 | vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); | |
520 | vty_out (vty, "LS Sequence Number: %#010lx%s", | |
521 | (u_long) ntohl (lsa->header->seqnum), VNL); | |
522 | vty_out (vty, "CheckSum: %#06hx Length: %hu%s", | |
523 | ntohs (lsa->header->checksum), | |
524 | ntohs (lsa->header->length), VNL); | |
e68a6767 | 525 | vty_out (vty, "Duration: %s%s", duration, VNL); |
6452df09 | 526 | |
1e05838a | 527 | handler = ospf6_get_lsa_handler (lsa->header->type); |
528 | if (handler->show == NULL) | |
529 | handler = &unknown_handler; | |
530 | (*handler->show) (vty, lsa); | |
6452df09 | 531 | |
532 | vty_out (vty, "%s", VNL); | |
533 | } | |
534 | ||
535 | /* OSPFv3 LSA creation/deletion function */ | |
718e3744 | 536 | struct ospf6_lsa * |
508e53e2 | 537 | ospf6_lsa_create (struct ospf6_lsa_header *header) |
718e3744 | 538 | { |
539 | struct ospf6_lsa *lsa = NULL; | |
508e53e2 | 540 | struct ospf6_lsa_header *new_header = NULL; |
718e3744 | 541 | u_int16_t lsa_size = 0; |
718e3744 | 542 | |
508e53e2 | 543 | /* size of the entire LSA */ |
544 | lsa_size = ntohs (header->length); /* XXX vulnerable */ | |
718e3744 | 545 | |
546 | /* allocate memory for this LSA */ | |
508e53e2 | 547 | new_header = (struct ospf6_lsa_header *) |
718e3744 | 548 | XMALLOC (MTYPE_OSPF6_LSA, lsa_size); |
718e3744 | 549 | |
508e53e2 | 550 | /* copy LSA from original header */ |
551 | memcpy (new_header, header, lsa_size); | |
718e3744 | 552 | |
553 | /* LSA information structure */ | |
554 | /* allocate memory */ | |
555 | lsa = (struct ospf6_lsa *) | |
393deb9b | 556 | XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); |
718e3744 | 557 | |
508e53e2 | 558 | lsa->header = (struct ospf6_lsa_header *) new_header; |
718e3744 | 559 | |
560 | /* dump string */ | |
508e53e2 | 561 | ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); |
718e3744 | 562 | |
3b68735f | 563 | /* calculate birth of this lsa */ |
718e3744 | 564 | ospf6_lsa_age_set (lsa); |
565 | ||
718e3744 | 566 | return lsa; |
567 | } | |
568 | ||
569 | struct ospf6_lsa * | |
508e53e2 | 570 | ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header) |
718e3744 | 571 | { |
572 | struct ospf6_lsa *lsa = NULL; | |
508e53e2 | 573 | struct ospf6_lsa_header *new_header = NULL; |
718e3744 | 574 | |
575 | /* allocate memory for this LSA */ | |
508e53e2 | 576 | new_header = (struct ospf6_lsa_header *) |
577 | XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_header)); | |
718e3744 | 578 | |
508e53e2 | 579 | /* copy LSA from original header */ |
580 | memcpy (new_header, header, sizeof (struct ospf6_lsa_header)); | |
718e3744 | 581 | |
582 | /* LSA information structure */ | |
583 | /* allocate memory */ | |
584 | lsa = (struct ospf6_lsa *) | |
393deb9b | 585 | XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); |
718e3744 | 586 | |
508e53e2 | 587 | lsa->header = (struct ospf6_lsa_header *) new_header; |
6452df09 | 588 | SET_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY); |
718e3744 | 589 | |
590 | /* dump string */ | |
508e53e2 | 591 | ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); |
718e3744 | 592 | |
3b68735f | 593 | /* calculate birth of this lsa */ |
718e3744 | 594 | ospf6_lsa_age_set (lsa); |
595 | ||
718e3744 | 596 | return lsa; |
597 | } | |
598 | ||
599 | void | |
600 | ospf6_lsa_delete (struct ospf6_lsa *lsa) | |
601 | { | |
508e53e2 | 602 | assert (lsa->lock == 0); |
718e3744 | 603 | |
604 | /* cancel threads */ | |
508e53e2 | 605 | THREAD_OFF (lsa->expire); |
606 | THREAD_OFF (lsa->refresh); | |
718e3744 | 607 | |
718e3744 | 608 | /* do free */ |
508e53e2 | 609 | XFREE (MTYPE_OSPF6_LSA, lsa->header); |
610 | XFREE (MTYPE_OSPF6_LSA, lsa); | |
611 | } | |
718e3744 | 612 | |
508e53e2 | 613 | struct ospf6_lsa * |
614 | ospf6_lsa_copy (struct ospf6_lsa *lsa) | |
615 | { | |
616 | struct ospf6_lsa *copy = NULL; | |
617 | ||
508e53e2 | 618 | ospf6_lsa_age_current (lsa); |
6452df09 | 619 | if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) |
508e53e2 | 620 | copy = ospf6_lsa_create_headeronly (lsa->header); |
718e3744 | 621 | else |
508e53e2 | 622 | copy = ospf6_lsa_create (lsa->header); |
623 | assert (copy->lock == 0); | |
624 | ||
3b68735f | 625 | copy->birth = lsa->birth; |
508e53e2 | 626 | copy->originated = lsa->originated; |
ccb59b11 | 627 | copy->received = lsa->received; |
628 | copy->installed = lsa->installed; | |
6452df09 | 629 | copy->lsdb = lsa->lsdb; |
a765eb93 | 630 | copy->rn = NULL; |
508e53e2 | 631 | |
508e53e2 | 632 | return copy; |
718e3744 | 633 | } |
634 | ||
508e53e2 | 635 | /* increment reference counter of struct ospf6_lsa */ |
718e3744 | 636 | void |
637 | ospf6_lsa_lock (struct ospf6_lsa *lsa) | |
638 | { | |
639 | lsa->lock++; | |
640 | return; | |
641 | } | |
642 | ||
508e53e2 | 643 | /* decrement reference counter of struct ospf6_lsa */ |
718e3744 | 644 | void |
645 | ospf6_lsa_unlock (struct ospf6_lsa *lsa) | |
646 | { | |
647 | /* decrement reference counter */ | |
508e53e2 | 648 | assert (lsa->lock > 0); |
649 | lsa->lock--; | |
718e3744 | 650 | |
508e53e2 | 651 | if (lsa->lock != 0) |
652 | return; | |
653 | ||
508e53e2 | 654 | ospf6_lsa_delete (lsa); |
718e3744 | 655 | } |
656 | ||
6b0655a2 | 657 | |
508e53e2 | 658 | /* ospf6 lsa expiry */ |
718e3744 | 659 | int |
660 | ospf6_lsa_expire (struct thread *thread) | |
661 | { | |
662 | struct ospf6_lsa *lsa; | |
718e3744 | 663 | |
664 | lsa = (struct ospf6_lsa *) THREAD_ARG (thread); | |
718e3744 | 665 | |
508e53e2 | 666 | assert (lsa && lsa->header); |
667 | assert (OSPF6_LSA_IS_MAXAGE (lsa)); | |
668 | assert (! lsa->refresh); | |
718e3744 | 669 | |
670 | lsa->expire = (struct thread *) NULL; | |
671 | ||
1e05838a | 672 | if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) |
718e3744 | 673 | { |
c6487d61 | 674 | zlog_debug ("LSA Expire:"); |
508e53e2 | 675 | ospf6_lsa_header_print (lsa); |
676 | } | |
718e3744 | 677 | |
6452df09 | 678 | if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) |
508e53e2 | 679 | return 0; /* dbexchange will do something ... */ |
718e3744 | 680 | |
508e53e2 | 681 | /* reinstall lsa */ |
3b68735f | 682 | ospf6_install_lsa (lsa); |
508e53e2 | 683 | |
bf986da7 DD |
684 | /* reflood lsa */ |
685 | ospf6_flood (NULL, lsa); | |
686 | ||
508e53e2 | 687 | /* schedule maxage remover */ |
688 | ospf6_maxage_remove (ospf6); | |
718e3744 | 689 | |
690 | return 0; | |
691 | } | |
692 | ||
693 | int | |
694 | ospf6_lsa_refresh (struct thread *thread) | |
695 | { | |
6452df09 | 696 | struct ospf6_lsa *old, *self, *new; |
697 | struct ospf6_lsdb *lsdb_self; | |
718e3744 | 698 | |
699 | assert (thread); | |
6452df09 | 700 | old = (struct ospf6_lsa *) THREAD_ARG (thread); |
701 | assert (old && old->header); | |
718e3744 | 702 | |
6452df09 | 703 | old->refresh = (struct thread *) NULL; |
704 | ||
705 | lsdb_self = ospf6_get_scoped_lsdb_self (old); | |
706 | self = ospf6_lsdb_lookup (old->header->type, old->header->id, | |
707 | old->header->adv_router, lsdb_self); | |
708 | if (self == NULL) | |
709 | { | |
1e05838a | 710 | if (IS_OSPF6_DEBUG_LSA_TYPE (old->header->type)) |
c6487d61 | 711 | zlog_debug ("Refresh: could not find self LSA, flush %s", old->name); |
6452df09 | 712 | ospf6_lsa_premature_aging (old); |
713 | return 0; | |
714 | } | |
715 | ||
716 | /* Reset age, increment LS sequence number. */ | |
717 | self->header->age = htons (0); | |
718 | self->header->seqnum = | |
719 | ospf6_new_ls_seqnum (self->header->type, self->header->id, | |
720 | self->header->adv_router, old->lsdb); | |
721 | ospf6_lsa_checksum (self->header); | |
722 | ||
723 | new = ospf6_lsa_create (self->header); | |
724 | new->lsdb = old->lsdb; | |
ffa2c898 QY |
725 | new->refresh = thread_add_timer(master, ospf6_lsa_refresh, new, |
726 | OSPF_LS_REFRESH_TIME, NULL); | |
718e3744 | 727 | |
6452df09 | 728 | /* store it in the LSDB for self-originated LSAs */ |
729 | ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self); | |
718e3744 | 730 | |
1e05838a | 731 | if (IS_OSPF6_DEBUG_LSA_TYPE (new->header->type)) |
718e3744 | 732 | { |
c6487d61 | 733 | zlog_debug ("LSA Refresh:"); |
6452df09 | 734 | ospf6_lsa_header_print (new); |
718e3744 | 735 | } |
736 | ||
6452df09 | 737 | ospf6_install_lsa (new); |
bf986da7 | 738 | ospf6_flood (NULL, new); |
6452df09 | 739 | |
508e53e2 | 740 | return 0; |
718e3744 | 741 | } |
742 | ||
6b0655a2 | 743 | |
718e3744 | 744 | |
d8a4e42b | 745 | /* Fletcher Checksum -- Refer to RFC1008. */ |
718e3744 | 746 | |
d8a4e42b JR |
747 | /* All the offsets are zero-based. The offsets in the RFC1008 are |
748 | one-based. */ | |
718e3744 | 749 | unsigned short |
750 | ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) | |
751 | { | |
d8a4e42b JR |
752 | u_char *buffer = (u_char *) &lsa_header->type; |
753 | int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ | |
718e3744 | 754 | |
d8a4e42b JR |
755 | /* Skip the AGE field */ |
756 | u_int16_t len = ntohs(lsa_header->length) - type_offset; | |
718e3744 | 757 | |
d8a4e42b JR |
758 | /* Checksum offset starts from "type" field, not the beginning of the |
759 | lsa_header struct. The offset is 14, rather than 16. */ | |
760 | int checksum_offset = (u_char *) &lsa_header->checksum - buffer; | |
761 | ||
762 | return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); | |
763 | } | |
718e3744 | 764 | |
d8a4e42b JR |
765 | int |
766 | ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) | |
767 | { | |
768 | u_char *buffer = (u_char *) &lsa_header->type; | |
769 | int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ | |
718e3744 | 770 | |
d8a4e42b JR |
771 | /* Skip the AGE field */ |
772 | u_int16_t len = ntohs(lsa_header->length) - type_offset; | |
718e3744 | 773 | |
d8a4e42b | 774 | return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); |
718e3744 | 775 | } |
776 | ||
6452df09 | 777 | void |
6ac29a51 | 778 | ospf6_lsa_init (void) |
6452df09 | 779 | { |
1e05838a | 780 | ospf6_lsa_handler_vector = vector_init (0); |
6452df09 | 781 | ospf6_install_lsa_handler (&unknown_handler); |
718e3744 | 782 | } |
783 | ||
ae2254aa TG |
784 | void |
785 | ospf6_lsa_terminate (void) | |
786 | { | |
787 | vector_free (ospf6_lsa_handler_vector); | |
788 | } | |
6b0655a2 | 789 | |
6ac29a51 | 790 | static char * |
1e05838a | 791 | ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) |
792 | { | |
793 | static char buf[64]; | |
0c083ee9 | 794 | unsigned int i; |
795 | unsigned int size = strlen (h->name); | |
1e05838a | 796 | |
09df4574 | 797 | if (!strcmp(h->name, "unknown") && |
1e05838a | 798 | h->type != OSPF6_LSTYPE_UNKNOWN) |
799 | { | |
800 | snprintf (buf, sizeof (buf), "%#04hx", h->type); | |
801 | return buf; | |
802 | } | |
803 | ||
804 | for (i = 0; i < MIN (size, sizeof (buf)); i++) | |
805 | { | |
6b629fe3 DL |
806 | if (! islower ((unsigned char)h->name[i])) |
807 | buf[i] = tolower ((unsigned char)h->name[i]); | |
1e05838a | 808 | else |
809 | buf[i] = h->name[i]; | |
810 | } | |
811 | buf[size] = '\0'; | |
812 | return buf; | |
813 | } | |
718e3744 | 814 | |
1e05838a | 815 | DEFUN (debug_ospf6_lsa_type, |
816 | debug_ospf6_lsa_hex_cmd, | |
6de69f83 | 817 | "debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]", |
508e53e2 | 818 | DEBUG_STR |
819 | OSPF6_STR | |
820 | "Debug Link State Advertisements (LSAs)\n" | |
3a2d747c QY |
821 | "Display Router LSAs\n" |
822 | "Display Network LSAs\n" | |
823 | "Display Inter-Area-Prefix LSAs\n" | |
824 | "Display Inter-Router LSAs\n" | |
825 | "Display As-External LSAs\n" | |
826 | "Display Link LSAs\n" | |
827 | "Display Intra-Area-Prefix LSAs\n" | |
828 | "Display LSAs of unknown origin\n" | |
829 | "Display details of LSAs\n" | |
830 | "Dump LSAs\n" | |
831 | "Display LSA's internal information\n") | |
508e53e2 | 832 | { |
51c26414 | 833 | int idx_lsa = 3; |
1d68dbfe | 834 | int idx_type = 4; |
0c083ee9 | 835 | unsigned int i; |
1e05838a | 836 | struct ospf6_lsa_handler *handler = NULL; |
1e05838a | 837 | |
55468c86 | 838 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
718e3744 | 839 | { |
1e05838a | 840 | handler = vector_slot (ospf6_lsa_handler_vector, i); |
841 | if (handler == NULL) | |
842 | continue; | |
51c26414 | 843 | if (strncmp (argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler), strlen(argv[idx_lsa]->arg)) == 0) |
1e05838a | 844 | break; |
51c26414 | 845 | if (! strcasecmp (argv[idx_lsa]->arg, handler->name)) |
1e05838a | 846 | break; |
847 | handler = NULL; | |
508e53e2 | 848 | } |
849 | ||
1e05838a | 850 | if (handler == NULL) |
851 | handler = &unknown_handler; | |
852 | ||
1d68dbfe | 853 | if (argc == 5) |
1e05838a | 854 | { |
1d68dbfe | 855 | if (! strcmp (argv[idx_type]->text, "originate")) |
1e05838a | 856 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); |
1d68dbfe | 857 | else if (! strcmp (argv[idx_type]->text, "examine")) |
1e05838a | 858 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); |
1d68dbfe | 859 | else if (! strcmp (argv[idx_type]->text, "flooding")) |
1e05838a | 860 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); |
861 | } | |
862 | else | |
863 | SET_FLAG (handler->debug, OSPF6_LSA_DEBUG); | |
864 | ||
508e53e2 | 865 | return CMD_SUCCESS; |
866 | } | |
867 | ||
1e05838a | 868 | DEFUN (no_debug_ospf6_lsa_type, |
869 | no_debug_ospf6_lsa_hex_cmd, | |
6de69f83 | 870 | "no debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]", |
508e53e2 | 871 | NO_STR |
872 | DEBUG_STR | |
873 | OSPF6_STR | |
874 | "Debug Link State Advertisements (LSAs)\n" | |
16cedbb0 QY |
875 | "Display Router LSAs\n" |
876 | "Display Network LSAs\n" | |
877 | "Display Inter-Area-Prefix LSAs\n" | |
3a2d747c | 878 | "Display Inter-Router LSAs\n" |
16cedbb0 QY |
879 | "Display As-External LSAs\n" |
880 | "Display Link LSAs\n" | |
881 | "Display Intra-Area-Prefix LSAs\n" | |
3a2d747c | 882 | "Display LSAs of unknown origin\n" |
16cedbb0 QY |
883 | "Display details of LSAs\n" |
884 | "Dump LSAs\n" | |
885 | "Display LSA's internal information\n") | |
508e53e2 | 886 | { |
51c26414 | 887 | int idx_lsa = 4; |
1d68dbfe | 888 | int idx_type = 5; |
0c083ee9 | 889 | u_int i; |
1e05838a | 890 | struct ospf6_lsa_handler *handler = NULL; |
508e53e2 | 891 | |
55468c86 | 892 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
1e05838a | 893 | { |
894 | handler = vector_slot (ospf6_lsa_handler_vector, i); | |
895 | if (handler == NULL) | |
896 | continue; | |
51c26414 | 897 | if (strncmp (argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler), strlen(argv[idx_lsa]->arg)) == 0) |
1e05838a | 898 | break; |
51c26414 | 899 | if (! strcasecmp (argv[idx_lsa]->arg, handler->name)) |
1e05838a | 900 | break; |
901 | } | |
902 | ||
903 | if (handler == NULL) | |
904 | return CMD_SUCCESS; | |
905 | ||
1d68dbfe | 906 | if (argc == 6) |
1e05838a | 907 | { |
1d68dbfe | 908 | if (! strcmp (argv[idx_type]->text, "originate")) |
1e05838a | 909 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); |
1d68dbfe | 910 | if (! strcmp (argv[idx_type]->text, "examine")) |
1e05838a | 911 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); |
1d68dbfe | 912 | if (! strcmp (argv[idx_type]->text, "flooding")) |
1e05838a | 913 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); |
718e3744 | 914 | } |
718e3744 | 915 | else |
1e05838a | 916 | UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); |
917 | ||
508e53e2 | 918 | return CMD_SUCCESS; |
718e3744 | 919 | } |
920 | ||
718e3744 | 921 | |
1e05838a | 922 | void |
6ac29a51 | 923 | install_element_ospf6_debug_lsa (void) |
718e3744 | 924 | { |
1e05838a | 925 | install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); |
1e05838a | 926 | install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); |
1e05838a | 927 | install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); |
1e05838a | 928 | install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); |
718e3744 | 929 | } |
930 | ||
1e05838a | 931 | int |
932 | config_write_ospf6_debug_lsa (struct vty *vty) | |
718e3744 | 933 | { |
0c083ee9 | 934 | u_int i; |
1e05838a | 935 | struct ospf6_lsa_handler *handler; |
936 | ||
55468c86 | 937 | for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) |
1e05838a | 938 | { |
939 | handler = vector_slot (ospf6_lsa_handler_vector, i); | |
940 | if (handler == NULL) | |
941 | continue; | |
942 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG)) | |
943 | vty_out (vty, "debug ospf6 lsa %s%s", | |
944 | ospf6_lsa_handler_name (handler), VNL); | |
945 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE)) | |
946 | vty_out (vty, "debug ospf6 lsa %s originate%s", | |
947 | ospf6_lsa_handler_name (handler), VNL); | |
948 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN)) | |
09df4574 | 949 | vty_out (vty, "debug ospf6 lsa %s examine%s", |
1e05838a | 950 | ospf6_lsa_handler_name (handler), VNL); |
951 | if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) | |
952 | vty_out (vty, "debug ospf6 lsa %s flooding%s", | |
953 | ospf6_lsa_handler_name (handler), VNL); | |
954 | } | |
955 | ||
956 | return 0; | |
718e3744 | 957 | } |
958 | ||
718e3744 | 959 |