]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_lsa.c
Merge pull request #9053 from opensourcerouting/ospfv3-debug-guard
[mirror_frr.git] / ospf6d / ospf6_lsa.c
CommitLineData
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 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 19 */
20
21#include <zebra.h>
22
23/* Include other stuffs */
718e3744 24#include "log.h"
718e3744 25#include "linklist.h"
1e05838a 26#include "vector.h"
27#include "vty.h"
718e3744 28#include "command.h"
29#include "memory.h"
718e3744 30#include "thread.h"
d8a4e42b 31#include "checksum.h"
718e3744 32
33#include "ospf6_proto.h"
718e3744 34#include "ospf6_lsa.h"
35#include "ospf6_lsdb.h"
36#include "ospf6_message.h"
c4122b55
YR
37#include "ospf6_asbr.h"
38#include "ospf6_zebra.h"
718e3744 39
40#include "ospf6_top.h"
41#include "ospf6_area.h"
42#include "ospf6_interface.h"
43#include "ospf6_neighbor.h"
718e3744 44
508e53e2 45#include "ospf6_flood.h"
049207c3 46#include "ospf6d.h"
718e3744 47
30043e4c
DL
48DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
49DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
50DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
51
1e05838a 52vector ospf6_lsa_handler_vector;
718e3744 53
beadc736 54struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa)
55{
56 struct ospf6 *ospf6 = NULL;
57
58 switch (OSPF6_LSA_SCOPE(lsa->header->type)) {
59 case OSPF6_SCOPE_LINKLOCAL:
60 ospf6 = OSPF6_INTERFACE(lsa->lsdb->data)->area->ospf6;
61 break;
62 case OSPF6_SCOPE_AREA:
63 ospf6 = OSPF6_AREA(lsa->lsdb->data)->ospf6;
64 break;
65 case OSPF6_SCOPE_AS:
66 ospf6 = OSPF6_PROCESS(lsa->lsdb->data);
67 break;
68 default:
69 assert(0);
70 break;
71 }
72 return ospf6;
73}
74
e4bacbaa
YR
75static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
76 json_object *json_obj, bool use_json)
1e05838a 77{
d7c0a89a 78 uint8_t *start, *end, *current;
d62a17ae 79 char byte[4];
1e05838a 80
d7c0a89a
QY
81 start = (uint8_t *)lsa->header + sizeof(struct ospf6_lsa_header);
82 end = (uint8_t *)lsa->header + ntohs(lsa->header->length);
1e05838a 83
e4bacbaa
YR
84 if (use_json)
85 json_object_string_add(json_obj, "LsaType", "unknown");
86 else {
87 vty_out(vty, " Unknown contents:\n");
88 for (current = start; current < end; current++) {
89 if ((current - start) % 16 == 0)
90 vty_out(vty, "\n ");
91 else if ((current - start) % 4 == 0)
92 vty_out(vty, " ");
93
94 snprintf(byte, sizeof(byte), "%02x", *current);
95 vty_out(vty, "%s", byte);
96 }
718e3744 97
e4bacbaa 98 vty_out(vty, "\n\n");
d62a17ae 99 }
d62a17ae 100 return 0;
1e05838a 101}
102
3981b5c7
VJ
103static struct ospf6_lsa_handler unknown_handler = {
104 .lh_type = OSPF6_LSTYPE_UNKNOWN,
105 .lh_name = "Unknown",
106 .lh_short_name = "Unk",
107 .lh_show = ospf6_unknown_lsa_show,
108 .lh_get_prefix_str = NULL,
109 .lh_debug = 0 /* No default debug */
110};
1e05838a 111
4062abfa 112void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler)
1e05838a 113{
d62a17ae 114 /* type in handler is host byte order */
3981b5c7
VJ
115 int index = handler->lh_type & OSPF6_LSTYPE_FCODE_MASK;
116 vector_set_index(ospf6_lsa_handler_vector, index, (void *)handler);
1e05838a 117}
118
4062abfa 119struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type)
1e05838a 120{
4062abfa 121 struct ospf6_lsa_handler *handler = NULL;
d62a17ae 122 unsigned int index = ntohs(type) & OSPF6_LSTYPE_FCODE_MASK;
1e05838a 123
d62a17ae 124 if (index >= vector_active(ospf6_lsa_handler_vector))
125 handler = &unknown_handler;
126 else
127 handler = vector_slot(ospf6_lsa_handler_vector, index);
1e05838a 128
d62a17ae 129 if (handler == NULL)
130 handler = &unknown_handler;
2680aa2b 131
d62a17ae 132 return handler;
1e05838a 133}
718e3744 134
d7c0a89a 135const char *ospf6_lstype_name(uint16_t type)
508e53e2 136{
d62a17ae 137 static char buf[8];
3981b5c7 138 const struct ospf6_lsa_handler *handler;
508e53e2 139
d62a17ae 140 handler = ospf6_get_lsa_handler(type);
141 if (handler && handler != &unknown_handler)
3981b5c7 142 return handler->lh_name;
718e3744 143
d62a17ae 144 snprintf(buf, sizeof(buf), "0x%04hx", ntohs(type));
145 return buf;
718e3744 146}
147
d7c0a89a 148const char *ospf6_lstype_short_name(uint16_t type)
e68a6767 149{
d62a17ae 150 static char buf[8];
3981b5c7 151 const struct ospf6_lsa_handler *handler;
e68a6767 152
d62a17ae 153 handler = ospf6_get_lsa_handler(type);
3e67830c 154 if (handler)
3981b5c7 155 return handler->lh_short_name;
e68a6767 156
d62a17ae 157 snprintf(buf, sizeof(buf), "0x%04hx", ntohs(type));
158 return buf;
e68a6767
DD
159}
160
d7c0a89a 161uint8_t ospf6_lstype_debug(uint16_t type)
1e05838a 162{
3981b5c7 163 const struct ospf6_lsa_handler *handler;
d62a17ae 164 handler = ospf6_get_lsa_handler(type);
01db90cd 165 return handler->lh_debug;
1e05838a 166}
167
c4122b55
YR
168int metric_type(struct ospf6 *ospf6, int type, uint8_t instance)
169{
170 struct ospf6_redist *red;
171
172 red = ospf6_redist_lookup(ospf6, type, instance);
173
174 return ((!red || red->dmetric.type < 0) ? DEFAULT_METRIC_TYPE
175 : red->dmetric.type);
176}
177
178int metric_value(struct ospf6 *ospf6, int type, uint8_t instance)
179{
180 struct ospf6_redist *red;
181
182 red = ospf6_redist_lookup(ospf6, type, instance);
183 if (!red || red->dmetric.value < 0) {
184 if (type == DEFAULT_ROUTE) {
185 if (ospf6->default_originate == DEFAULT_ORIGINATE_ZEBRA)
186 return DEFAULT_DEFAULT_ORIGINATE_METRIC;
187 else
188 return DEFAULT_DEFAULT_ALWAYS_METRIC;
189 } else
190 return DEFAULT_DEFAULT_METRIC;
191 }
192
193 return red->dmetric.value;
194}
195
718e3744 196/* RFC2328: Section 13.2 */
d62a17ae 197int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2)
718e3744 198{
d62a17ae 199 int len;
718e3744 200
d62a17ae 201 assert(OSPF6_LSA_IS_SAME(lsa1, lsa2));
718e3744 202
d62a17ae 203 /* XXX, Options ??? */
718e3744 204
d62a17ae 205 ospf6_lsa_age_current(lsa1);
206 ospf6_lsa_age_current(lsa2);
207 if (ntohs(lsa1->header->age) == OSPF_LSA_MAXAGE
208 && ntohs(lsa2->header->age) != OSPF_LSA_MAXAGE)
209 return 1;
210 if (ntohs(lsa1->header->age) != OSPF_LSA_MAXAGE
211 && ntohs(lsa2->header->age) == OSPF_LSA_MAXAGE)
212 return 1;
718e3744 213
d62a17ae 214 /* compare body */
215 if (ntohs(lsa1->header->length) != ntohs(lsa2->header->length))
216 return 1;
718e3744 217
d62a17ae 218 len = ntohs(lsa1->header->length) - sizeof(struct ospf6_lsa_header);
219 return memcmp(lsa1->header + 1, lsa2->header + 1, len);
718e3744 220}
221
d62a17ae 222int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2)
718e3744 223{
d62a17ae 224 int length;
718e3744 225
d62a17ae 226 if (OSPF6_LSA_IS_MAXAGE(lsa1) ^ OSPF6_LSA_IS_MAXAGE(lsa2))
227 return 1;
228 if (ntohs(lsa1->header->length) != ntohs(lsa2->header->length))
229 return 1;
230 /* Going beyond LSA headers to compare the payload only makes sense,
231 * when both LSAs aren't header-only. */
232 if (CHECK_FLAG(lsa1->flag, OSPF6_LSA_HEADERONLY)
233 != CHECK_FLAG(lsa2->flag, OSPF6_LSA_HEADERONLY)) {
234 zlog_warn(
235 "%s: only one of two (%s, %s) LSAs compared is header-only",
236 __func__, lsa1->name, lsa2->name);
237 return 1;
238 }
239 if (CHECK_FLAG(lsa1->flag, OSPF6_LSA_HEADERONLY))
240 return 0;
718e3744 241
d62a17ae 242 length = OSPF6_LSA_SIZE(lsa1->header) - sizeof(struct ospf6_lsa_header);
243 /* Once upper layer verifies LSAs received, length underrun should
244 * become a warning. */
245 if (length <= 0)
246 return 0;
718e3744 247
d62a17ae 248 return memcmp(OSPF6_LSA_HEADER_END(lsa1->header),
249 OSPF6_LSA_HEADER_END(lsa2->header), length);
718e3744 250}
251
252/* ospf6 age functions */
3b68735f 253/* calculate birth */
da086a3b 254void ospf6_lsa_age_set(struct ospf6_lsa *lsa)
718e3744 255{
d62a17ae 256 struct timeval now;
718e3744 257
d62a17ae 258 assert(lsa && lsa->header);
718e3744 259
d62a17ae 260 monotime(&now);
718e3744 261
d62a17ae 262 lsa->birth.tv_sec = now.tv_sec - ntohs(lsa->header->age);
263 lsa->birth.tv_usec = now.tv_usec;
3b68735f 264
d62a17ae 265 return;
718e3744 266}
267
268/* this function calculates current age from its birth,
269 then update age field of LSA header. return value is current age */
d7c0a89a 270uint16_t ospf6_lsa_age_current(struct ospf6_lsa *lsa)
718e3744 271{
d62a17ae 272 struct timeval now;
d7c0a89a
QY
273 uint32_t ulage;
274 uint16_t age;
718e3744 275
d62a17ae 276 assert(lsa);
277 assert(lsa->header);
718e3744 278
d62a17ae 279 /* current time */
280 monotime(&now);
718e3744 281
d62a17ae 282 if (ntohs(lsa->header->age) >= OSPF_LSA_MAXAGE) {
283 /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using
284 relative time, we cannot compare against lsa birth time, so
285 we catch this special case here. */
286 lsa->header->age = htons(OSPF_LSA_MAXAGE);
287 return OSPF_LSA_MAXAGE;
288 }
289 /* calculate age */
290 ulage = now.tv_sec - lsa->birth.tv_sec;
718e3744 291
d62a17ae 292 /* if over MAXAGE, set to it */
293 age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage);
718e3744 294
d62a17ae 295 lsa->header->age = htons(age);
296 return age;
718e3744 297}
298
299/* update age field of LSA header with adding InfTransDelay */
d7c0a89a 300void ospf6_lsa_age_update_to_send(struct ospf6_lsa *lsa, uint32_t transdelay)
d62a17ae 301{
302 unsigned short age;
303
304 age = ospf6_lsa_age_current(lsa) + transdelay;
305 if (age > OSPF_LSA_MAXAGE)
306 age = OSPF_LSA_MAXAGE;
307 lsa->header->age = htons(age);
308}
309
310void ospf6_lsa_premature_aging(struct ospf6_lsa *lsa)
311{
312 /* log */
313 if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
314 zlog_debug("LSA: Premature aging: %s", lsa->name);
315
316 THREAD_OFF(lsa->expire);
317 THREAD_OFF(lsa->refresh);
318
319 /*
320 * We clear the LSA from the neighbor retx lists now because it
321 * will not get deleted later. Essentially, changing the age to
322 * MaxAge will prevent this LSA from being matched with its
323 * existing entries in the retx list thereby causing those entries
324 * to be silently replaced with its MaxAged version, but with ever
325 * increasing retx count causing this LSA to remain forever and
326 * for the MaxAge remover thread to be called forever too.
327 *
328 * The reason the previous entry silently disappears is that when
329 * entry is added to a neighbor's retx list, it replaces the existing
330 * entry. But since the ospf6_lsdb_add() routine is generic and not
331 * aware
332 * of the special semantics of retx count, the retx count is not
333 * decremented when its replaced. Attempting to add the incr and decr
334 * retx count routines as the hook_add and hook_remove for the retx
335 * lists
336 * have a problem because the hook_remove routine is called for MaxAge
337 * entries (as will be the case in a traditional LSDB, unlike in this
338 * case
339 * where an LSDB is used as an efficient tree structure to store all
340 * kinds
341 * of data) that are added instead of calling the hook_add routine.
342 */
343
344 ospf6_flood_clear(lsa);
345
346 lsa->header->age = htons(OSPF_LSA_MAXAGE);
347 thread_execute(master, ospf6_lsa_expire, lsa, 0);
718e3744 348}
349
350/* check which is more recent. if a is more recent, return -1;
351 if the same, return 0; otherwise(b is more recent), return 1 */
d62a17ae 352int ospf6_lsa_compare(struct ospf6_lsa *a, struct ospf6_lsa *b)
718e3744 353{
d62a17ae 354 int32_t seqnuma, seqnumb;
d7c0a89a
QY
355 uint16_t cksuma, cksumb;
356 uint16_t agea, ageb;
d62a17ae 357
358 assert(a && a->header);
359 assert(b && b->header);
360 assert(OSPF6_LSA_IS_SAME(a, b));
718e3744 361
d62a17ae 362 seqnuma = (int32_t)ntohl(a->header->seqnum);
363 seqnumb = (int32_t)ntohl(b->header->seqnum);
718e3744 364
d62a17ae 365 /* compare by sequence number */
366 if (seqnuma > seqnumb)
367 return -1;
368 if (seqnuma < seqnumb)
369 return 1;
370
371 /* Checksum */
372 cksuma = ntohs(a->header->checksum);
373 cksumb = ntohs(b->header->checksum);
374 if (cksuma > cksumb)
375 return -1;
376 if (cksuma < cksumb)
377 return 0;
378
379 /* Update Age */
380 agea = ospf6_lsa_age_current(a);
381 ageb = ospf6_lsa_age_current(b);
382
383 /* MaxAge check */
384 if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE)
385 return -1;
386 else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE)
387 return 1;
388
389 /* Age check */
390 if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF)
391 return 1;
392 else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF)
393 return -1;
394
395 /* neither recent */
396 return 0;
397}
398
399char *ospf6_lsa_printbuf(struct ospf6_lsa *lsa, char *buf, int size)
400{
401 char id[16], adv_router[16];
402 inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id));
403 inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,
404 sizeof(adv_router));
405 snprintf(buf, size, "[%s Id:%s Adv:%s]",
406 ospf6_lstype_name(lsa->header->type), id, adv_router);
407 return buf;
408}
409
410void ospf6_lsa_header_print_raw(struct ospf6_lsa_header *header)
411{
412 char id[16], adv_router[16];
413 inet_ntop(AF_INET, &header->id, id, sizeof(id));
414 inet_ntop(AF_INET, &header->adv_router, adv_router, sizeof(adv_router));
415 zlog_debug(" [%s Id:%s Adv:%s]", ospf6_lstype_name(header->type), id,
416 adv_router);
417 zlog_debug(" Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d",
d7c0a89a 418 ntohs(header->age), (unsigned long)ntohl(header->seqnum),
d62a17ae 419 ntohs(header->checksum), ntohs(header->length));
420}
421
422void ospf6_lsa_header_print(struct ospf6_lsa *lsa)
423{
424 ospf6_lsa_age_current(lsa);
425 ospf6_lsa_header_print_raw(lsa->header);
426}
427
428void ospf6_lsa_show_summary_header(struct vty *vty)
429{
430 vty_out(vty, "%-4s %-15s%-15s%4s %8s %30s\n", "Type", "LSId",
431 "AdvRouter", "Age", "SeqNum", "Payload");
432}
433
e4bacbaa
YR
434void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa,
435 json_object *json_array, bool use_json)
d62a17ae 436{
437 char adv_router[16], id[16];
438 int type;
3981b5c7 439 const struct ospf6_lsa_handler *handler;
e4bacbaa 440 char buf[64];
d62a17ae 441 int cnt = 0;
e4bacbaa 442 json_object *json_obj = NULL;
d62a17ae 443
444 assert(lsa);
445 assert(lsa->header);
446
447 inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id));
448 inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,
449 sizeof(adv_router));
450
451 type = ntohs(lsa->header->type);
452 handler = ospf6_get_lsa_handler(lsa->header->type);
e4bacbaa
YR
453
454 if (use_json)
455 json_obj = json_object_new_object();
456
3e67830c 457 switch (type) {
458 case OSPF6_LSTYPE_INTER_PREFIX:
459 case OSPF6_LSTYPE_INTER_ROUTER:
460 case OSPF6_LSTYPE_AS_EXTERNAL:
ad500b22 461 case OSPF6_LSTYPE_TYPE_7:
e4bacbaa
YR
462 if (use_json) {
463 json_object_string_add(
464 json_obj, "type",
465 ospf6_lstype_short_name(lsa->header->type));
466 json_object_string_add(json_obj, "lsId", id);
467 json_object_string_add(json_obj, "advRouter",
468 adv_router);
469 json_object_int_add(json_obj, "age",
470 ospf6_lsa_age_current(lsa));
471 json_object_int_add(
472 json_obj, "seqNum",
473 (unsigned long)ntohl(lsa->header->seqnum));
474 json_object_string_add(
475 json_obj, "payload",
476 handler->lh_get_prefix_str(lsa, buf,
477 sizeof(buf), 0));
478 json_object_array_add(json_array, json_obj);
479 } else
480 vty_out(vty, "%-4s %-15s%-15s%4hu %8lx %30s\n",
481 ospf6_lstype_short_name(lsa->header->type), id,
482 adv_router, ospf6_lsa_age_current(lsa),
483 (unsigned long)ntohl(lsa->header->seqnum),
484 handler->lh_get_prefix_str(lsa, buf,
485 sizeof(buf), 0));
3e67830c 486 break;
487 case OSPF6_LSTYPE_ROUTER:
488 case OSPF6_LSTYPE_NETWORK:
489 case OSPF6_LSTYPE_GROUP_MEMBERSHIP:
3e67830c 490 case OSPF6_LSTYPE_LINK:
491 case OSPF6_LSTYPE_INTRA_PREFIX:
3981b5c7 492 while (handler->lh_get_prefix_str(lsa, buf, sizeof(buf), cnt)
d62a17ae 493 != NULL) {
e4bacbaa
YR
494 if (use_json) {
495 json_object_string_add(
496 json_obj, "type",
497 ospf6_lstype_short_name(
498 lsa->header->type));
499 json_object_string_add(json_obj, "lsId", id);
500 json_object_string_add(json_obj, "advRouter",
501 adv_router);
502 json_object_int_add(json_obj, "age",
503 ospf6_lsa_age_current(lsa));
504 json_object_int_add(
505 json_obj, "seqNum",
506 (unsigned long)ntohl(
507 lsa->header->seqnum));
508 json_object_string_add(json_obj, "payload",
509 buf);
510 json_object_array_add(json_array, json_obj);
511 json_obj = json_object_new_object();
512 } else
513 vty_out(vty, "%-4s %-15s%-15s%4hu %8lx %30s\n",
514 ospf6_lstype_short_name(
515 lsa->header->type),
516 id, adv_router,
517 ospf6_lsa_age_current(lsa),
518 (unsigned long)ntohl(
519 lsa->header->seqnum),
520 buf);
d62a17ae 521 cnt++;
522 }
e4bacbaa
YR
523 if (use_json)
524 json_object_free(json_obj);
3e67830c 525 break;
526 default:
e4bacbaa
YR
527 if (use_json) {
528 json_object_string_add(
529 json_obj, "type",
530 ospf6_lstype_short_name(lsa->header->type));
531 json_object_string_add(json_obj, "lsId", id);
532 json_object_string_add(json_obj, "advRouter",
533 adv_router);
534 json_object_int_add(json_obj, "age",
535 ospf6_lsa_age_current(lsa));
536 json_object_int_add(
537 json_obj, "seqNum",
538 (unsigned long)ntohl(lsa->header->seqnum));
539 json_object_array_add(json_array, json_obj);
540 } else
541 vty_out(vty, "%-4s %-15s%-15s%4hu %8lx\n",
542 ospf6_lstype_short_name(lsa->header->type), id,
543 adv_router, ospf6_lsa_age_current(lsa),
544 (unsigned long)ntohl(lsa->header->seqnum));
3e67830c 545 break;
e68a6767 546 }
d62a17ae 547}
548
e4bacbaa
YR
549void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa,
550 json_object *json_array, bool use_json)
d62a17ae 551{
d7c0a89a 552 uint8_t *start, *end, *current;
d62a17ae 553 char byte[4];
554
d7c0a89a
QY
555 start = (uint8_t *)lsa->header;
556 end = (uint8_t *)lsa->header + ntohs(lsa->header->length);
d62a17ae 557
e4bacbaa
YR
558 if (use_json)
559 return;
560
d62a17ae 561 vty_out(vty, "\n");
562 vty_out(vty, "%s:\n", lsa->name);
563
564 for (current = start; current < end; current++) {
565 if ((current - start) % 16 == 0)
566 vty_out(vty, "\n ");
567 else if ((current - start) % 4 == 0)
568 vty_out(vty, " ");
569
570 snprintf(byte, sizeof(byte), "%02x", *current);
571 vty_out(vty, "%s", byte);
572 }
573
574 vty_out(vty, "\n\n");
e4bacbaa 575
d62a17ae 576 return;
577}
578
e4bacbaa
YR
579void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa,
580 json_object *json_array, bool use_json)
d62a17ae 581{
582 char adv_router[64], id[64];
e4bacbaa 583 json_object *json_obj;
d62a17ae 584
585 assert(lsa && lsa->header);
586
587 inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id));
588 inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,
589 sizeof(adv_router));
590
e4bacbaa
YR
591 if (use_json) {
592 json_obj = json_object_new_object();
593 json_object_int_add(json_obj, "age",
594 ospf6_lsa_age_current(lsa));
595 json_object_string_add(json_obj, "type",
596 ospf6_lstype_name(lsa->header->type));
597 json_object_string_add(json_obj, "linkStateId", id);
598 json_object_string_add(json_obj, "advertisingRouter",
599 adv_router);
600 json_object_int_add(json_obj, "lsSequenceNumber",
601 (unsigned long)ntohl(lsa->header->seqnum));
602 json_object_int_add(json_obj, "checksum",
603 ntohs(lsa->header->checksum));
604 json_object_int_add(json_obj, "length",
605 ntohs(lsa->header->length));
606 json_object_int_add(json_obj, "flag", lsa->flag);
607 json_object_int_add(json_obj, "lock", lsa->lock);
608 json_object_int_add(json_obj, "reTxCount", lsa->retrans_count);
609
610 /* Threads Data not added */
611 json_object_array_add(json_array, json_obj);
612 } else {
613 vty_out(vty, "\n");
614 vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa),
615 ospf6_lstype_name(lsa->header->type));
616 vty_out(vty, "Link State ID: %s\n", id);
617 vty_out(vty, "Advertising Router: %s\n", adv_router);
618 vty_out(vty, "LS Sequence Number: %#010lx\n",
619 (unsigned long)ntohl(lsa->header->seqnum));
620 vty_out(vty, "CheckSum: %#06hx Length: %hu\n",
621 ntohs(lsa->header->checksum),
622 ntohs(lsa->header->length));
623 vty_out(vty, "Flag: %x \n", lsa->flag);
624 vty_out(vty, "Lock: %d \n", lsa->lock);
625 vty_out(vty, "ReTx Count: %d\n", lsa->retrans_count);
461d106d
RW
626 vty_out(vty, "Threads: Expire: %p, Refresh: %p\n", lsa->expire,
627 lsa->refresh);
e4bacbaa
YR
628 vty_out(vty, "\n");
629 }
d62a17ae 630 return;
631}
632
e4bacbaa
YR
633void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
634 json_object *json_array, bool use_json)
d62a17ae 635{
636 char adv_router[64], id[64];
3981b5c7 637 const struct ospf6_lsa_handler *handler;
d62a17ae 638 struct timeval now, res;
68bfcc05 639 char duration[64];
e4bacbaa 640 json_object *json_obj = NULL;
d62a17ae 641
642 assert(lsa && lsa->header);
643
644 inet_ntop(AF_INET, &lsa->header->id, id, sizeof(id));
645 inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,
646 sizeof(adv_router));
647
648 monotime(&now);
649 timersub(&now, &lsa->installed, &res);
650 timerstring(&res, duration, sizeof(duration));
e4bacbaa
YR
651 if (use_json) {
652 json_obj = json_object_new_object();
653 json_object_int_add(json_obj, "age",
654 ospf6_lsa_age_current(lsa));
655 json_object_string_add(json_obj, "type",
656 ospf6_lstype_name(lsa->header->type));
2804f2d2 657 json_object_string_add(json_obj, "linkStateId", id);
e4bacbaa
YR
658 json_object_string_add(json_obj, "advertisingRouter",
659 adv_router);
660 json_object_int_add(json_obj, "lsSequenceNumber",
661 (unsigned long)ntohl(lsa->header->seqnum));
d6265808 662 json_object_int_add(json_obj, "checksum",
e4bacbaa
YR
663 ntohs(lsa->header->checksum));
664 json_object_int_add(json_obj, "length",
665 ntohs(lsa->header->length));
666 json_object_string_add(json_obj, "duration", duration);
667 } else {
668 vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa),
669 ospf6_lstype_name(lsa->header->type));
670 vty_out(vty, "Link State ID: %s\n", id);
671 vty_out(vty, "Advertising Router: %s\n", adv_router);
672 vty_out(vty, "LS Sequence Number: %#010lx\n",
673 (unsigned long)ntohl(lsa->header->seqnum));
674 vty_out(vty, "CheckSum: %#06hx Length: %hu\n",
675 ntohs(lsa->header->checksum),
676 ntohs(lsa->header->length));
677 vty_out(vty, "Duration: %s\n", duration);
678 }
d62a17ae 679
680 handler = ospf6_get_lsa_handler(lsa->header->type);
3981b5c7
VJ
681
682 if (handler->lh_show != NULL)
e4bacbaa 683 handler->lh_show(vty, lsa, json_obj, use_json);
3981b5c7
VJ
684 else {
685 assert(unknown_handler.lh_show != NULL);
e4bacbaa 686 unknown_handler.lh_show(vty, lsa, json_obj, use_json);
3981b5c7 687 }
d62a17ae 688
e4bacbaa
YR
689 if (use_json)
690 json_object_array_add(json_array, json_obj);
691 else
692 vty_out(vty, "\n");
6452df09 693}
694
771e1fbe
DL
695struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length)
696{
30043e4c
DL
697 struct ospf6_lsa *lsa;
698
771e1fbe
DL
699 lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
700 lsa->header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_length);
701
702 return lsa;
703}
704
6452df09 705/* OSPFv3 LSA creation/deletion function */
d62a17ae 706struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header)
718e3744 707{
d62a17ae 708 struct ospf6_lsa *lsa = NULL;
d7c0a89a 709 uint16_t lsa_size = 0;
718e3744 710
d62a17ae 711 /* size of the entire LSA */
712 lsa_size = ntohs(header->length); /* XXX vulnerable */
718e3744 713
771e1fbe 714 lsa = ospf6_lsa_alloc(lsa_size);
718e3744 715
d62a17ae 716 /* copy LSA from original header */
771e1fbe 717 memcpy(lsa->header, header, lsa_size);
718e3744 718
d62a17ae 719 /* dump string */
720 ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
718e3744 721
d62a17ae 722 /* calculate birth of this lsa */
723 ospf6_lsa_age_set(lsa);
718e3744 724
d62a17ae 725 return lsa;
718e3744 726}
727
d62a17ae 728struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header)
718e3744 729{
d62a17ae 730 struct ospf6_lsa *lsa = NULL;
718e3744 731
771e1fbe 732 lsa = ospf6_lsa_alloc(sizeof(struct ospf6_lsa_header));
718e3744 733
771e1fbe 734 memcpy(lsa->header, header, sizeof(struct ospf6_lsa_header));
718e3744 735
d62a17ae 736 SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY);
718e3744 737
d62a17ae 738 /* dump string */
739 ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
718e3744 740
d62a17ae 741 /* calculate birth of this lsa */
742 ospf6_lsa_age_set(lsa);
718e3744 743
d62a17ae 744 return lsa;
718e3744 745}
746
d62a17ae 747void ospf6_lsa_delete(struct ospf6_lsa *lsa)
718e3744 748{
d62a17ae 749 assert(lsa->lock == 0);
718e3744 750
d62a17ae 751 /* cancel threads */
752 THREAD_OFF(lsa->expire);
753 THREAD_OFF(lsa->refresh);
718e3744 754
d62a17ae 755 /* do free */
d107621d 756 XFREE(MTYPE_OSPF6_LSA_HEADER, lsa->header);
d62a17ae 757 XFREE(MTYPE_OSPF6_LSA, lsa);
508e53e2 758}
718e3744 759
d62a17ae 760struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa)
508e53e2 761{
d62a17ae 762 struct ospf6_lsa *copy = NULL;
508e53e2 763
d62a17ae 764 ospf6_lsa_age_current(lsa);
765 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY))
766 copy = ospf6_lsa_create_headeronly(lsa->header);
767 else
768 copy = ospf6_lsa_create(lsa->header);
769 assert(copy->lock == 0);
508e53e2 770
d62a17ae 771 copy->birth = lsa->birth;
772 copy->originated = lsa->originated;
773 copy->received = lsa->received;
774 copy->installed = lsa->installed;
775 copy->lsdb = lsa->lsdb;
776 copy->rn = NULL;
508e53e2 777
d62a17ae 778 return copy;
718e3744 779}
780
508e53e2 781/* increment reference counter of struct ospf6_lsa */
62270cc3 782struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa)
718e3744 783{
d62a17ae 784 lsa->lock++;
62270cc3 785 return lsa;
718e3744 786}
787
508e53e2 788/* decrement reference counter of struct ospf6_lsa */
744ba569 789struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa)
718e3744 790{
d62a17ae 791 /* decrement reference counter */
792 assert(lsa->lock > 0);
793 lsa->lock--;
718e3744 794
d62a17ae 795 if (lsa->lock != 0)
744ba569 796 return lsa;
508e53e2 797
d62a17ae 798 ospf6_lsa_delete(lsa);
744ba569 799 return NULL;
718e3744 800}
801
6b0655a2 802
508e53e2 803/* ospf6 lsa expiry */
d62a17ae 804int ospf6_lsa_expire(struct thread *thread)
718e3744 805{
d62a17ae 806 struct ospf6_lsa *lsa;
beadc736 807 struct ospf6 *ospf6;
718e3744 808
d62a17ae 809 lsa = (struct ospf6_lsa *)THREAD_ARG(thread);
718e3744 810
d62a17ae 811 assert(lsa && lsa->header);
812 assert(OSPF6_LSA_IS_MAXAGE(lsa));
813 assert(!lsa->refresh);
718e3744 814
d62a17ae 815 lsa->expire = (struct thread *)NULL;
718e3744 816
d62a17ae 817 if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)) {
818 zlog_debug("LSA Expire:");
819 ospf6_lsa_header_print(lsa);
820 }
718e3744 821
d62a17ae 822 if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY))
823 return 0; /* dbexchange will do something ... */
beadc736 824 ospf6 = ospf6_get_by_lsdb(lsa);
d62a17ae 825 /* reinstall lsa */
826 ospf6_install_lsa(lsa);
508e53e2 827
d62a17ae 828 /* reflood lsa */
829 ospf6_flood(NULL, lsa);
bf986da7 830
d62a17ae 831 /* schedule maxage remover */
832 ospf6_maxage_remove(ospf6);
718e3744 833
d62a17ae 834 return 0;
718e3744 835}
836
d62a17ae 837int ospf6_lsa_refresh(struct thread *thread)
718e3744 838{
d62a17ae 839 struct ospf6_lsa *old, *self, *new;
840 struct ospf6_lsdb *lsdb_self;
6452df09 841
d62a17ae 842 old = (struct ospf6_lsa *)THREAD_ARG(thread);
843 assert(old && old->header);
6452df09 844
d62a17ae 845 old->refresh = (struct thread *)NULL;
6452df09 846
d62a17ae 847 lsdb_self = ospf6_get_scoped_lsdb_self(old);
848 self = ospf6_lsdb_lookup(old->header->type, old->header->id,
849 old->header->adv_router, lsdb_self);
850 if (self == NULL) {
851 if (IS_OSPF6_DEBUG_LSA_TYPE(old->header->type))
852 zlog_debug("Refresh: could not find self LSA, flush %s",
853 old->name);
854 ospf6_lsa_premature_aging(old);
855 return 0;
856 }
718e3744 857
d62a17ae 858 /* Reset age, increment LS sequence number. */
859 self->header->age = htons(0);
860 self->header->seqnum =
861 ospf6_new_ls_seqnum(self->header->type, self->header->id,
862 self->header->adv_router, old->lsdb);
863 ospf6_lsa_checksum(self->header);
864
865 new = ospf6_lsa_create(self->header);
866 new->lsdb = old->lsdb;
867 new->refresh = NULL;
868 thread_add_timer(master, ospf6_lsa_refresh, new, OSPF_LS_REFRESH_TIME,
869 &new->refresh);
870
871 /* store it in the LSDB for self-originated LSAs */
872 ospf6_lsdb_add(ospf6_lsa_copy(new), lsdb_self);
873
874 if (IS_OSPF6_DEBUG_LSA_TYPE(new->header->type)) {
875 zlog_debug("LSA Refresh:");
876 ospf6_lsa_header_print(new);
877 }
718e3744 878
d62a17ae 879 ospf6_install_lsa(new);
880 ospf6_flood(NULL, new);
6452df09 881
d62a17ae 882 return 0;
718e3744 883}
884
beadc736 885void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6)
76249532 886{
e161c2dc 887 struct listnode *node, *nnode;
76249532
CS
888 struct ospf6_area *oa;
889 struct ospf6_lsa *lsa;
890 const struct route_node *end = NULL;
891 uint32_t type, adv_router;
e161c2dc 892 struct ospf6_interface *oi;
76249532
CS
893
894 ospf6->inst_shutdown = 1;
895
896 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
996c9314
LB
897 end = ospf6_lsdb_head(oa->lsdb_self, 0, 0, ospf6->router_id,
898 &lsa);
76249532
CS
899 while (lsa) {
900 /* RFC 2328 (14.1): Set MAXAGE */
901 lsa->header->age = htons(OSPF_LSA_MAXAGE);
902 /* Flood MAXAGE LSA*/
903 ospf6_flood(NULL, lsa);
904
905 lsa = ospf6_lsdb_next(end, lsa);
906 }
e161c2dc
YR
907
908 for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
909 end = ospf6_lsdb_head(oi->lsdb_self, 0, 0,
910 ospf6->router_id, &lsa);
911 while (lsa) {
912 /* RFC 2328 (14.1): Set MAXAGE */
913 lsa->header->age = htons(OSPF_LSA_MAXAGE);
914 /* Flood MAXAGE LSA*/
915 ospf6_flood(NULL, lsa);
916
917 lsa = ospf6_lsdb_next(end, lsa);
918 }
919 }
76249532
CS
920 }
921
922 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
923 adv_router = ospf6->router_id;
924 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
925 /* RFC 2328 (14.1): Set MAXAGE */
926 lsa->header->age = htons(OSPF_LSA_MAXAGE);
927 ospf6_flood(NULL, lsa);
928 }
929}
6b0655a2 930
d8a4e42b 931/* Fletcher Checksum -- Refer to RFC1008. */
718e3744 932
d8a4e42b
JR
933/* All the offsets are zero-based. The offsets in the RFC1008 are
934 one-based. */
d62a17ae 935unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *lsa_header)
718e3744 936{
d7c0a89a
QY
937 uint8_t *buffer = (uint8_t *)&lsa_header->type;
938 int type_offset =
939 buffer - (uint8_t *)&lsa_header->age; /* should be 2 */
718e3744 940
d62a17ae 941 /* Skip the AGE field */
d7c0a89a 942 uint16_t len = ntohs(lsa_header->length) - type_offset;
718e3744 943
d62a17ae 944 /* Checksum offset starts from "type" field, not the beginning of the
945 lsa_header struct. The offset is 14, rather than 16. */
d7c0a89a 946 int checksum_offset = (uint8_t *)&lsa_header->checksum - buffer;
d8a4e42b 947
d62a17ae 948 return (unsigned short)fletcher_checksum(buffer, len, checksum_offset);
d8a4e42b 949}
718e3744 950
d62a17ae 951int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsa_header)
d8a4e42b 952{
d7c0a89a
QY
953 uint8_t *buffer = (uint8_t *)&lsa_header->type;
954 int type_offset =
955 buffer - (uint8_t *)&lsa_header->age; /* should be 2 */
718e3744 956
d62a17ae 957 /* Skip the AGE field */
d7c0a89a 958 uint16_t len = ntohs(lsa_header->length) - type_offset;
718e3744 959
d62a17ae 960 return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE)
961 == 0);
718e3744 962}
963
d62a17ae 964void ospf6_lsa_init(void)
6452df09 965{
d62a17ae 966 ospf6_lsa_handler_vector = vector_init(0);
967 ospf6_install_lsa_handler(&unknown_handler);
718e3744 968}
969
d62a17ae 970void ospf6_lsa_terminate(void)
ae2254aa 971{
d62a17ae 972 vector_free(ospf6_lsa_handler_vector);
ae2254aa 973}
6b0655a2 974
3981b5c7 975static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h)
1e05838a 976{
d62a17ae 977 static char buf[64];
978 unsigned int i;
3981b5c7 979 unsigned int size = strlen(h->lh_name);
1e05838a 980
996c9314
LB
981 if (!strcmp(h->lh_name, "unknown")
982 && h->lh_type != OSPF6_LSTYPE_UNKNOWN) {
3981b5c7 983 snprintf(buf, sizeof(buf), "%#04hx", h->lh_type);
d62a17ae 984 return buf;
985 }
1e05838a 986
d62a17ae 987 for (i = 0; i < MIN(size, sizeof(buf)); i++) {
3981b5c7
VJ
988 if (!islower((unsigned char)h->lh_name[i]))
989 buf[i] = tolower((unsigned char)h->lh_name[i]);
d62a17ae 990 else
3981b5c7 991 buf[i] = h->lh_name[i];
d62a17ae 992 }
993 buf[size] = '\0';
994 return buf;
1e05838a 995}
718e3744 996
1e05838a 997DEFUN (debug_ospf6_lsa_type,
998 debug_ospf6_lsa_hex_cmd,
6de69f83 999 "debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]",
508e53e2 1000 DEBUG_STR
1001 OSPF6_STR
1002 "Debug Link State Advertisements (LSAs)\n"
3a2d747c
QY
1003 "Display Router LSAs\n"
1004 "Display Network LSAs\n"
1005 "Display Inter-Area-Prefix LSAs\n"
1006 "Display Inter-Router LSAs\n"
1007 "Display As-External LSAs\n"
1008 "Display Link LSAs\n"
1009 "Display Intra-Area-Prefix LSAs\n"
1010 "Display LSAs of unknown origin\n"
1011 "Display details of LSAs\n"
1012 "Dump LSAs\n"
1013 "Display LSA's internal information\n")
508e53e2 1014{
d62a17ae 1015 int idx_lsa = 3;
1016 int idx_type = 4;
1017 unsigned int i;
1018 struct ospf6_lsa_handler *handler = NULL;
1019
1020 for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
1021 handler = vector_slot(ospf6_lsa_handler_vector, i);
1022 if (handler == NULL)
1023 continue;
1024 if (strncmp(argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler),
1025 strlen(argv[idx_lsa]->arg))
1026 == 0)
1027 break;
3981b5c7 1028 if (!strcasecmp(argv[idx_lsa]->arg, handler->lh_name))
d62a17ae 1029 break;
1030 handler = NULL;
1031 }
1032
1033 if (handler == NULL)
1034 handler = &unknown_handler;
1035
1036 if (argc == 5) {
1037 if (strmatch(argv[idx_type]->text, "originate"))
01db90cd 1038 SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ORIGINATE);
d62a17ae 1039 else if (strmatch(argv[idx_type]->text, "examine"))
01db90cd 1040 SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_EXAMIN);
d62a17ae 1041 else if (strmatch(argv[idx_type]->text, "flooding"))
01db90cd 1042 SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD);
d62a17ae 1043 } else
01db90cd 1044 SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG);
d62a17ae 1045
1046 return CMD_SUCCESS;
508e53e2 1047}
1048
1e05838a 1049DEFUN (no_debug_ospf6_lsa_type,
1050 no_debug_ospf6_lsa_hex_cmd,
6de69f83 1051 "no debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]",
508e53e2 1052 NO_STR
1053 DEBUG_STR
1054 OSPF6_STR
1055 "Debug Link State Advertisements (LSAs)\n"
16cedbb0
QY
1056 "Display Router LSAs\n"
1057 "Display Network LSAs\n"
1058 "Display Inter-Area-Prefix LSAs\n"
3a2d747c 1059 "Display Inter-Router LSAs\n"
16cedbb0
QY
1060 "Display As-External LSAs\n"
1061 "Display Link LSAs\n"
1062 "Display Intra-Area-Prefix LSAs\n"
3a2d747c 1063 "Display LSAs of unknown origin\n"
16cedbb0
QY
1064 "Display details of LSAs\n"
1065 "Dump LSAs\n"
1066 "Display LSA's internal information\n")
508e53e2 1067{
d62a17ae 1068 int idx_lsa = 4;
1069 int idx_type = 5;
d7c0a89a 1070 unsigned int i;
d62a17ae 1071 struct ospf6_lsa_handler *handler = NULL;
1072
1073 for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
1074 handler = vector_slot(ospf6_lsa_handler_vector, i);
1075 if (handler == NULL)
1076 continue;
1077 if (strncmp(argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler),
1078 strlen(argv[idx_lsa]->arg))
1079 == 0)
1080 break;
3981b5c7 1081 if (!strcasecmp(argv[idx_lsa]->arg, handler->lh_name))
d62a17ae 1082 break;
1083 }
718e3744 1084
d62a17ae 1085 if (handler == NULL)
1086 return CMD_SUCCESS;
1087
1088 if (argc == 6) {
1089 if (strmatch(argv[idx_type]->text, "originate"))
01db90cd
DL
1090 UNSET_FLAG(handler->lh_debug,
1091 OSPF6_LSA_DEBUG_ORIGINATE);
d62a17ae 1092 if (strmatch(argv[idx_type]->text, "examine"))
01db90cd 1093 UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_EXAMIN);
d62a17ae 1094 if (strmatch(argv[idx_type]->text, "flooding"))
01db90cd 1095 UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD);
d62a17ae 1096 } else
01db90cd 1097 UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG);
d62a17ae 1098
1099 return CMD_SUCCESS;
1100}
1101
1102void install_element_ospf6_debug_lsa(void)
1103{
1104 install_element(ENABLE_NODE, &debug_ospf6_lsa_hex_cmd);
1105 install_element(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
1106 install_element(CONFIG_NODE, &debug_ospf6_lsa_hex_cmd);
1107 install_element(CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd);
1108}
1109
1110int config_write_ospf6_debug_lsa(struct vty *vty)
1111{
d7c0a89a 1112 unsigned int i;
3981b5c7 1113 const struct ospf6_lsa_handler *handler;
d62a17ae 1114
1115 for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
1116 handler = vector_slot(ospf6_lsa_handler_vector, i);
1117 if (handler == NULL)
1118 continue;
01db90cd 1119 if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG))
d62a17ae 1120 vty_out(vty, "debug ospf6 lsa %s\n",
1121 ospf6_lsa_handler_name(handler));
01db90cd 1122 if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ORIGINATE))
d62a17ae 1123 vty_out(vty, "debug ospf6 lsa %s originate\n",
1124 ospf6_lsa_handler_name(handler));
01db90cd 1125 if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_EXAMIN))
d62a17ae 1126 vty_out(vty, "debug ospf6 lsa %s examine\n",
1127 ospf6_lsa_handler_name(handler));
01db90cd 1128 if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD))
d62a17ae 1129 vty_out(vty, "debug ospf6 lsa %s flooding\n",
1130 ospf6_lsa_handler_name(handler));
1131 }
718e3744 1132
d62a17ae 1133 return 0;
1134}