]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_route.c
ospfd: Do not auto-debug DR-Election notifications
[mirror_frr.git] / ospf6d / ospf6_route.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
508e53e2 21#include <zebra.h>
22
23#include "log.h"
24#include "memory.h"
25#include "prefix.h"
26#include "table.h"
27#include "vty.h"
28#include "command.h"
cf1ce250 29#include "linklist.h"
508e53e2 30
508e53e2 31#include "ospf6_proto.h"
32#include "ospf6_lsa.h"
049207c3 33#include "ospf6_lsdb.h"
508e53e2 34#include "ospf6_route.h"
cf1ce250
PJ
35#include "ospf6_top.h"
36#include "ospf6_area.h"
37#include "ospf6_interface.h"
049207c3 38#include "ospf6d.h"
c3c0ac83 39#include "ospf6_zebra.h"
d5cb3508 40#include "ospf6d/ospf6_route_clippy.c"
718e3744 41
30043e4c 42DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE, "OSPF6 route");
de4a0bda 43DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE_TABLE, "OSPF6 route table");
30043e4c
DL
44DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop");
45DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PATH, "OSPF6 Path");
46
508e53e2 47unsigned char conf_debug_ospf6_route = 0;
718e3744 48
d62a17ae 49static char *ospf6_route_table_name(struct ospf6_route_table *table)
cf1ce250 50{
d62a17ae 51 static char name[64];
52 switch (table->scope_type) {
53 case OSPF6_SCOPE_TYPE_GLOBAL: {
54 switch (table->table_type) {
55 case OSPF6_TABLE_TYPE_ROUTES:
56 snprintf(name, sizeof(name), "global route table");
57 break;
58 case OSPF6_TABLE_TYPE_BORDER_ROUTERS:
59 snprintf(name, sizeof(name), "global brouter table");
60 break;
61 case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES:
62 snprintf(name, sizeof(name), "global external table");
63 break;
64 default:
65 snprintf(name, sizeof(name), "global unknown table");
66 break;
67 }
68 } break;
69
70 case OSPF6_SCOPE_TYPE_AREA: {
71 struct ospf6_area *oa = (struct ospf6_area *)table->scope;
72 switch (table->table_type) {
73 case OSPF6_TABLE_TYPE_SPF_RESULTS:
74 snprintf(name, sizeof(name), "area %s spf table",
75 oa->name);
76 break;
77 case OSPF6_TABLE_TYPE_ROUTES:
78 snprintf(name, sizeof(name), "area %s route table",
79 oa->name);
80 break;
81 case OSPF6_TABLE_TYPE_PREFIX_RANGES:
82 snprintf(name, sizeof(name), "area %s range table",
83 oa->name);
84 break;
85 case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES:
86 snprintf(name, sizeof(name),
87 "area %s summary prefix table", oa->name);
88 break;
89 case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS:
90 snprintf(name, sizeof(name),
91 "area %s summary router table", oa->name);
92 break;
93 default:
94 snprintf(name, sizeof(name), "area %s unknown table",
95 oa->name);
96 break;
97 }
98 } break;
99
100 case OSPF6_SCOPE_TYPE_INTERFACE: {
101 struct ospf6_interface *oi =
102 (struct ospf6_interface *)table->scope;
103 switch (table->table_type) {
104 case OSPF6_TABLE_TYPE_CONNECTED_ROUTES:
105 snprintf(name, sizeof(name),
106 "interface %s connected table",
107 oi->interface->name);
108 break;
109 default:
110 snprintf(name, sizeof(name),
111 "interface %s unknown table",
112 oi->interface->name);
113 break;
114 }
115 } break;
116
117 default: {
118 switch (table->table_type) {
119 case OSPF6_TABLE_TYPE_SPF_RESULTS:
120 snprintf(name, sizeof(name), "temporary spf table");
121 break;
122 default:
123 snprintf(name, sizeof(name), "temporary unknown table");
124 break;
125 }
126 } break;
127 }
128 return name;
cf1ce250
PJ
129}
130
d7c0a89a 131void ospf6_linkstate_prefix(uint32_t adv_router, uint32_t id,
d62a17ae 132 struct prefix *prefix)
508e53e2 133{
d62a17ae 134 memset(prefix, 0, sizeof(struct prefix));
135 prefix->family = AF_INET6;
136 prefix->prefixlen = 64;
137 memcpy(&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
138 memcpy(&prefix->u.prefix6.s6_addr[4], &id, 4);
508e53e2 139}
718e3744 140
d62a17ae 141void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, int size)
718e3744 142{
d7c0a89a 143 uint32_t adv_router, id;
d62a17ae 144 char adv_router_str[16], id_str[16];
145 memcpy(&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
146 memcpy(&id, &prefix->u.prefix6.s6_addr[4], 4);
147 inet_ntop(AF_INET, &adv_router, adv_router_str, sizeof(adv_router_str));
148 inet_ntop(AF_INET, &id, id_str, sizeof(id_str));
149 if (ntohl(id))
150 snprintf(buf, size, "%s Net-ID: %s", adv_router_str, id_str);
151 else
152 snprintf(buf, size, "%s", adv_router_str);
508e53e2 153}
718e3744 154
508e53e2 155/* Global strings for logging */
2b64873d 156const char *const ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = {
d62a17ae 157 "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange",
158};
718e3744 159
2b64873d 160const char *const ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = {
d62a17ae 161 "?", "R", "N", "D", "L", "A",
162};
718e3744 163
2b64873d 164const char *const ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = {
d62a17ae 165 "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2",
166};
718e3744 167
2b64873d 168const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = {
d62a17ae 169 "??", "IA", "IE", "E1", "E2",
170};
718e3744 171
eacd0828
YR
172const char *ospf6_path_type_json[OSPF6_PATH_TYPE_MAX] = {
173 "UnknownRoute", "IntraArea", "InterArea", "External1", "External2",
174};
175
718e3744 176
d62a17ae 177struct ospf6_nexthop *ospf6_nexthop_create(void)
c3c0ac83 178{
d62a17ae 179 struct ospf6_nexthop *nh;
c3c0ac83 180
d62a17ae 181 nh = XCALLOC(MTYPE_OSPF6_NEXTHOP, sizeof(struct ospf6_nexthop));
182 return nh;
c3c0ac83
DS
183}
184
d62a17ae 185void ospf6_nexthop_delete(struct ospf6_nexthop *nh)
c3c0ac83 186{
0a22ddfb 187 XFREE(MTYPE_OSPF6_NEXTHOP, nh);
c3c0ac83
DS
188}
189
d62a17ae 190void ospf6_clear_nexthops(struct list *nh_list)
c3c0ac83 191{
d62a17ae 192 struct listnode *node;
193 struct ospf6_nexthop *nh;
194
195 if (nh_list) {
196 for (ALL_LIST_ELEMENTS_RO(nh_list, node, nh))
197 ospf6_nexthop_clear(nh);
198 }
c3c0ac83
DS
199}
200
201static struct ospf6_nexthop *
d62a17ae 202ospf6_route_find_nexthop(struct list *nh_list, struct ospf6_nexthop *nh_match)
c3c0ac83 203{
d62a17ae 204 struct listnode *node;
205 struct ospf6_nexthop *nh;
206
207 if (nh_list && nh_match) {
208 for (ALL_LIST_ELEMENTS_RO(nh_list, node, nh)) {
209 if (ospf6_nexthop_is_same(nh, nh_match))
210 return (nh);
211 }
c3c0ac83 212 }
c3c0ac83 213
d62a17ae 214 return (NULL);
c3c0ac83
DS
215}
216
d62a17ae 217void ospf6_copy_nexthops(struct list *dst, struct list *src)
c3c0ac83 218{
d62a17ae 219 struct ospf6_nexthop *nh_new, *nh;
220 struct listnode *node;
221
222 if (dst && src) {
223 for (ALL_LIST_ELEMENTS_RO(src, node, nh)) {
224 if (ospf6_nexthop_is_set(nh)) {
225 nh_new = ospf6_nexthop_create();
226 ospf6_nexthop_copy(nh_new, nh);
064d4355 227 listnode_add_sort(dst, nh_new);
d62a17ae 228 }
229 }
c3c0ac83 230 }
c3c0ac83
DS
231}
232
d62a17ae 233void ospf6_merge_nexthops(struct list *dst, struct list *src)
c3c0ac83 234{
d62a17ae 235 struct listnode *node;
236 struct ospf6_nexthop *nh, *nh_new;
237
238 if (src && dst) {
239 for (ALL_LIST_ELEMENTS_RO(src, node, nh)) {
240 if (!ospf6_route_find_nexthop(dst, nh)) {
241 nh_new = ospf6_nexthop_create();
242 ospf6_nexthop_copy(nh_new, nh);
064d4355 243 listnode_add_sort(dst, nh_new);
d62a17ae 244 }
245 }
c3c0ac83 246 }
c3c0ac83
DS
247}
248
d62a17ae 249int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
c3c0ac83 250{
d62a17ae 251 struct listnode *anode, *bnode;
252 struct ospf6_nexthop *anh, *bnh;
f867df18 253 bool identical = false;
d62a17ae 254
255 if (a && b) {
256 if (listcount(a->nh_list) == listcount(b->nh_list)) {
257 for (ALL_LIST_ELEMENTS_RO(a->nh_list, anode, anh)) {
f867df18 258 identical = false;
d62a17ae 259 for (ALL_LIST_ELEMENTS_RO(b->nh_list, bnode,
f867df18
CS
260 bnh)) {
261 if (ospf6_nexthop_is_same(anh, bnh))
262 identical = true;
263 }
264 /* Currnet List A element not found List B
265 * Non-Identical lists return */
266 if (identical == false)
267 return 1;
d62a17ae 268 }
f867df18 269 return 0;
d62a17ae 270 } else
f867df18 271 return 1;
c3c0ac83 272 }
d62a17ae 273 /* One of the routes doesn't exist ? */
c3c0ac83 274 return (1);
c3c0ac83
DS
275}
276
d62a17ae 277int ospf6_num_nexthops(struct list *nh_list)
c3c0ac83 278{
d62a17ae 279 return (listcount(nh_list));
c3c0ac83
DS
280}
281
d62a17ae 282void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
c3c0ac83 283{
d62a17ae 284 struct ospf6_nexthop *nh;
285 struct ospf6_nexthop nh_match;
286
287 if (nh_list) {
d2e5d5d4
MR
288 if (addr) {
289 if (ifindex)
290 nh_match.type = NEXTHOP_TYPE_IPV6_IFINDEX;
291 else
292 nh_match.type = NEXTHOP_TYPE_IPV6;
293
d62a17ae 294 memcpy(&nh_match.address, addr,
295 sizeof(struct in6_addr));
d2e5d5d4
MR
296 } else {
297 nh_match.type = NEXTHOP_TYPE_IFINDEX;
298
d62a17ae 299 memset(&nh_match.address, 0, sizeof(struct in6_addr));
d2e5d5d4
MR
300 }
301
302 nh_match.ifindex = ifindex;
d62a17ae 303
304 if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
305 nh = ospf6_nexthop_create();
306 ospf6_nexthop_copy(nh, &nh_match);
307 listnode_add(nh_list, nh);
308 }
c3c0ac83 309 }
c3c0ac83
DS
310}
311
d2e5d5d4
MR
312void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route)
313{
314 struct ospf6_nexthop *nh;
315 struct ospf6_nexthop nh_match = {};
316
317 /* List not allocated. */
318 if (route->nh_list == NULL)
319 return;
320
321 /* Entry already exists. */
322 nh_match.type = NEXTHOP_TYPE_BLACKHOLE;
323 if (ospf6_route_find_nexthop(route->nh_list, &nh_match))
324 return;
325
326 nh = ospf6_nexthop_create();
327 ospf6_nexthop_copy(nh, &nh_match);
328 listnode_add(route->nh_list, nh);
329}
330
d62a17ae 331void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
5afa1c6b 332 struct zapi_nexthop nexthops[],
1fa58587 333 int entries, vrf_id_t vrf_id)
c3c0ac83 334{
d62a17ae 335 struct ospf6_nexthop *nh;
336 struct listnode *node;
d62a17ae 337 int i;
338
339 if (route) {
340 i = 0;
341 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
342 if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
d2e5d5d4
MR
343 zlog_debug(" nexthop: %s %pI6%%%.*s(%d)",
344 nexthop_type_to_str(nh->type),
345 &nh->address, IFNAMSIZ,
346 ifindex2ifname(nh->ifindex, vrf_id),
347 nh->ifindex);
d62a17ae 348 }
d2e5d5d4 349
b30f3b91
RW
350 if (i >= entries)
351 return;
352
1fa58587 353 nexthops[i].vrf_id = vrf_id;
d2e5d5d4
MR
354 nexthops[i].type = nh->type;
355
356 switch (nh->type) {
357 case NEXTHOP_TYPE_BLACKHOLE:
358 /* NOTHING */
359 break;
360
361 case NEXTHOP_TYPE_IFINDEX:
362 nexthops[i].ifindex = nh->ifindex;
363 break;
364
365 case NEXTHOP_TYPE_IPV4_IFINDEX:
366 case NEXTHOP_TYPE_IPV4:
367 /*
368 * OSPFv3 with IPv4 routes is not supported
369 * yet. Skip this next hop.
370 */
371 if (IS_OSPF6_DEBUG_ZEBRA(SEND))
372 zlog_debug(" Skipping IPv4 next hop");
373 continue;
374
375 case NEXTHOP_TYPE_IPV6_IFINDEX:
376 nexthops[i].ifindex = nh->ifindex;
377 /* FALLTHROUGH */
378 case NEXTHOP_TYPE_IPV6:
5afa1c6b 379 nexthops[i].gate.ipv6 = nh->address;
d2e5d5d4
MR
380 break;
381 }
b30f3b91 382 i++;
d62a17ae 383 }
c3c0ac83 384 }
c3c0ac83
DS
385}
386
d62a17ae 387int ospf6_route_get_first_nh_index(struct ospf6_route *route)
c3c0ac83 388{
d62a17ae 389 struct ospf6_nexthop *nh;
c3c0ac83 390
d62a17ae 391 if (route) {
10197318
DS
392 nh = listnode_head(route->nh_list);
393 if (nh)
394 return nh->ifindex;
d62a17ae 395 }
c3c0ac83 396
95f7965d 397 return -1;
c3c0ac83
DS
398}
399
064d4355 400int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
d107621d 401{
f867df18
CS
402 if (a->ifindex < b->ifindex)
403 return -1;
404 else if (a->ifindex > b->ifindex)
d107621d 405 return 1;
f867df18
CS
406 else
407 return memcmp(&a->address, &b->address,
408 sizeof(struct in6_addr));
d107621d
CS
409}
410
064d4355
CS
411static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
412{
413 if (a->origin.adv_router < b->origin.adv_router)
414 return -1;
415 else if (a->origin.adv_router > b->origin.adv_router)
416 return 1;
417 else
418 return 0;
419}
420
421void ospf6_path_free(struct ospf6_path *op)
422{
423 if (op->nh_list)
6a154c88 424 list_delete(&op->nh_list);
064d4355
CS
425 XFREE(MTYPE_OSPF6_PATH, op);
426}
427
428struct ospf6_path *ospf6_path_dup(struct ospf6_path *path)
429{
430 struct ospf6_path *new;
431
432 new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path));
433 memcpy(new, path, sizeof(struct ospf6_path));
434 new->nh_list = list_new();
435 new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
996c9314 436 new->nh_list->del = (void (*)(void *))ospf6_nexthop_delete;
064d4355
CS
437
438 return new;
439}
440
03f3c1c1
CS
441void ospf6_copy_paths(struct list *dst, struct list *src)
442{
443 struct ospf6_path *path_new, *path;
444 struct listnode *node;
445
446 if (dst && src) {
447 for (ALL_LIST_ELEMENTS_RO(src, node, path)) {
448 path_new = ospf6_path_dup(path);
449 ospf6_copy_nexthops(path_new->nh_list, path->nh_list);
450 listnode_add_sort(dst, path_new);
451 }
452 }
453}
454
22813fdb 455struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6)
718e3744 456{
d62a17ae 457 struct ospf6_route *route;
e285b70d 458
d62a17ae 459 route = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route));
460 route->nh_list = list_new();
d107621d 461 route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
996c9314 462 route->nh_list->del = (void (*)(void *))ospf6_nexthop_delete;
064d4355
CS
463 route->paths = list_new();
464 route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
996c9314 465 route->paths->del = (void (*)(void *))ospf6_path_free;
22813fdb
MR
466 route->ospf6 = ospf6;
467
d62a17ae 468 return route;
508e53e2 469}
718e3744 470
d62a17ae 471void ospf6_route_delete(struct ospf6_route *route)
508e53e2 472{
d62a17ae 473 if (route) {
d107621d 474 if (route->nh_list)
6a154c88 475 list_delete(&route->nh_list);
064d4355 476 if (route->paths)
6a154c88 477 list_delete(&route->paths);
d62a17ae 478 XFREE(MTYPE_OSPF6_ROUTE, route);
479 }
718e3744 480}
481
d62a17ae 482struct ospf6_route *ospf6_route_copy(struct ospf6_route *route)
718e3744 483{
d62a17ae 484 struct ospf6_route *new;
485
22813fdb 486 new = ospf6_route_create(route->ospf6);
d62a17ae 487 new->type = route->type;
488 memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
4699ad72 489 new->prefix_options = route->prefix_options;
d62a17ae 490 new->installed = route->installed;
491 new->changed = route->changed;
492 new->flag = route->flag;
493 new->route_option = route->route_option;
494 new->linkstate_id = route->linkstate_id;
495 new->path = route->path;
496 ospf6_copy_nexthops(new->nh_list, route->nh_list);
03f3c1c1 497 ospf6_copy_paths(new->paths, route->paths);
d62a17ae 498 new->rnode = NULL;
499 new->prev = NULL;
500 new->next = NULL;
501 new->table = NULL;
502 new->lock = 0;
503 return new;
508e53e2 504}
718e3744 505
d62a17ae 506void ospf6_route_lock(struct ospf6_route *route)
508e53e2 507{
d62a17ae 508 route->lock++;
508e53e2 509}
718e3744 510
d62a17ae 511void ospf6_route_unlock(struct ospf6_route *route)
508e53e2 512{
d62a17ae 513 assert(route->lock > 0);
514 route->lock--;
515 if (route->lock == 0) {
516 /* Can't detach from the table until here
517 because ospf6_route_next () will use
518 the 'route->table' pointer for logging */
519 route->table = NULL;
520 ospf6_route_delete(route);
521 }
508e53e2 522}
718e3744 523
508e53e2 524/* Route compare function. If ra is more preferred, it returns
525 less than 0. If rb is more preferred returns greater than 0.
526 Otherwise (neither one is preferred), returns 0 */
d62a17ae 527int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
508e53e2 528{
d62a17ae 529 assert(ospf6_route_is_same(ra, rb));
530 assert(OSPF6_PATH_TYPE_NONE < ra->path.type
531 && ra->path.type < OSPF6_PATH_TYPE_MAX);
532 assert(OSPF6_PATH_TYPE_NONE < rb->path.type
533 && rb->path.type < OSPF6_PATH_TYPE_MAX);
534
535 if (ra->type != rb->type)
536 return (ra->type - rb->type);
537
d62a17ae 538 if (ra->path.type != rb->path.type)
539 return (ra->path.type - rb->path.type);
540
541 if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
542 if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
543 return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
07b37f93
CS
544 else
545 return (ra->path.cost - rb->path.cost);
d62a17ae 546 } else {
547 if (ra->path.cost != rb->path.cost)
548 return (ra->path.cost - rb->path.cost);
549 }
550
10efbdc2
CS
551 if (ra->path.area_id != rb->path.area_id)
552 return (ntohl(ra->path.area_id) - ntohl(rb->path.area_id));
553
d62a17ae 554 return 0;
718e3744 555}
556
d62a17ae 557struct ospf6_route *ospf6_route_lookup(struct prefix *prefix,
558 struct ospf6_route_table *table)
718e3744 559{
d62a17ae 560 struct route_node *node;
561 struct ospf6_route *route;
718e3744 562
d62a17ae 563 node = route_node_lookup(table->table, prefix);
564 if (node == NULL)
565 return NULL;
508e53e2 566
d62a17ae 567 route = (struct ospf6_route *)node->info;
d107621d 568 route_unlock_node(node); /* to free the lookup lock */
d62a17ae 569 return route;
508e53e2 570}
718e3744 571
508e53e2 572struct ospf6_route *
d62a17ae 573ospf6_route_lookup_identical(struct ospf6_route *route,
574 struct ospf6_route_table *table)
508e53e2 575{
d62a17ae 576 struct ospf6_route *target;
577
578 for (target = ospf6_route_lookup(&route->prefix, table); target;
579 target = target->next) {
996c9314 580 if (target->type == route->type
a48bc483 581 && prefix_same(&target->prefix, &route->prefix)
996c9314
LB
582 && target->path.type == route->path.type
583 && target->path.cost == route->path.cost
584 && target->path.u.cost_e2 == route->path.u.cost_e2
585 && ospf6_route_cmp_nexthops(target, route) == 0)
d62a17ae 586 return target;
587 }
588 return NULL;
718e3744 589}
590
508e53e2 591struct ospf6_route *
d62a17ae 592ospf6_route_lookup_bestmatch(struct prefix *prefix,
593 struct ospf6_route_table *table)
718e3744 594{
d62a17ae 595 struct route_node *node;
596 struct ospf6_route *route;
718e3744 597
d62a17ae 598 node = route_node_match(table->table, prefix);
599 if (node == NULL)
600 return NULL;
601 route_unlock_node(node);
718e3744 602
d62a17ae 603 route = (struct ospf6_route *)node->info;
604 return route;
718e3744 605}
606
e39d0538 607#ifdef DEBUG
d62a17ae 608static void route_table_assert(struct ospf6_route_table *table)
718e3744 609{
d62a17ae 610 struct ospf6_route *prev, *r, *next;
d62a17ae 611 unsigned int link_error = 0, num = 0;
612
613 r = ospf6_route_head(table);
614 prev = NULL;
615 while (r) {
616 if (r->prev != prev)
617 link_error++;
618
619 next = ospf6_route_next(r);
620
621 if (r->next != next)
622 link_error++;
623
624 prev = r;
625 r = next;
626 }
627
628 for (r = ospf6_route_head(table); r; r = ospf6_route_next(r))
629 num++;
630
631 if (link_error == 0 && num == table->count)
632 return;
633
450971aa 634 flog_err(EC_LIB_DEVELOPMENT, "PANIC !!");
1c50c1c0
QY
635 flog_err(EC_LIB_DEVELOPMENT,
636 "Something has gone wrong with ospf6_route_table[%p]", table);
d62a17ae 637 zlog_debug("table count = %d, real number = %d", table->count, num);
638 zlog_debug("DUMP START");
2dbe669b
DA
639 for (r = ospf6_route_head(table); r; r = ospf6_route_next(r))
640 zlog_info("%p<-[%p]->%p : %pFX", r->prev, r, r->next,
641 &r->prefix);
d62a17ae 642 zlog_debug("DUMP END");
643
644 assert(link_error == 0 && num == table->count);
718e3744 645}
cf1ce250 646#define ospf6_route_table_assert(t) (route_table_assert (t))
508e53e2 647#else
cf1ce250 648#define ospf6_route_table_assert(t) ((void) 0)
e39d0538 649#endif /*DEBUG*/
718e3744 650
d62a17ae 651struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
e285b70d 652 struct ospf6_route_table *table)
718e3744 653{
d62a17ae 654 struct route_node *node, *nextnode, *prevnode;
655 struct ospf6_route *current = NULL;
656 struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
657 char buf[PREFIX2STR_BUFFER];
658 struct timeval now;
659
660 assert(route->rnode == NULL);
661 assert(route->lock == 0);
662 assert(route->next == NULL);
663 assert(route->prev == NULL);
664
665 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
666 ospf6_linkstate_prefix2str(&route->prefix, buf, sizeof(buf));
9142948e
RW
667 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
668 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
669 sizeof(buf));
d62a17ae 670 else
671 prefix2str(&route->prefix, buf, sizeof(buf));
672
673 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
6942698d 674 zlog_debug("%s %p: route add %p: %s paths %u nh %u",
d62a17ae 675 ospf6_route_table_name(table), (void *)table,
6942698d
CS
676 (void *)route, buf, listcount(route->paths),
677 listcount(route->nh_list));
d62a17ae 678 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
679 zlog_debug("%s: route add: %s", ospf6_route_table_name(table),
680 buf);
681
682 monotime(&now);
683
684 node = route_node_get(table->table, &route->prefix);
685 route->rnode = node;
686
687 /* find place to insert */
688 for (current = node->info; current; current = current->next) {
689 if (!ospf6_route_is_same(current, route))
690 next = current;
691 else if (current->type != route->type)
692 prev = current;
693 else if (ospf6_route_is_same_origin(current, route))
694 old = current;
695 else if (ospf6_route_cmp(current, route) > 0)
696 next = current;
697 else
698 prev = current;
699
700 if (old || next)
701 break;
702 }
718e3744 703
d62a17ae 704 if (old) {
4dfe1520
RW
705 /* if route does not actually change, return unchanged */
706 if (ospf6_route_is_identical(old, route)) {
707 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
708 zlog_debug(
709 "%s %p: route add %p: needless update of %p old cost %u",
710 ospf6_route_table_name(table),
711 (void *)table, (void *)route,
712 (void *)old, old->path.cost);
713 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
714 zlog_debug("%s: route add: needless update",
715 ospf6_route_table_name(table));
716
717 ospf6_route_delete(route);
718 SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
719 ospf6_route_table_assert(table);
720
721 /* to free the lookup lock */
722 route_unlock_node(node);
723 return old;
724 }
725
d62a17ae 726 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
996c9314 727 zlog_debug(
6942698d 728 "%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
996c9314 729 ospf6_route_table_name(table), (void *)table,
03f3c1c1 730 (void *)route, route->path.cost,
6942698d 731 listcount(route->paths),
03f3c1c1 732 listcount(route->nh_list), (void *)old,
6942698d
CS
733 old->path.cost, listcount(old->paths),
734 listcount(old->nh_list));
d62a17ae 735 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
736 zlog_debug("%s: route add: update",
737 ospf6_route_table_name(table));
738
739 /* replace old one if exists */
740 if (node->info == old) {
741 node->info = route;
742 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
35769de4
K
743 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
744 zlog_debug("%s: replace old route %s",
745 __func__, buf);
d62a17ae 746 }
747
748 if (old->prev)
749 old->prev->next = route;
750 route->prev = old->prev;
751 if (old->next)
752 old->next->prev = route;
753 route->next = old->next;
754
755 route->installed = old->installed;
756 route->changed = now;
757 assert(route->table == NULL);
758 route->table = table;
759
760 ospf6_route_unlock(old); /* will be deleted later */
761 ospf6_route_lock(route);
762
763 SET_FLAG(route->flag, OSPF6_ROUTE_CHANGE);
764 ospf6_route_table_assert(table);
765
766 if (table->hook_add)
e285b70d 767 (*table->hook_add)(route);
d62a17ae 768
769 return route;
770 }
771
772 /* insert if previous or next node found */
773 if (prev || next) {
774 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
775 zlog_debug(
07b37f93 776 "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u",
d62a17ae 777 ospf6_route_table_name(table), (void *)table,
07b37f93 778 (void *)route, route->path.cost, (void *)prev,
c10e14e9 779 (void *)next, route_node_get_lock_count(node));
d62a17ae 780 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
07b37f93
CS
781 zlog_debug("%s: route add cost %u: another path found",
782 ospf6_route_table_name(table),
783 route->path.cost);
d62a17ae 784
785 if (prev == NULL)
786 prev = next->prev;
787 if (next == NULL)
788 next = prev->next;
789
790 if (prev)
791 prev->next = route;
792 route->prev = prev;
793 if (next)
794 next->prev = route;
795 route->next = next;
796
797 if (node->info == next) {
4f4060f6 798 assert(next && next->rnode == node);
d62a17ae 799 node->info = route;
800 UNSET_FLAG(next->flag, OSPF6_ROUTE_BEST);
801 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
802 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
35769de4 803 zlog_debug(
c601fa3f 804 "%s %p: route add %p cost %u: replacing previous best: %p cost %u",
d62a17ae 805 ospf6_route_table_name(table),
806 (void *)table, (void *)route,
35769de4
K
807 route->path.cost, (void *)next,
808 next->path.cost);
d62a17ae 809 }
810
811 route->installed = now;
812 route->changed = now;
813 assert(route->table == NULL);
814 route->table = table;
815
816 ospf6_route_lock(route);
817 table->count++;
818 ospf6_route_table_assert(table);
819
820 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
821 if (table->hook_add)
e285b70d 822 (*table->hook_add)(route);
d62a17ae 823
824 return route;
825 }
826
827 /* Else, this is the brand new route regarding to the prefix */
828 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
c601fa3f 829 zlog_debug("%s %p: route add %p %s cost %u: brand new route",
d62a17ae 830 ospf6_route_table_name(table), (void *)table,
c601fa3f 831 (void *)route, buf, route->path.cost);
d62a17ae 832 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
833 zlog_debug("%s: route add: brand new route",
834 ospf6_route_table_name(table));
835
836 assert(node->info == NULL);
837 node->info = route;
838 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
839 ospf6_route_lock(route);
840 route->installed = now;
841 route->changed = now;
842 assert(route->table == NULL);
843 route->table = table;
844
845 /* lookup real existing next route */
846 nextnode = node;
847 route_lock_node(nextnode);
848 do {
849 nextnode = route_next(nextnode);
850 } while (nextnode && nextnode->info == NULL);
851
852 /* set next link */
853 if (nextnode == NULL)
854 route->next = NULL;
855 else {
856 route_unlock_node(nextnode);
857
858 next = nextnode->info;
859 route->next = next;
860 next->prev = route;
861 }
862
863 /* lookup real existing prev route */
864 prevnode = node;
865 route_lock_node(prevnode);
866 do {
867 prevnode = route_prev(prevnode);
868 } while (prevnode && prevnode->info == NULL);
869
870 /* set prev link */
871 if (prevnode == NULL)
872 route->prev = NULL;
873 else {
874 route_unlock_node(prevnode);
875
876 prev = prevnode->info;
877 while (prev->next && ospf6_route_is_same(prev, prev->next))
878 prev = prev->next;
879 route->prev = prev;
880 prev->next = route;
881 }
882
883 table->count++;
884 ospf6_route_table_assert(table);
885
886 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
887 if (table->hook_add)
e285b70d 888 (*table->hook_add)(route);
d62a17ae 889
890 return route;
508e53e2 891}
718e3744 892
d62a17ae 893void ospf6_route_remove(struct ospf6_route *route,
e285b70d 894 struct ospf6_route_table *table)
508e53e2 895{
d62a17ae 896 struct route_node *node;
897 struct ospf6_route *current;
898 char buf[PREFIX2STR_BUFFER];
899
900 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
901 ospf6_linkstate_prefix2str(&route->prefix, buf, sizeof(buf));
9142948e
RW
902 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
903 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
904 sizeof(buf));
d62a17ae 905 else
906 prefix2str(&route->prefix, buf, sizeof(buf));
907
908 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
07b37f93 909 zlog_debug("%s %p: route remove %p: %s cost %u refcount %u",
d62a17ae 910 ospf6_route_table_name(table), (void *)table,
07b37f93 911 (void *)route, buf, route->path.cost, route->lock);
d62a17ae 912 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
913 zlog_debug("%s: route remove: %s",
914 ospf6_route_table_name(table), buf);
915
916 node = route_node_lookup(table->table, &route->prefix);
917 assert(node);
918
919 /* find the route to remove, making sure that the route pointer
920 is from the route table. */
921 current = node->info;
d107621d 922 while (current && current != route)
d62a17ae 923 current = current->next;
d107621d 924
d62a17ae 925 assert(current == route);
926
927 /* adjust doubly linked list */
928 if (route->prev)
929 route->prev->next = route->next;
930 if (route->next)
931 route->next->prev = route->prev;
932
933 if (node->info == route) {
934 if (route->next && route->next->rnode == node) {
935 node->info = route->next;
936 SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST);
35769de4
K
937 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
938 zlog_debug("%s: remove route %s", __func__,
939 buf);
d107621d
CS
940 } else {
941 node->info = NULL;
942 route->rnode = NULL;
943 route_unlock_node(node); /* to free the original lock */
944 }
d62a17ae 945 }
508e53e2 946
d107621d 947 route_unlock_node(node); /* to free the lookup lock */
d62a17ae 948 table->count--;
949 ospf6_route_table_assert(table);
718e3744 950
d62a17ae 951 SET_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED);
508e53e2 952
dd2395e1 953 /* Note hook_remove may call ospf6_route_remove */
d62a17ae 954 if (table->hook_remove)
e285b70d 955 (*table->hook_remove)(route);
cf1ce250 956
d62a17ae 957 ospf6_route_unlock(route);
958}
cf1ce250 959
d62a17ae 960struct ospf6_route *ospf6_route_head(struct ospf6_route_table *table)
961{
962 struct route_node *node;
963 struct ospf6_route *route;
964
965 node = route_top(table->table);
966 if (node == NULL)
967 return NULL;
968
969 /* skip to the real existing entry */
970 while (node && node->info == NULL)
971 node = route_next(node);
972 if (node == NULL)
973 return NULL;
974
975 route_unlock_node(node);
976 assert(node->info);
977
978 route = (struct ospf6_route *)node->info;
979 assert(route->prev == NULL);
980 assert(route->table == table);
981 ospf6_route_lock(route);
982
983 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
984 zlog_info("%s %p: route head: %p<-[%p]->%p",
985 ospf6_route_table_name(table), (void *)table,
986 (void *)route->prev, (void *)route,
987 (void *)route->next);
988
989 return route;
718e3744 990}
991
d62a17ae 992struct ospf6_route *ospf6_route_next(struct ospf6_route *route)
718e3744 993{
d62a17ae 994 struct ospf6_route *next = route->next;
718e3744 995
d62a17ae 996 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
a2d0055a 997 zlog_info("%s %p: route next: %p<-[%p]->%p , route ref count %u",
d62a17ae 998 ospf6_route_table_name(route->table),
999 (void *)route->table, (void *)route->prev,
a2d0055a
CS
1000 (void *)route, (void *)route->next,
1001 route->lock);
cf1ce250 1002
d62a17ae 1003 ospf6_route_unlock(route);
1004 if (next)
1005 ospf6_route_lock(next);
718e3744 1006
d62a17ae 1007 return next;
508e53e2 1008}
718e3744 1009
d62a17ae 1010struct ospf6_route *ospf6_route_best_next(struct ospf6_route *route)
508e53e2 1011{
d62a17ae 1012 struct route_node *rnode;
1013 struct ospf6_route *next;
1014
1015 ospf6_route_unlock(route);
1016
1017 rnode = route->rnode;
1018 route_lock_node(rnode);
1019 rnode = route_next(rnode);
1020 while (rnode && rnode->info == NULL)
1021 rnode = route_next(rnode);
1022 if (rnode == NULL)
1023 return NULL;
1024 route_unlock_node(rnode);
1025
1026 assert(rnode->info);
1027 next = (struct ospf6_route *)rnode->info;
1028 ospf6_route_lock(next);
1029 return next;
508e53e2 1030}
718e3744 1031
d62a17ae 1032struct ospf6_route *ospf6_route_match_head(struct prefix *prefix,
1033 struct ospf6_route_table *table)
508e53e2 1034{
d62a17ae 1035 struct route_node *node;
1036 struct ospf6_route *route;
1037
1038 /* Walk down tree. */
1039 node = table->table->top;
1040 while (node && node->p.prefixlen < prefix->prefixlen
1041 && prefix_match(&node->p, prefix))
1042 node = node->link[prefix_bit(&prefix->u.prefix,
1043 node->p.prefixlen)];
1044
1045 if (node)
1046 route_lock_node(node);
1047 while (node && node->info == NULL)
1048 node = route_next(node);
1049 if (node == NULL)
1050 return NULL;
1051 route_unlock_node(node);
1052
1053 if (!prefix_match(prefix, &node->p))
1054 return NULL;
1055
1056 route = node->info;
1057 ospf6_route_lock(route);
1058 return route;
508e53e2 1059}
718e3744 1060
d62a17ae 1061struct ospf6_route *ospf6_route_match_next(struct prefix *prefix,
1062 struct ospf6_route *route)
508e53e2 1063{
d62a17ae 1064 struct ospf6_route *next;
508e53e2 1065
d62a17ae 1066 next = ospf6_route_next(route);
1067 if (next && !prefix_match(prefix, &next->prefix)) {
1068 ospf6_route_unlock(next);
1069 next = NULL;
1070 }
508e53e2 1071
d62a17ae 1072 return next;
718e3744 1073}
1074
e285b70d 1075void ospf6_route_remove_all(struct ospf6_route_table *table)
718e3744 1076{
d62a17ae 1077 struct ospf6_route *route;
1078 for (route = ospf6_route_head(table); route;
1079 route = ospf6_route_next(route))
e285b70d 1080 ospf6_route_remove(route, table);
718e3744 1081}
1082
d62a17ae 1083struct ospf6_route_table *ospf6_route_table_create(int s, int t)
718e3744 1084{
d62a17ae 1085 struct ospf6_route_table *new;
de4a0bda
PR
1086 new = XCALLOC(MTYPE_OSPF6_ROUTE_TABLE,
1087 sizeof(struct ospf6_route_table));
d62a17ae 1088 new->table = route_table_init();
1089 new->scope_type = s;
1090 new->table_type = t;
1091 return new;
718e3744 1092}
1093
e285b70d 1094void ospf6_route_table_delete(struct ospf6_route_table *table)
718e3744 1095{
e285b70d 1096 ospf6_route_remove_all(table);
d62a17ae 1097 route_table_finish(table->table);
de4a0bda 1098 XFREE(MTYPE_OSPF6_ROUTE_TABLE, table);
718e3744 1099}
1100
6b0655a2 1101
508e53e2 1102/* VTY commands */
eacd0828 1103void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
a49ef569 1104 json_object *json_routes, bool use_json)
718e3744 1105{
d62a17ae 1106 int i;
1107 char destination[PREFIX2STR_BUFFER], nexthop[64];
68bfcc05 1108 char duration[64];
d62a17ae 1109 struct timeval now, res;
1110 struct listnode *node;
1111 struct ospf6_nexthop *nh;
eacd0828
YR
1112 json_object *json_route = NULL;
1113 json_object *json_array_next_hops = NULL;
1114 json_object *json_next_hop;
dbbcd516 1115 vrf_id_t vrf_id = route->ospf6->vrf_id;
d62a17ae 1116
1117 monotime(&now);
1118 timersub(&now, &route->changed, &res);
1119 timerstring(&res, duration, sizeof(duration));
1120
1121 /* destination */
1122 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1123 ospf6_linkstate_prefix2str(&route->prefix, destination,
1124 sizeof(destination));
1125 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1126 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1127 destination, sizeof(destination));
1128 else
1129 prefix2str(&route->prefix, destination, sizeof(destination));
1130
eacd0828
YR
1131 if (use_json) {
1132 json_route = json_object_new_object();
eacd0828
YR
1133 json_object_boolean_add(json_route, "isBestRoute",
1134 ospf6_route_is_best(route));
1135 json_object_string_add(json_route, "destinationType",
1136 OSPF6_DEST_TYPE_SUBSTR(route->type));
1137 json_object_string_add(
1138 json_route, "pathType",
1139 OSPF6_PATH_TYPE_SUBSTR(route->path.type));
1140 json_object_string_add(json_route, "duration", duration);
1141 }
1142
1143 /* Nexthops */
1144 if (use_json)
1145 json_array_next_hops = json_object_new_array();
1146 else
1147 i = 0;
d62a17ae 1148 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
1149 /* nexthop */
1150 inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
eacd0828
YR
1151 if (use_json) {
1152 json_next_hop = json_object_new_object();
1153 json_object_string_add(json_next_hop, "nextHop",
1154 nexthop);
dbbcd516
IR
1155 json_object_string_add(
1156 json_next_hop, "interfaceName",
1157 ifindex2ifname(nh->ifindex, vrf_id));
eacd0828
YR
1158 json_object_array_add(json_array_next_hops,
1159 json_next_hop);
1160 } else {
1161 if (!i) {
1162 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1163 (ospf6_route_is_best(route) ? '*'
1164 : ' '),
1165 OSPF6_DEST_TYPE_SUBSTR(route->type),
1166 OSPF6_PATH_TYPE_SUBSTR(
1167 route->path.type),
1168 destination, nexthop, IFNAMSIZ,
dbbcd516
IR
1169 ifindex2ifname(nh->ifindex, vrf_id),
1170 duration);
eacd0828
YR
1171 i++;
1172 } else
1173 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1174 ' ', "", "", "", nexthop, IFNAMSIZ,
dbbcd516
IR
1175 ifindex2ifname(nh->ifindex, vrf_id),
1176 "");
eacd0828
YR
1177 }
1178 }
1179 if (use_json) {
1180 json_object_object_add(json_route, "nextHops",
1181 json_array_next_hops);
a49ef569 1182 json_object_object_add(json_routes, destination, json_route);
c3c0ac83 1183 }
718e3744 1184}
1185
eacd0828 1186void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
a49ef569 1187 json_object *json_routes, bool use_json)
718e3744 1188{
eacd0828 1189 char destination[PREFIX2STR_BUFFER], nexthop[64];
6cb85350 1190 char area_id[16], id[16], adv_router[16], capa[16], options[32];
b0822151 1191 char pfx_options[16];
d62a17ae 1192 struct timeval now, res;
68bfcc05 1193 char duration[64];
d62a17ae 1194 struct listnode *node;
1195 struct ospf6_nexthop *nh;
eacd0828
YR
1196 char flag[6];
1197 json_object *json_route = NULL;
1198 json_object *json_array_next_hops = NULL;
1199 json_object *json_next_hop;
dbbcd516 1200 vrf_id_t vrf_id = route->ospf6->vrf_id;
d62a17ae 1201
1202 monotime(&now);
1203
1204 /* destination */
1205 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1206 ospf6_linkstate_prefix2str(&route->prefix, destination,
1207 sizeof(destination));
1208 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1209 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1210 destination, sizeof(destination));
1211 else
1212 prefix2str(&route->prefix, destination, sizeof(destination));
d62a17ae 1213
eacd0828
YR
1214 if (use_json) {
1215 json_route = json_object_new_object();
eacd0828
YR
1216 json_object_string_add(json_route, "destinationType",
1217 OSPF6_DEST_TYPE_NAME(route->type));
1218 } else {
1219 vty_out(vty, "Destination: %s\n", destination);
1220 vty_out(vty, "Destination type: %s\n",
1221 OSPF6_DEST_TYPE_NAME(route->type));
1222 }
d62a17ae 1223
1224 /* Time */
1225 timersub(&now, &route->installed, &res);
1226 timerstring(&res, duration, sizeof(duration));
eacd0828
YR
1227 if (use_json)
1228 json_object_string_add(json_route, "installedTimeSince",
1229 duration);
1230 else
1231 vty_out(vty, "Installed Time: %s ago\n", duration);
d62a17ae 1232
1233 timersub(&now, &route->changed, &res);
1234 timerstring(&res, duration, sizeof(duration));
eacd0828
YR
1235 if (use_json)
1236 json_object_string_add(json_route, "changedTimeSince",
1237 duration);
1238 else
1239 vty_out(vty, "Changed Time: %s ago\n", duration);
d62a17ae 1240
1241 /* Debugging info */
eacd0828
YR
1242 if (use_json) {
1243 json_object_int_add(json_route, "numberOfLock", route->lock);
1244 snprintf(
1245 flag, sizeof(flag), "%s%s%s%s",
1246 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1247 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1248 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1249 : "-"),
1250 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1251 : "-"));
1252 json_object_string_add(json_route, "flags", flag);
1253 } else {
1254 vty_out(vty, "Lock: %d Flags: %s%s%s%s\n", route->lock,
1255 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1256 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1257 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1258 : "-"),
1259 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1260 : "-"));
1261 vty_out(vty, "Memory: prev: %p this: %p next: %p\n",
1262 (void *)route->prev, (void *)route,
1263 (void *)route->next);
1264 }
d62a17ae 1265
1266 /* Path section */
1267
1268 /* Area-ID */
1269 inet_ntop(AF_INET, &route->path.area_id, area_id, sizeof(area_id));
eacd0828
YR
1270 if (use_json)
1271 json_object_string_add(json_route, "associatedArea", area_id);
1272 else
1273 vty_out(vty, "Associated Area: %s\n", area_id);
d62a17ae 1274
1275 /* Path type */
eacd0828
YR
1276 if (use_json)
1277 json_object_string_add(json_route, "pathType",
1278 OSPF6_PATH_TYPE_NAME(route->path.type));
1279 else
1280 vty_out(vty, "Path Type: %s\n",
1281 OSPF6_PATH_TYPE_NAME(route->path.type));
d62a17ae 1282
1283 /* LS Origin */
1284 inet_ntop(AF_INET, &route->path.origin.id, id, sizeof(id));
1285 inet_ntop(AF_INET, &route->path.origin.adv_router, adv_router,
1286 sizeof(adv_router));
eacd0828
YR
1287 if (use_json) {
1288 json_object_string_add(
1289 json_route, "lsOriginRoutePathType",
1290 ospf6_lstype_name(route->path.origin.type));
1291 json_object_string_add(json_route, "lsId", id);
1292 json_object_string_add(json_route, "lsAdvertisingRouter",
1293 adv_router);
1294 } else {
1295 vty_out(vty, "LS Origin: %s Id: %s Adv: %s\n",
1296 ospf6_lstype_name(route->path.origin.type), id,
1297 adv_router);
1298 }
d62a17ae 1299
1300 /* Options */
1301 ospf6_options_printbuf(route->path.options, options, sizeof(options));
eacd0828
YR
1302 if (use_json)
1303 json_object_string_add(json_route, "options", options);
1304 else
1305 vty_out(vty, "Options: %s\n", options);
d62a17ae 1306
1307 /* Router Bits */
1308 ospf6_capability_printbuf(route->path.router_bits, capa, sizeof(capa));
eacd0828
YR
1309 if (use_json)
1310 json_object_string_add(json_route, "routerBits", capa);
1311 else
1312 vty_out(vty, "Router Bits: %s\n", capa);
d62a17ae 1313
1314 /* Prefix Options */
b0822151
DL
1315 ospf6_prefix_options_printbuf(route->prefix_options, pfx_options,
1316 sizeof(pfx_options));
eacd0828 1317 if (use_json)
b0822151
DL
1318 json_object_string_add(json_route, "prefixOptions",
1319 pfx_options);
eacd0828 1320 else
b0822151 1321 vty_out(vty, "Prefix Options: %s\n", pfx_options);
d62a17ae 1322
1323 /* Metrics */
eacd0828
YR
1324 if (use_json) {
1325 json_object_int_add(json_route, "metricType",
1326 route->path.metric_type);
1327 json_object_int_add(json_route, "metricCost", route->path.cost);
1328 json_object_int_add(json_route, "metricCostE2",
1329 route->path.u.cost_e2);
1330
1331 json_object_int_add(json_route, "pathsCount",
1332 route->paths->count);
1333 json_object_int_add(json_route, "nextHopCount",
1334 route->nh_list->count);
1335 } else {
1336 vty_out(vty, "Metric Type: %d\n", route->path.metric_type);
1337 vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
1338 route->path.u.cost_e2);
1339
1340 vty_out(vty, "Paths count: %u\n", route->paths->count);
1341 vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
1342 }
d62a17ae 1343
1344 /* Nexthops */
eacd0828
YR
1345 if (use_json)
1346 json_array_next_hops = json_object_new_array();
1347 else
1348 vty_out(vty, "Nexthop:\n");
1349
d62a17ae 1350 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
eacd0828
YR
1351 /* nexthop */
1352 if (use_json) {
1353 inet_ntop(AF_INET6, &nh->address, nexthop,
1354 sizeof(nexthop));
1355 json_next_hop = json_object_new_object();
1356 json_object_string_add(json_next_hop, "nextHop",
1357 nexthop);
dbbcd516
IR
1358 json_object_string_add(
1359 json_next_hop, "interfaceName",
1360 ifindex2ifname(nh->ifindex, vrf_id));
eacd0828
YR
1361 json_object_array_add(json_array_next_hops,
1362 json_next_hop);
1363 } else
1364 vty_out(vty, " %pI6 %.*s\n", &nh->address, IFNAMSIZ,
dbbcd516 1365 ifindex2ifname(nh->ifindex, vrf_id));
d62a17ae 1366 }
eacd0828
YR
1367 if (use_json) {
1368 json_object_object_add(json_route, "nextHops",
1369 json_array_next_hops);
a49ef569 1370 json_object_object_add(json_routes, destination, json_route);
eacd0828
YR
1371 } else
1372 vty_out(vty, "\n");
508e53e2 1373}
718e3744 1374
d62a17ae 1375static void ospf6_route_show_table_summary(struct vty *vty,
eacd0828
YR
1376 struct ospf6_route_table *table,
1377 json_object *json, bool use_json)
508e53e2 1378{
d62a17ae 1379 struct ospf6_route *route, *prev = NULL;
1380 int i, pathtype[OSPF6_PATH_TYPE_MAX];
1381 unsigned int number = 0;
b6ce3356 1382 int nh_count = 0, ecmp = 0;
d62a17ae 1383 int alternative = 0, destination = 0;
eacd0828 1384 char path_str[30];
d62a17ae 1385
1386 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
1387 pathtype[i] = 0;
1388
1389 for (route = ospf6_route_head(table); route;
1390 route = ospf6_route_next(route)) {
1391 if (prev == NULL || !ospf6_route_is_same(prev, route))
1392 destination++;
1393 else
1394 alternative++;
1395 nh_count = ospf6_num_nexthops(route->nh_list);
b6ce3356 1396 if (nh_count > 1)
d62a17ae 1397 ecmp++;
1398 pathtype[route->path.type]++;
1399 number++;
1400
1401 prev = route;
1402 }
1403
1404 assert(number == table->count);
eacd0828
YR
1405 if (use_json) {
1406 json_object_int_add(json, "numberOfOspfv3Routes", number);
1407 json_object_int_add(json, "numberOfDestination", destination);
1408 json_object_int_add(json, "numberOfAlternativeRoutes",
1409 alternative);
1410 json_object_int_add(json, "numberOfEcmp", ecmp);
1411 } else {
1412 vty_out(vty, "Number of OSPFv3 routes: %d\n", number);
1413 vty_out(vty, "Number of Destination: %d\n", destination);
1414 vty_out(vty, "Number of Alternative routes: %d\n", alternative);
1415 vty_out(vty, "Number of Equal Cost Multi Path: %d\n", ecmp);
1416 }
d62a17ae 1417 for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) {
eacd0828
YR
1418 if (use_json) {
1419 snprintf(path_str, sizeof(path_str), "numberOf%sRoutes",
1420 OSPF6_PATH_TYPE_JSON(i));
1421 json_object_int_add(json, path_str, pathtype[i]);
1422 } else
1423 vty_out(vty, "Number of %s routes: %d\n",
1424 OSPF6_PATH_TYPE_NAME(i), pathtype[i]);
d62a17ae 1425 }
4846ef64 1426}
1427
d62a17ae 1428static void ospf6_route_show_table_prefix(struct vty *vty,
1429 struct prefix *prefix,
eacd0828
YR
1430 struct ospf6_route_table *table,
1431 json_object *json, bool use_json)
4846ef64 1432{
d62a17ae 1433 struct ospf6_route *route;
a49ef569 1434 json_object *json_routes = NULL;
d62a17ae 1435
1436 route = ospf6_route_lookup(prefix, table);
1437 if (route == NULL)
1438 return;
1439
eacd0828 1440 if (use_json)
a49ef569 1441 json_routes = json_object_new_object();
d62a17ae 1442 ospf6_route_lock(route);
1443 while (route && ospf6_route_is_prefix(prefix, route)) {
1444 /* Specifying a prefix will always display details */
a49ef569 1445 ospf6_route_show_detail(vty, route, json_routes, use_json);
d62a17ae 1446 route = ospf6_route_next(route);
1447 }
eacd0828
YR
1448
1449 if (use_json)
a49ef569 1450 json_object_object_add(json, "routes", json_routes);
d62a17ae 1451 if (route)
1452 ospf6_route_unlock(route);
4846ef64 1453}
1454
d62a17ae 1455static void ospf6_route_show_table_address(struct vty *vty,
1456 struct prefix *prefix,
eacd0828
YR
1457 struct ospf6_route_table *table,
1458 json_object *json, bool use_json)
4846ef64 1459{
d62a17ae 1460 struct ospf6_route *route;
a49ef569 1461 json_object *json_routes = NULL;
d62a17ae 1462
1463 route = ospf6_route_lookup_bestmatch(prefix, table);
1464 if (route == NULL)
1465 return;
1466
eacd0828 1467 if (use_json)
a49ef569 1468 json_routes = json_object_new_object();
d62a17ae 1469 prefix = &route->prefix;
1470 ospf6_route_lock(route);
1471 while (route && ospf6_route_is_prefix(prefix, route)) {
1472 /* Specifying a prefix will always display details */
a49ef569 1473 ospf6_route_show_detail(vty, route, json_routes, use_json);
d62a17ae 1474 route = ospf6_route_next(route);
1475 }
eacd0828 1476 if (use_json)
a49ef569 1477 json_object_object_add(json, "routes", json_routes);
d62a17ae 1478 if (route)
1479 ospf6_route_unlock(route);
4846ef64 1480}
1481
d62a17ae 1482static void ospf6_route_show_table_match(struct vty *vty, int detail,
1483 struct prefix *prefix,
eacd0828
YR
1484 struct ospf6_route_table *table,
1485 json_object *json, bool use_json)
4846ef64 1486{
d62a17ae 1487 struct ospf6_route *route;
a49ef569 1488 json_object *json_routes = NULL;
eacd0828 1489
d62a17ae 1490 assert(prefix->family);
1491
1492 route = ospf6_route_match_head(prefix, table);
eacd0828 1493 if (use_json)
a49ef569 1494 json_routes = json_object_new_object();
d62a17ae 1495 while (route) {
1496 if (detail)
a49ef569 1497 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1498 use_json);
d62a17ae 1499 else
a49ef569 1500 ospf6_route_show(vty, route, json_routes, use_json);
d62a17ae 1501 route = ospf6_route_match_next(prefix, route);
1502 }
eacd0828 1503 if (use_json)
a49ef569 1504 json_object_object_add(json, "routes", json_routes);
4846ef64 1505}
1506
d62a17ae 1507static void ospf6_route_show_table_type(struct vty *vty, int detail,
d7c0a89a 1508 uint8_t type,
eacd0828
YR
1509 struct ospf6_route_table *table,
1510 json_object *json, bool use_json)
4846ef64 1511{
d62a17ae 1512 struct ospf6_route *route;
a49ef569 1513 json_object *json_routes = NULL;
d62a17ae 1514
1515 route = ospf6_route_head(table);
eacd0828 1516 if (use_json)
a49ef569 1517 json_routes = json_object_new_object();
d62a17ae 1518 while (route) {
1519 if (route->path.type == type) {
1520 if (detail)
a49ef569 1521 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1522 use_json);
d62a17ae 1523 else
a49ef569 1524 ospf6_route_show(vty, route, json_routes,
eacd0828 1525 use_json);
d62a17ae 1526 }
1527 route = ospf6_route_next(route);
1528 }
eacd0828 1529 if (use_json)
a49ef569 1530 json_object_object_add(json, "routes", json_routes);
4846ef64 1531}
1532
d62a17ae 1533static void ospf6_route_show_table(struct vty *vty, int detail,
eacd0828
YR
1534 struct ospf6_route_table *table,
1535 json_object *json, bool use_json)
4846ef64 1536{
d62a17ae 1537 struct ospf6_route *route;
a49ef569 1538 json_object *json_routes = NULL;
d62a17ae 1539
1540 route = ospf6_route_head(table);
eacd0828 1541 if (use_json)
a49ef569 1542 json_routes = json_object_new_object();
d62a17ae 1543 while (route) {
1544 if (detail)
a49ef569 1545 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1546 use_json);
d62a17ae 1547 else
a49ef569 1548 ospf6_route_show(vty, route, json_routes, use_json);
d62a17ae 1549 route = ospf6_route_next(route);
1550 }
eacd0828 1551 if (use_json)
a49ef569 1552 json_object_object_add(json, "routes", json_routes);
718e3744 1553}
1554
d62a17ae 1555int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
1556 struct cmd_token **argv,
eacd0828 1557 struct ospf6_route_table *table, bool use_json)
718e3744 1558{
d62a17ae 1559 int summary = 0;
1560 int match = 0;
1561 int detail = 0;
1562 int slash = 0;
1563 int isprefix = 0;
1564 int i, ret;
1565 struct prefix prefix;
d7c0a89a 1566 uint8_t type = 0;
eacd0828
YR
1567 int arg_end = use_json ? (argc - 1) : argc;
1568 json_object *json = NULL;
d62a17ae 1569
6006b807 1570 memset(&prefix, 0, sizeof(prefix));
d62a17ae 1571
eacd0828
YR
1572 if (use_json)
1573 json = json_object_new_object();
1574
1575 for (i = argc_start; i < arg_end; i++) {
d62a17ae 1576 if (strmatch(argv[i]->text, "summary")) {
1577 summary++;
1578 continue;
1579 }
1580
1581 if (strmatch(argv[i]->text, "intra-area")) {
1582 type = OSPF6_PATH_TYPE_INTRA;
1583 continue;
1584 }
1585
1586 if (strmatch(argv[i]->text, "inter-area")) {
1587 type = OSPF6_PATH_TYPE_INTER;
1588 continue;
1589 }
1590
1591 if (strmatch(argv[i]->text, "external-1")) {
1592 type = OSPF6_PATH_TYPE_EXTERNAL1;
1593 continue;
1594 }
1595
1596 if (strmatch(argv[i]->text, "external-2")) {
1597 type = OSPF6_PATH_TYPE_EXTERNAL2;
1598 continue;
1599 }
1600
1601 if (strmatch(argv[i]->text, "detail")) {
1602 detail++;
1603 continue;
1604 }
1605
1606 if (strmatch(argv[i]->text, "match")) {
1607 match++;
1608 continue;
1609 }
1610
1611 ret = str2prefix(argv[i]->arg, &prefix);
1612 if (ret == 1 && prefix.family == AF_INET6) {
1613 isprefix++;
1614 if (strchr(argv[i]->arg, '/'))
1615 slash++;
1616 continue;
1617 }
eacd0828
YR
1618 if (use_json)
1619 json_object_string_add(json, "malformedArgument",
1620 argv[i]->arg);
1621 else
1622 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
d62a17ae 1623
d62a17ae 1624 return CMD_SUCCESS;
1625 }
1626
1627 /* Give summary of this route table */
1628 if (summary) {
eacd0828 1629 ospf6_route_show_table_summary(vty, table, json, use_json);
c48349e3 1630 if (use_json)
5a6c232b 1631 vty_json(vty, json);
d62a17ae 1632 return CMD_SUCCESS;
1633 }
1634
1635 /* Give exact prefix-match route */
1636 if (isprefix && !match) {
1637 /* If exact address, give best matching route */
1638 if (!slash)
eacd0828
YR
1639 ospf6_route_show_table_address(vty, &prefix, table,
1640 json, use_json);
d62a17ae 1641 else
eacd0828
YR
1642 ospf6_route_show_table_prefix(vty, &prefix, table, json,
1643 use_json);
1644
c48349e3 1645 if (use_json)
5a6c232b 1646 vty_json(vty, json);
d62a17ae 1647 return CMD_SUCCESS;
1648 }
1649
1650 if (match)
eacd0828
YR
1651 ospf6_route_show_table_match(vty, detail, &prefix, table, json,
1652 use_json);
d62a17ae 1653 else if (type)
eacd0828
YR
1654 ospf6_route_show_table_type(vty, detail, type, table, json,
1655 use_json);
d62a17ae 1656 else
eacd0828 1657 ospf6_route_show_table(vty, detail, table, json, use_json);
d62a17ae 1658
c48349e3 1659 if (use_json)
5a6c232b 1660 vty_json(vty, json);
d62a17ae 1661 return CMD_SUCCESS;
4846ef64 1662}
508e53e2 1663
d62a17ae 1664static void ospf6_linkstate_show_header(struct vty *vty)
4846ef64 1665{
d62a17ae 1666 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %s\n", "Type", "Router-ID",
1667 "Net-ID", "Rtr-Bits", "Options", "Cost");
4846ef64 1668}
1669
d62a17ae 1670static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route)
4846ef64 1671{
d7c0a89a 1672 uint32_t router, id;
6cb85350 1673 char routername[16], idname[16], rbits[16], options[32];
d62a17ae 1674
1675 router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1676 inet_ntop(AF_INET, &router, routername, sizeof(routername));
1677 id = ospf6_linkstate_prefix_id(&route->prefix);
1678 inet_ntop(AF_INET, &id, idname, sizeof(idname));
1679
1680 ospf6_capability_printbuf(route->path.router_bits, rbits,
1681 sizeof(rbits));
1682 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1683
1684 if (ntohl(id))
1685 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Network",
1686 routername, idname, rbits, options,
1687 (unsigned long)route->path.cost);
1688 else
1689 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Router",
1690 routername, idname, rbits, options,
1691 (unsigned long)route->path.cost);
4846ef64 1692}
1693
1694
d62a17ae 1695static void ospf6_linkstate_show_table_exact(struct vty *vty,
1696 struct prefix *prefix,
1697 struct ospf6_route_table *table)
4846ef64 1698{
d62a17ae 1699 struct ospf6_route *route;
1700
1701 route = ospf6_route_lookup(prefix, table);
1702 if (route == NULL)
1703 return;
1704
1705 ospf6_route_lock(route);
1706 while (route && ospf6_route_is_prefix(prefix, route)) {
1707 /* Specifying a prefix will always display details */
eacd0828 1708 ospf6_route_show_detail(vty, route, NULL, false);
d62a17ae 1709 route = ospf6_route_next(route);
1710 }
1711 if (route)
1712 ospf6_route_unlock(route);
4846ef64 1713}
1714
d62a17ae 1715static void ospf6_linkstate_show_table(struct vty *vty, int detail,
1716 struct ospf6_route_table *table)
4846ef64 1717{
d62a17ae 1718 struct ospf6_route *route;
1719
1720 if (!detail)
1721 ospf6_linkstate_show_header(vty);
1722
1723 route = ospf6_route_head(table);
1724 while (route) {
1725 if (detail)
eacd0828 1726 ospf6_route_show_detail(vty, route, NULL, false);
d62a17ae 1727 else
1728 ospf6_linkstate_show(vty, route);
1729 route = ospf6_route_next(route);
1730 }
718e3744 1731}
1732
d62a17ae 1733int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
1734 struct cmd_token **argv,
1735 struct ospf6_route_table *table)
718e3744 1736{
d62a17ae 1737 int detail = 0;
1738 int is_id = 0;
1739 int is_router = 0;
1740 int i, ret;
1741 struct prefix router, id, prefix;
1742
6006b807
DA
1743 memset(&router, 0, sizeof(router));
1744 memset(&id, 0, sizeof(id));
1745 memset(&prefix, 0, sizeof(prefix));
d62a17ae 1746
1747 for (i = idx_ipv4; i < argc; i++) {
1748 if (strmatch(argv[i]->text, "detail")) {
1749 detail++;
1750 continue;
1751 }
1752
1753 if (!is_router) {
1754 ret = str2prefix(argv[i]->arg, &router);
1755 if (ret == 1 && router.family == AF_INET) {
1756 is_router++;
1757 continue;
1758 }
1759 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1760 return CMD_SUCCESS;
1761 }
1762
1763 if (!is_id) {
1764 ret = str2prefix(argv[i]->arg, &id);
1765 if (ret == 1 && id.family == AF_INET) {
1766 is_id++;
1767 continue;
1768 }
1769 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1770 return CMD_SUCCESS;
1771 }
1772
1773 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1774 return CMD_SUCCESS;
1775 }
1776
1777 if (is_router)
1778 ospf6_linkstate_prefix(router.u.prefix4.s_addr,
1779 id.u.prefix4.s_addr, &prefix);
1780
1781 if (prefix.family)
1782 ospf6_linkstate_show_table_exact(vty, &prefix, table);
1783 else
1784 ospf6_linkstate_show_table(vty, detail, table);
1785
1786 return CMD_SUCCESS;
508e53e2 1787}
718e3744 1788
4846ef64 1789
d62a17ae 1790void ospf6_brouter_show_header(struct vty *vty)
6452df09 1791{
d62a17ae 1792 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", "Router-ID", "Rtr-Bits",
1793 "Options", "Path-Type", "Area");
6452df09 1794}
1795
d62a17ae 1796void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route)
6452df09 1797{
d7c0a89a 1798 uint32_t adv_router;
6cb85350 1799 char adv[16], rbits[16], options[32], area[16];
d62a17ae 1800
1801 adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1802 inet_ntop(AF_INET, &adv_router, adv, sizeof(adv));
1803 ospf6_capability_printbuf(route->path.router_bits, rbits,
1804 sizeof(rbits));
1805 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1806 inet_ntop(AF_INET, &route->path.area_id, area, sizeof(area));
1807
1808 /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s\n",
1809 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area"); */
1810 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", adv, rbits, options,
1811 OSPF6_PATH_TYPE_NAME(route->path.type), area);
6452df09 1812}
1813
d5cb3508
YR
1814DEFPY(debug_ospf6_route,
1815 debug_ospf6_route_cmd,
1816 "[no$no] debug ospf6 route <all|table|intra-area|inter-area|memory>",
1817 NO_STR
1818 DEBUG_STR
1819 OSPF6_STR
1820 "Debug routes\n"
1821 "Debug for all types of route calculation\n"
1822 "Debug route table calculation\n"
1823 "Debug intra-area route calculation\n"
1824 "Debug inter-area route calculation\n"
1825 "Debug route memory use\n")
508e53e2 1826{
d5cb3508 1827 int idx_type;
d62a17ae 1828 unsigned char level = 0;
1829
d5cb3508 1830 idx_type = ((no) ? 4 : 3);
d62a17ae 1831
d5cb3508
YR
1832 if (!strcmp(argv[idx_type]->text, "all"))
1833 level = OSPF6_DEBUG_ROUTE_ALL;
1834 else if (!strcmp(argv[idx_type]->text, "table"))
d62a17ae 1835 level = OSPF6_DEBUG_ROUTE_TABLE;
8034beff 1836 else if (!strcmp(argv[idx_type]->text, "intra-area"))
d62a17ae 1837 level = OSPF6_DEBUG_ROUTE_INTRA;
8034beff 1838 else if (!strcmp(argv[idx_type]->text, "inter-area"))
d62a17ae 1839 level = OSPF6_DEBUG_ROUTE_INTER;
8034beff 1840 else if (!strcmp(argv[idx_type]->text, "memory"))
d62a17ae 1841 level = OSPF6_DEBUG_ROUTE_MEMORY;
d5cb3508
YR
1842
1843 if (no)
1844 OSPF6_DEBUG_ROUTE_OFF(level);
1845 else
1846 OSPF6_DEBUG_ROUTE_ON(level);
d62a17ae 1847 return CMD_SUCCESS;
718e3744 1848}
1849
d62a17ae 1850int config_write_ospf6_debug_route(struct vty *vty)
508e53e2 1851{
d5cb3508
YR
1852 if (IS_OSPF6_DEBUG_ROUTE(ALL) == OSPF6_DEBUG_ROUTE_ALL) {
1853 vty_out(vty, "debug ospf6 route all\n");
1854 return 0;
1855 }
d62a17ae 1856 if (IS_OSPF6_DEBUG_ROUTE(TABLE))
1857 vty_out(vty, "debug ospf6 route table\n");
1858 if (IS_OSPF6_DEBUG_ROUTE(INTRA))
1859 vty_out(vty, "debug ospf6 route intra-area\n");
1860 if (IS_OSPF6_DEBUG_ROUTE(INTER))
1861 vty_out(vty, "debug ospf6 route inter-area\n");
6f7af48c
CS
1862 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
1863 vty_out(vty, "debug ospf6 route memory\n");
1864
d62a17ae 1865 return 0;
508e53e2 1866}
1867
d62a17ae 1868void install_element_ospf6_debug_route(void)
508e53e2 1869{
d62a17ae 1870 install_element(ENABLE_NODE, &debug_ospf6_route_cmd);
d62a17ae 1871 install_element(CONFIG_NODE, &debug_ospf6_route_cmd);
508e53e2 1872}