]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_route.c
build, vtysh: extract vtysh commands from .xref
[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) {
d62a17ae 705 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
996c9314 706 zlog_debug(
6942698d 707 "%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
996c9314 708 ospf6_route_table_name(table), (void *)table,
03f3c1c1 709 (void *)route, route->path.cost,
6942698d 710 listcount(route->paths),
03f3c1c1 711 listcount(route->nh_list), (void *)old,
6942698d
CS
712 old->path.cost, listcount(old->paths),
713 listcount(old->nh_list));
d62a17ae 714 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
715 zlog_debug("%s: route add: update",
716 ospf6_route_table_name(table));
717
718 /* replace old one if exists */
719 if (node->info == old) {
720 node->info = route;
721 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
35769de4
K
722 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
723 zlog_debug("%s: replace old route %s",
724 __func__, buf);
d62a17ae 725 }
726
727 if (old->prev)
728 old->prev->next = route;
729 route->prev = old->prev;
730 if (old->next)
731 old->next->prev = route;
732 route->next = old->next;
733
734 route->installed = old->installed;
735 route->changed = now;
736 assert(route->table == NULL);
737 route->table = table;
738
739 ospf6_route_unlock(old); /* will be deleted later */
740 ospf6_route_lock(route);
741
742 SET_FLAG(route->flag, OSPF6_ROUTE_CHANGE);
743 ospf6_route_table_assert(table);
744
745 if (table->hook_add)
e285b70d 746 (*table->hook_add)(route);
d62a17ae 747
748 return route;
749 }
750
751 /* insert if previous or next node found */
752 if (prev || next) {
753 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
754 zlog_debug(
07b37f93 755 "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u",
d62a17ae 756 ospf6_route_table_name(table), (void *)table,
07b37f93 757 (void *)route, route->path.cost, (void *)prev,
c10e14e9 758 (void *)next, route_node_get_lock_count(node));
d62a17ae 759 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
07b37f93
CS
760 zlog_debug("%s: route add cost %u: another path found",
761 ospf6_route_table_name(table),
762 route->path.cost);
d62a17ae 763
764 if (prev == NULL)
765 prev = next->prev;
766 if (next == NULL)
767 next = prev->next;
768
769 if (prev)
770 prev->next = route;
771 route->prev = prev;
772 if (next)
773 next->prev = route;
774 route->next = next;
775
776 if (node->info == next) {
4f4060f6 777 assert(next && next->rnode == node);
d62a17ae 778 node->info = route;
779 UNSET_FLAG(next->flag, OSPF6_ROUTE_BEST);
780 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
781 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
35769de4 782 zlog_debug(
c601fa3f 783 "%s %p: route add %p cost %u: replacing previous best: %p cost %u",
d62a17ae 784 ospf6_route_table_name(table),
785 (void *)table, (void *)route,
35769de4
K
786 route->path.cost, (void *)next,
787 next->path.cost);
d62a17ae 788 }
789
790 route->installed = now;
791 route->changed = now;
792 assert(route->table == NULL);
793 route->table = table;
794
795 ospf6_route_lock(route);
796 table->count++;
797 ospf6_route_table_assert(table);
798
799 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
800 if (table->hook_add)
e285b70d 801 (*table->hook_add)(route);
d62a17ae 802
803 return route;
804 }
805
806 /* Else, this is the brand new route regarding to the prefix */
807 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
c601fa3f 808 zlog_debug("%s %p: route add %p %s cost %u: brand new route",
d62a17ae 809 ospf6_route_table_name(table), (void *)table,
c601fa3f 810 (void *)route, buf, route->path.cost);
d62a17ae 811 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
812 zlog_debug("%s: route add: brand new route",
813 ospf6_route_table_name(table));
814
815 assert(node->info == NULL);
816 node->info = route;
817 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
818 ospf6_route_lock(route);
819 route->installed = now;
820 route->changed = now;
821 assert(route->table == NULL);
822 route->table = table;
823
824 /* lookup real existing next route */
825 nextnode = node;
826 route_lock_node(nextnode);
827 do {
828 nextnode = route_next(nextnode);
829 } while (nextnode && nextnode->info == NULL);
830
831 /* set next link */
832 if (nextnode == NULL)
833 route->next = NULL;
834 else {
835 route_unlock_node(nextnode);
836
837 next = nextnode->info;
838 route->next = next;
839 next->prev = route;
840 }
841
842 /* lookup real existing prev route */
843 prevnode = node;
844 route_lock_node(prevnode);
845 do {
846 prevnode = route_prev(prevnode);
847 } while (prevnode && prevnode->info == NULL);
848
849 /* set prev link */
850 if (prevnode == NULL)
851 route->prev = NULL;
852 else {
853 route_unlock_node(prevnode);
854
855 prev = prevnode->info;
856 while (prev->next && ospf6_route_is_same(prev, prev->next))
857 prev = prev->next;
858 route->prev = prev;
859 prev->next = route;
860 }
861
862 table->count++;
863 ospf6_route_table_assert(table);
864
865 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
866 if (table->hook_add)
e285b70d 867 (*table->hook_add)(route);
d62a17ae 868
869 return route;
508e53e2 870}
718e3744 871
d62a17ae 872void ospf6_route_remove(struct ospf6_route *route,
e285b70d 873 struct ospf6_route_table *table)
508e53e2 874{
d62a17ae 875 struct route_node *node;
876 struct ospf6_route *current;
877 char buf[PREFIX2STR_BUFFER];
878
879 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
880 ospf6_linkstate_prefix2str(&route->prefix, buf, sizeof(buf));
9142948e
RW
881 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
882 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
883 sizeof(buf));
d62a17ae 884 else
885 prefix2str(&route->prefix, buf, sizeof(buf));
886
887 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
07b37f93 888 zlog_debug("%s %p: route remove %p: %s cost %u refcount %u",
d62a17ae 889 ospf6_route_table_name(table), (void *)table,
07b37f93 890 (void *)route, buf, route->path.cost, route->lock);
d62a17ae 891 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
892 zlog_debug("%s: route remove: %s",
893 ospf6_route_table_name(table), buf);
894
895 node = route_node_lookup(table->table, &route->prefix);
896 assert(node);
897
898 /* find the route to remove, making sure that the route pointer
899 is from the route table. */
900 current = node->info;
d107621d 901 while (current && current != route)
d62a17ae 902 current = current->next;
d107621d 903
d62a17ae 904 assert(current == route);
905
906 /* adjust doubly linked list */
907 if (route->prev)
908 route->prev->next = route->next;
909 if (route->next)
910 route->next->prev = route->prev;
911
912 if (node->info == route) {
913 if (route->next && route->next->rnode == node) {
914 node->info = route->next;
915 SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST);
35769de4
K
916 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
917 zlog_debug("%s: remove route %s", __func__,
918 buf);
d107621d
CS
919 } else {
920 node->info = NULL;
921 route->rnode = NULL;
922 route_unlock_node(node); /* to free the original lock */
923 }
d62a17ae 924 }
508e53e2 925
d107621d 926 route_unlock_node(node); /* to free the lookup lock */
d62a17ae 927 table->count--;
928 ospf6_route_table_assert(table);
718e3744 929
d62a17ae 930 SET_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED);
508e53e2 931
dd2395e1 932 /* Note hook_remove may call ospf6_route_remove */
d62a17ae 933 if (table->hook_remove)
e285b70d 934 (*table->hook_remove)(route);
cf1ce250 935
d62a17ae 936 ospf6_route_unlock(route);
937}
cf1ce250 938
d62a17ae 939struct ospf6_route *ospf6_route_head(struct ospf6_route_table *table)
940{
941 struct route_node *node;
942 struct ospf6_route *route;
943
944 node = route_top(table->table);
945 if (node == NULL)
946 return NULL;
947
948 /* skip to the real existing entry */
949 while (node && node->info == NULL)
950 node = route_next(node);
951 if (node == NULL)
952 return NULL;
953
954 route_unlock_node(node);
955 assert(node->info);
956
957 route = (struct ospf6_route *)node->info;
958 assert(route->prev == NULL);
959 assert(route->table == table);
960 ospf6_route_lock(route);
961
962 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
963 zlog_info("%s %p: route head: %p<-[%p]->%p",
964 ospf6_route_table_name(table), (void *)table,
965 (void *)route->prev, (void *)route,
966 (void *)route->next);
967
968 return route;
718e3744 969}
970
d62a17ae 971struct ospf6_route *ospf6_route_next(struct ospf6_route *route)
718e3744 972{
d62a17ae 973 struct ospf6_route *next = route->next;
718e3744 974
d62a17ae 975 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
a2d0055a 976 zlog_info("%s %p: route next: %p<-[%p]->%p , route ref count %u",
d62a17ae 977 ospf6_route_table_name(route->table),
978 (void *)route->table, (void *)route->prev,
a2d0055a
CS
979 (void *)route, (void *)route->next,
980 route->lock);
cf1ce250 981
d62a17ae 982 ospf6_route_unlock(route);
983 if (next)
984 ospf6_route_lock(next);
718e3744 985
d62a17ae 986 return next;
508e53e2 987}
718e3744 988
d62a17ae 989struct ospf6_route *ospf6_route_best_next(struct ospf6_route *route)
508e53e2 990{
d62a17ae 991 struct route_node *rnode;
992 struct ospf6_route *next;
993
994 ospf6_route_unlock(route);
995
996 rnode = route->rnode;
997 route_lock_node(rnode);
998 rnode = route_next(rnode);
999 while (rnode && rnode->info == NULL)
1000 rnode = route_next(rnode);
1001 if (rnode == NULL)
1002 return NULL;
1003 route_unlock_node(rnode);
1004
1005 assert(rnode->info);
1006 next = (struct ospf6_route *)rnode->info;
1007 ospf6_route_lock(next);
1008 return next;
508e53e2 1009}
718e3744 1010
d62a17ae 1011struct ospf6_route *ospf6_route_match_head(struct prefix *prefix,
1012 struct ospf6_route_table *table)
508e53e2 1013{
d62a17ae 1014 struct route_node *node;
1015 struct ospf6_route *route;
1016
1017 /* Walk down tree. */
1018 node = table->table->top;
1019 while (node && node->p.prefixlen < prefix->prefixlen
1020 && prefix_match(&node->p, prefix))
1021 node = node->link[prefix_bit(&prefix->u.prefix,
1022 node->p.prefixlen)];
1023
1024 if (node)
1025 route_lock_node(node);
1026 while (node && node->info == NULL)
1027 node = route_next(node);
1028 if (node == NULL)
1029 return NULL;
1030 route_unlock_node(node);
1031
1032 if (!prefix_match(prefix, &node->p))
1033 return NULL;
1034
1035 route = node->info;
1036 ospf6_route_lock(route);
1037 return route;
508e53e2 1038}
718e3744 1039
d62a17ae 1040struct ospf6_route *ospf6_route_match_next(struct prefix *prefix,
1041 struct ospf6_route *route)
508e53e2 1042{
d62a17ae 1043 struct ospf6_route *next;
508e53e2 1044
d62a17ae 1045 next = ospf6_route_next(route);
1046 if (next && !prefix_match(prefix, &next->prefix)) {
1047 ospf6_route_unlock(next);
1048 next = NULL;
1049 }
508e53e2 1050
d62a17ae 1051 return next;
718e3744 1052}
1053
e285b70d 1054void ospf6_route_remove_all(struct ospf6_route_table *table)
718e3744 1055{
d62a17ae 1056 struct ospf6_route *route;
1057 for (route = ospf6_route_head(table); route;
1058 route = ospf6_route_next(route))
e285b70d 1059 ospf6_route_remove(route, table);
718e3744 1060}
1061
d62a17ae 1062struct ospf6_route_table *ospf6_route_table_create(int s, int t)
718e3744 1063{
d62a17ae 1064 struct ospf6_route_table *new;
de4a0bda
PR
1065 new = XCALLOC(MTYPE_OSPF6_ROUTE_TABLE,
1066 sizeof(struct ospf6_route_table));
d62a17ae 1067 new->table = route_table_init();
1068 new->scope_type = s;
1069 new->table_type = t;
1070 return new;
718e3744 1071}
1072
e285b70d 1073void ospf6_route_table_delete(struct ospf6_route_table *table)
718e3744 1074{
e285b70d 1075 ospf6_route_remove_all(table);
d62a17ae 1076 route_table_finish(table->table);
de4a0bda 1077 XFREE(MTYPE_OSPF6_ROUTE_TABLE, table);
718e3744 1078}
1079
6b0655a2 1080
508e53e2 1081/* VTY commands */
eacd0828 1082void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
a49ef569 1083 json_object *json_routes, bool use_json)
718e3744 1084{
d62a17ae 1085 int i;
1086 char destination[PREFIX2STR_BUFFER], nexthop[64];
68bfcc05 1087 char duration[64];
d62a17ae 1088 struct timeval now, res;
1089 struct listnode *node;
1090 struct ospf6_nexthop *nh;
eacd0828
YR
1091 json_object *json_route = NULL;
1092 json_object *json_array_next_hops = NULL;
1093 json_object *json_next_hop;
dbbcd516 1094 vrf_id_t vrf_id = route->ospf6->vrf_id;
d62a17ae 1095
1096 monotime(&now);
1097 timersub(&now, &route->changed, &res);
1098 timerstring(&res, duration, sizeof(duration));
1099
1100 /* destination */
1101 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1102 ospf6_linkstate_prefix2str(&route->prefix, destination,
1103 sizeof(destination));
1104 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1105 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1106 destination, sizeof(destination));
1107 else
1108 prefix2str(&route->prefix, destination, sizeof(destination));
1109
eacd0828
YR
1110 if (use_json) {
1111 json_route = json_object_new_object();
eacd0828
YR
1112 json_object_boolean_add(json_route, "isBestRoute",
1113 ospf6_route_is_best(route));
1114 json_object_string_add(json_route, "destinationType",
1115 OSPF6_DEST_TYPE_SUBSTR(route->type));
1116 json_object_string_add(
1117 json_route, "pathType",
1118 OSPF6_PATH_TYPE_SUBSTR(route->path.type));
1119 json_object_string_add(json_route, "duration", duration);
1120 }
1121
1122 /* Nexthops */
1123 if (use_json)
1124 json_array_next_hops = json_object_new_array();
1125 else
1126 i = 0;
d62a17ae 1127 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
1128 /* nexthop */
1129 inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
eacd0828
YR
1130 if (use_json) {
1131 json_next_hop = json_object_new_object();
1132 json_object_string_add(json_next_hop, "nextHop",
1133 nexthop);
dbbcd516
IR
1134 json_object_string_add(
1135 json_next_hop, "interfaceName",
1136 ifindex2ifname(nh->ifindex, vrf_id));
eacd0828
YR
1137 json_object_array_add(json_array_next_hops,
1138 json_next_hop);
1139 } else {
1140 if (!i) {
1141 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1142 (ospf6_route_is_best(route) ? '*'
1143 : ' '),
1144 OSPF6_DEST_TYPE_SUBSTR(route->type),
1145 OSPF6_PATH_TYPE_SUBSTR(
1146 route->path.type),
1147 destination, nexthop, IFNAMSIZ,
dbbcd516
IR
1148 ifindex2ifname(nh->ifindex, vrf_id),
1149 duration);
eacd0828
YR
1150 i++;
1151 } else
1152 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1153 ' ', "", "", "", nexthop, IFNAMSIZ,
dbbcd516
IR
1154 ifindex2ifname(nh->ifindex, vrf_id),
1155 "");
eacd0828
YR
1156 }
1157 }
1158 if (use_json) {
1159 json_object_object_add(json_route, "nextHops",
1160 json_array_next_hops);
a49ef569 1161 json_object_object_add(json_routes, destination, json_route);
c3c0ac83 1162 }
718e3744 1163}
1164
eacd0828 1165void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
a49ef569 1166 json_object *json_routes, bool use_json)
718e3744 1167{
eacd0828 1168 char destination[PREFIX2STR_BUFFER], nexthop[64];
6cb85350 1169 char area_id[16], id[16], adv_router[16], capa[16], options[32];
b0822151 1170 char pfx_options[16];
d62a17ae 1171 struct timeval now, res;
68bfcc05 1172 char duration[64];
d62a17ae 1173 struct listnode *node;
1174 struct ospf6_nexthop *nh;
eacd0828
YR
1175 char flag[6];
1176 json_object *json_route = NULL;
1177 json_object *json_array_next_hops = NULL;
1178 json_object *json_next_hop;
dbbcd516 1179 vrf_id_t vrf_id = route->ospf6->vrf_id;
d62a17ae 1180
1181 monotime(&now);
1182
1183 /* destination */
1184 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1185 ospf6_linkstate_prefix2str(&route->prefix, destination,
1186 sizeof(destination));
1187 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1188 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1189 destination, sizeof(destination));
1190 else
1191 prefix2str(&route->prefix, destination, sizeof(destination));
d62a17ae 1192
eacd0828
YR
1193 if (use_json) {
1194 json_route = json_object_new_object();
eacd0828
YR
1195 json_object_string_add(json_route, "destinationType",
1196 OSPF6_DEST_TYPE_NAME(route->type));
1197 } else {
1198 vty_out(vty, "Destination: %s\n", destination);
1199 vty_out(vty, "Destination type: %s\n",
1200 OSPF6_DEST_TYPE_NAME(route->type));
1201 }
d62a17ae 1202
1203 /* Time */
1204 timersub(&now, &route->installed, &res);
1205 timerstring(&res, duration, sizeof(duration));
eacd0828
YR
1206 if (use_json)
1207 json_object_string_add(json_route, "installedTimeSince",
1208 duration);
1209 else
1210 vty_out(vty, "Installed Time: %s ago\n", duration);
d62a17ae 1211
1212 timersub(&now, &route->changed, &res);
1213 timerstring(&res, duration, sizeof(duration));
eacd0828
YR
1214 if (use_json)
1215 json_object_string_add(json_route, "changedTimeSince",
1216 duration);
1217 else
1218 vty_out(vty, "Changed Time: %s ago\n", duration);
d62a17ae 1219
1220 /* Debugging info */
eacd0828
YR
1221 if (use_json) {
1222 json_object_int_add(json_route, "numberOfLock", route->lock);
1223 snprintf(
1224 flag, sizeof(flag), "%s%s%s%s",
1225 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1226 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1227 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1228 : "-"),
1229 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1230 : "-"));
1231 json_object_string_add(json_route, "flags", flag);
1232 } else {
1233 vty_out(vty, "Lock: %d Flags: %s%s%s%s\n", route->lock,
1234 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1235 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1236 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1237 : "-"),
1238 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1239 : "-"));
1240 vty_out(vty, "Memory: prev: %p this: %p next: %p\n",
1241 (void *)route->prev, (void *)route,
1242 (void *)route->next);
1243 }
d62a17ae 1244
1245 /* Path section */
1246
1247 /* Area-ID */
1248 inet_ntop(AF_INET, &route->path.area_id, area_id, sizeof(area_id));
eacd0828
YR
1249 if (use_json)
1250 json_object_string_add(json_route, "associatedArea", area_id);
1251 else
1252 vty_out(vty, "Associated Area: %s\n", area_id);
d62a17ae 1253
1254 /* Path type */
eacd0828
YR
1255 if (use_json)
1256 json_object_string_add(json_route, "pathType",
1257 OSPF6_PATH_TYPE_NAME(route->path.type));
1258 else
1259 vty_out(vty, "Path Type: %s\n",
1260 OSPF6_PATH_TYPE_NAME(route->path.type));
d62a17ae 1261
1262 /* LS Origin */
1263 inet_ntop(AF_INET, &route->path.origin.id, id, sizeof(id));
1264 inet_ntop(AF_INET, &route->path.origin.adv_router, adv_router,
1265 sizeof(adv_router));
eacd0828
YR
1266 if (use_json) {
1267 json_object_string_add(
1268 json_route, "lsOriginRoutePathType",
1269 ospf6_lstype_name(route->path.origin.type));
1270 json_object_string_add(json_route, "lsId", id);
1271 json_object_string_add(json_route, "lsAdvertisingRouter",
1272 adv_router);
1273 } else {
1274 vty_out(vty, "LS Origin: %s Id: %s Adv: %s\n",
1275 ospf6_lstype_name(route->path.origin.type), id,
1276 adv_router);
1277 }
d62a17ae 1278
1279 /* Options */
1280 ospf6_options_printbuf(route->path.options, options, sizeof(options));
eacd0828
YR
1281 if (use_json)
1282 json_object_string_add(json_route, "options", options);
1283 else
1284 vty_out(vty, "Options: %s\n", options);
d62a17ae 1285
1286 /* Router Bits */
1287 ospf6_capability_printbuf(route->path.router_bits, capa, sizeof(capa));
eacd0828
YR
1288 if (use_json)
1289 json_object_string_add(json_route, "routerBits", capa);
1290 else
1291 vty_out(vty, "Router Bits: %s\n", capa);
d62a17ae 1292
1293 /* Prefix Options */
b0822151
DL
1294 ospf6_prefix_options_printbuf(route->prefix_options, pfx_options,
1295 sizeof(pfx_options));
eacd0828 1296 if (use_json)
b0822151
DL
1297 json_object_string_add(json_route, "prefixOptions",
1298 pfx_options);
eacd0828 1299 else
b0822151 1300 vty_out(vty, "Prefix Options: %s\n", pfx_options);
d62a17ae 1301
1302 /* Metrics */
eacd0828
YR
1303 if (use_json) {
1304 json_object_int_add(json_route, "metricType",
1305 route->path.metric_type);
1306 json_object_int_add(json_route, "metricCost", route->path.cost);
1307 json_object_int_add(json_route, "metricCostE2",
1308 route->path.u.cost_e2);
1309
1310 json_object_int_add(json_route, "pathsCount",
1311 route->paths->count);
1312 json_object_int_add(json_route, "nextHopCount",
1313 route->nh_list->count);
1314 } else {
1315 vty_out(vty, "Metric Type: %d\n", route->path.metric_type);
1316 vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
1317 route->path.u.cost_e2);
1318
1319 vty_out(vty, "Paths count: %u\n", route->paths->count);
1320 vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
1321 }
d62a17ae 1322
1323 /* Nexthops */
eacd0828
YR
1324 if (use_json)
1325 json_array_next_hops = json_object_new_array();
1326 else
1327 vty_out(vty, "Nexthop:\n");
1328
d62a17ae 1329 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
eacd0828
YR
1330 /* nexthop */
1331 if (use_json) {
1332 inet_ntop(AF_INET6, &nh->address, nexthop,
1333 sizeof(nexthop));
1334 json_next_hop = json_object_new_object();
1335 json_object_string_add(json_next_hop, "nextHop",
1336 nexthop);
dbbcd516
IR
1337 json_object_string_add(
1338 json_next_hop, "interfaceName",
1339 ifindex2ifname(nh->ifindex, vrf_id));
eacd0828
YR
1340 json_object_array_add(json_array_next_hops,
1341 json_next_hop);
1342 } else
1343 vty_out(vty, " %pI6 %.*s\n", &nh->address, IFNAMSIZ,
dbbcd516 1344 ifindex2ifname(nh->ifindex, vrf_id));
d62a17ae 1345 }
eacd0828
YR
1346 if (use_json) {
1347 json_object_object_add(json_route, "nextHops",
1348 json_array_next_hops);
a49ef569 1349 json_object_object_add(json_routes, destination, json_route);
eacd0828
YR
1350 } else
1351 vty_out(vty, "\n");
508e53e2 1352}
718e3744 1353
d62a17ae 1354static void ospf6_route_show_table_summary(struct vty *vty,
eacd0828
YR
1355 struct ospf6_route_table *table,
1356 json_object *json, bool use_json)
508e53e2 1357{
d62a17ae 1358 struct ospf6_route *route, *prev = NULL;
1359 int i, pathtype[OSPF6_PATH_TYPE_MAX];
1360 unsigned int number = 0;
1361 int nh_count = 0, nhinval = 0, ecmp = 0;
1362 int alternative = 0, destination = 0;
eacd0828 1363 char path_str[30];
d62a17ae 1364
1365 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
1366 pathtype[i] = 0;
1367
1368 for (route = ospf6_route_head(table); route;
1369 route = ospf6_route_next(route)) {
1370 if (prev == NULL || !ospf6_route_is_same(prev, route))
1371 destination++;
1372 else
1373 alternative++;
1374 nh_count = ospf6_num_nexthops(route->nh_list);
1375 if (!nh_count)
1376 nhinval++;
1377 else if (nh_count > 1)
1378 ecmp++;
1379 pathtype[route->path.type]++;
1380 number++;
1381
1382 prev = route;
1383 }
1384
1385 assert(number == table->count);
eacd0828
YR
1386 if (use_json) {
1387 json_object_int_add(json, "numberOfOspfv3Routes", number);
1388 json_object_int_add(json, "numberOfDestination", destination);
1389 json_object_int_add(json, "numberOfAlternativeRoutes",
1390 alternative);
1391 json_object_int_add(json, "numberOfEcmp", ecmp);
1392 } else {
1393 vty_out(vty, "Number of OSPFv3 routes: %d\n", number);
1394 vty_out(vty, "Number of Destination: %d\n", destination);
1395 vty_out(vty, "Number of Alternative routes: %d\n", alternative);
1396 vty_out(vty, "Number of Equal Cost Multi Path: %d\n", ecmp);
1397 }
d62a17ae 1398 for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) {
eacd0828
YR
1399 if (use_json) {
1400 snprintf(path_str, sizeof(path_str), "numberOf%sRoutes",
1401 OSPF6_PATH_TYPE_JSON(i));
1402 json_object_int_add(json, path_str, pathtype[i]);
1403 } else
1404 vty_out(vty, "Number of %s routes: %d\n",
1405 OSPF6_PATH_TYPE_NAME(i), pathtype[i]);
d62a17ae 1406 }
4846ef64 1407}
1408
d62a17ae 1409static void ospf6_route_show_table_prefix(struct vty *vty,
1410 struct prefix *prefix,
eacd0828
YR
1411 struct ospf6_route_table *table,
1412 json_object *json, bool use_json)
4846ef64 1413{
d62a17ae 1414 struct ospf6_route *route;
a49ef569 1415 json_object *json_routes = NULL;
d62a17ae 1416
1417 route = ospf6_route_lookup(prefix, table);
1418 if (route == NULL)
1419 return;
1420
eacd0828 1421 if (use_json)
a49ef569 1422 json_routes = json_object_new_object();
d62a17ae 1423 ospf6_route_lock(route);
1424 while (route && ospf6_route_is_prefix(prefix, route)) {
1425 /* Specifying a prefix will always display details */
a49ef569 1426 ospf6_route_show_detail(vty, route, json_routes, use_json);
d62a17ae 1427 route = ospf6_route_next(route);
1428 }
eacd0828
YR
1429
1430 if (use_json)
a49ef569 1431 json_object_object_add(json, "routes", json_routes);
d62a17ae 1432 if (route)
1433 ospf6_route_unlock(route);
4846ef64 1434}
1435
d62a17ae 1436static void ospf6_route_show_table_address(struct vty *vty,
1437 struct prefix *prefix,
eacd0828
YR
1438 struct ospf6_route_table *table,
1439 json_object *json, bool use_json)
4846ef64 1440{
d62a17ae 1441 struct ospf6_route *route;
a49ef569 1442 json_object *json_routes = NULL;
d62a17ae 1443
1444 route = ospf6_route_lookup_bestmatch(prefix, table);
1445 if (route == NULL)
1446 return;
1447
eacd0828 1448 if (use_json)
a49ef569 1449 json_routes = json_object_new_object();
d62a17ae 1450 prefix = &route->prefix;
1451 ospf6_route_lock(route);
1452 while (route && ospf6_route_is_prefix(prefix, route)) {
1453 /* Specifying a prefix will always display details */
a49ef569 1454 ospf6_route_show_detail(vty, route, json_routes, use_json);
d62a17ae 1455 route = ospf6_route_next(route);
1456 }
eacd0828 1457 if (use_json)
a49ef569 1458 json_object_object_add(json, "routes", json_routes);
d62a17ae 1459 if (route)
1460 ospf6_route_unlock(route);
4846ef64 1461}
1462
d62a17ae 1463static void ospf6_route_show_table_match(struct vty *vty, int detail,
1464 struct prefix *prefix,
eacd0828
YR
1465 struct ospf6_route_table *table,
1466 json_object *json, bool use_json)
4846ef64 1467{
d62a17ae 1468 struct ospf6_route *route;
a49ef569 1469 json_object *json_routes = NULL;
eacd0828 1470
d62a17ae 1471 assert(prefix->family);
1472
1473 route = ospf6_route_match_head(prefix, table);
eacd0828 1474 if (use_json)
a49ef569 1475 json_routes = json_object_new_object();
d62a17ae 1476 while (route) {
1477 if (detail)
a49ef569 1478 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1479 use_json);
d62a17ae 1480 else
a49ef569 1481 ospf6_route_show(vty, route, json_routes, use_json);
d62a17ae 1482 route = ospf6_route_match_next(prefix, route);
1483 }
eacd0828 1484 if (use_json)
a49ef569 1485 json_object_object_add(json, "routes", json_routes);
4846ef64 1486}
1487
d62a17ae 1488static void ospf6_route_show_table_type(struct vty *vty, int detail,
d7c0a89a 1489 uint8_t type,
eacd0828
YR
1490 struct ospf6_route_table *table,
1491 json_object *json, bool use_json)
4846ef64 1492{
d62a17ae 1493 struct ospf6_route *route;
a49ef569 1494 json_object *json_routes = NULL;
d62a17ae 1495
1496 route = ospf6_route_head(table);
eacd0828 1497 if (use_json)
a49ef569 1498 json_routes = json_object_new_object();
d62a17ae 1499 while (route) {
1500 if (route->path.type == type) {
1501 if (detail)
a49ef569 1502 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1503 use_json);
d62a17ae 1504 else
a49ef569 1505 ospf6_route_show(vty, route, json_routes,
eacd0828 1506 use_json);
d62a17ae 1507 }
1508 route = ospf6_route_next(route);
1509 }
eacd0828 1510 if (use_json)
a49ef569 1511 json_object_object_add(json, "routes", json_routes);
4846ef64 1512}
1513
d62a17ae 1514static void ospf6_route_show_table(struct vty *vty, int detail,
eacd0828
YR
1515 struct ospf6_route_table *table,
1516 json_object *json, bool use_json)
4846ef64 1517{
d62a17ae 1518 struct ospf6_route *route;
a49ef569 1519 json_object *json_routes = NULL;
d62a17ae 1520
1521 route = ospf6_route_head(table);
eacd0828 1522 if (use_json)
a49ef569 1523 json_routes = json_object_new_object();
d62a17ae 1524 while (route) {
1525 if (detail)
a49ef569 1526 ospf6_route_show_detail(vty, route, json_routes,
eacd0828 1527 use_json);
d62a17ae 1528 else
a49ef569 1529 ospf6_route_show(vty, route, json_routes, use_json);
d62a17ae 1530 route = ospf6_route_next(route);
1531 }
eacd0828 1532 if (use_json)
a49ef569 1533 json_object_object_add(json, "routes", json_routes);
718e3744 1534}
1535
d62a17ae 1536int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
1537 struct cmd_token **argv,
eacd0828 1538 struct ospf6_route_table *table, bool use_json)
718e3744 1539{
d62a17ae 1540 int summary = 0;
1541 int match = 0;
1542 int detail = 0;
1543 int slash = 0;
1544 int isprefix = 0;
1545 int i, ret;
1546 struct prefix prefix;
d7c0a89a 1547 uint8_t type = 0;
eacd0828
YR
1548 int arg_end = use_json ? (argc - 1) : argc;
1549 json_object *json = NULL;
d62a17ae 1550
6006b807 1551 memset(&prefix, 0, sizeof(prefix));
d62a17ae 1552
eacd0828
YR
1553 if (use_json)
1554 json = json_object_new_object();
1555
1556 for (i = argc_start; i < arg_end; i++) {
d62a17ae 1557 if (strmatch(argv[i]->text, "summary")) {
1558 summary++;
1559 continue;
1560 }
1561
1562 if (strmatch(argv[i]->text, "intra-area")) {
1563 type = OSPF6_PATH_TYPE_INTRA;
1564 continue;
1565 }
1566
1567 if (strmatch(argv[i]->text, "inter-area")) {
1568 type = OSPF6_PATH_TYPE_INTER;
1569 continue;
1570 }
1571
1572 if (strmatch(argv[i]->text, "external-1")) {
1573 type = OSPF6_PATH_TYPE_EXTERNAL1;
1574 continue;
1575 }
1576
1577 if (strmatch(argv[i]->text, "external-2")) {
1578 type = OSPF6_PATH_TYPE_EXTERNAL2;
1579 continue;
1580 }
1581
1582 if (strmatch(argv[i]->text, "detail")) {
1583 detail++;
1584 continue;
1585 }
1586
1587 if (strmatch(argv[i]->text, "match")) {
1588 match++;
1589 continue;
1590 }
1591
1592 ret = str2prefix(argv[i]->arg, &prefix);
1593 if (ret == 1 && prefix.family == AF_INET6) {
1594 isprefix++;
1595 if (strchr(argv[i]->arg, '/'))
1596 slash++;
1597 continue;
1598 }
eacd0828
YR
1599 if (use_json)
1600 json_object_string_add(json, "malformedArgument",
1601 argv[i]->arg);
1602 else
1603 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
d62a17ae 1604
d62a17ae 1605 return CMD_SUCCESS;
1606 }
1607
1608 /* Give summary of this route table */
1609 if (summary) {
eacd0828 1610 ospf6_route_show_table_summary(vty, table, json, use_json);
c48349e3 1611 if (use_json)
5a6c232b 1612 vty_json(vty, json);
d62a17ae 1613 return CMD_SUCCESS;
1614 }
1615
1616 /* Give exact prefix-match route */
1617 if (isprefix && !match) {
1618 /* If exact address, give best matching route */
1619 if (!slash)
eacd0828
YR
1620 ospf6_route_show_table_address(vty, &prefix, table,
1621 json, use_json);
d62a17ae 1622 else
eacd0828
YR
1623 ospf6_route_show_table_prefix(vty, &prefix, table, json,
1624 use_json);
1625
c48349e3 1626 if (use_json)
5a6c232b 1627 vty_json(vty, json);
d62a17ae 1628 return CMD_SUCCESS;
1629 }
1630
1631 if (match)
eacd0828
YR
1632 ospf6_route_show_table_match(vty, detail, &prefix, table, json,
1633 use_json);
d62a17ae 1634 else if (type)
eacd0828
YR
1635 ospf6_route_show_table_type(vty, detail, type, table, json,
1636 use_json);
d62a17ae 1637 else
eacd0828 1638 ospf6_route_show_table(vty, detail, table, json, use_json);
d62a17ae 1639
c48349e3 1640 if (use_json)
5a6c232b 1641 vty_json(vty, json);
d62a17ae 1642 return CMD_SUCCESS;
4846ef64 1643}
508e53e2 1644
d62a17ae 1645static void ospf6_linkstate_show_header(struct vty *vty)
4846ef64 1646{
d62a17ae 1647 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %s\n", "Type", "Router-ID",
1648 "Net-ID", "Rtr-Bits", "Options", "Cost");
4846ef64 1649}
1650
d62a17ae 1651static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route)
4846ef64 1652{
d7c0a89a 1653 uint32_t router, id;
6cb85350 1654 char routername[16], idname[16], rbits[16], options[32];
d62a17ae 1655
1656 router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1657 inet_ntop(AF_INET, &router, routername, sizeof(routername));
1658 id = ospf6_linkstate_prefix_id(&route->prefix);
1659 inet_ntop(AF_INET, &id, idname, sizeof(idname));
1660
1661 ospf6_capability_printbuf(route->path.router_bits, rbits,
1662 sizeof(rbits));
1663 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1664
1665 if (ntohl(id))
1666 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Network",
1667 routername, idname, rbits, options,
1668 (unsigned long)route->path.cost);
1669 else
1670 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Router",
1671 routername, idname, rbits, options,
1672 (unsigned long)route->path.cost);
4846ef64 1673}
1674
1675
d62a17ae 1676static void ospf6_linkstate_show_table_exact(struct vty *vty,
1677 struct prefix *prefix,
1678 struct ospf6_route_table *table)
4846ef64 1679{
d62a17ae 1680 struct ospf6_route *route;
1681
1682 route = ospf6_route_lookup(prefix, table);
1683 if (route == NULL)
1684 return;
1685
1686 ospf6_route_lock(route);
1687 while (route && ospf6_route_is_prefix(prefix, route)) {
1688 /* Specifying a prefix will always display details */
eacd0828 1689 ospf6_route_show_detail(vty, route, NULL, false);
d62a17ae 1690 route = ospf6_route_next(route);
1691 }
1692 if (route)
1693 ospf6_route_unlock(route);
4846ef64 1694}
1695
d62a17ae 1696static void ospf6_linkstate_show_table(struct vty *vty, int detail,
1697 struct ospf6_route_table *table)
4846ef64 1698{
d62a17ae 1699 struct ospf6_route *route;
1700
1701 if (!detail)
1702 ospf6_linkstate_show_header(vty);
1703
1704 route = ospf6_route_head(table);
1705 while (route) {
1706 if (detail)
eacd0828 1707 ospf6_route_show_detail(vty, route, NULL, false);
d62a17ae 1708 else
1709 ospf6_linkstate_show(vty, route);
1710 route = ospf6_route_next(route);
1711 }
718e3744 1712}
1713
d62a17ae 1714int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
1715 struct cmd_token **argv,
1716 struct ospf6_route_table *table)
718e3744 1717{
d62a17ae 1718 int detail = 0;
1719 int is_id = 0;
1720 int is_router = 0;
1721 int i, ret;
1722 struct prefix router, id, prefix;
1723
6006b807
DA
1724 memset(&router, 0, sizeof(router));
1725 memset(&id, 0, sizeof(id));
1726 memset(&prefix, 0, sizeof(prefix));
d62a17ae 1727
1728 for (i = idx_ipv4; i < argc; i++) {
1729 if (strmatch(argv[i]->text, "detail")) {
1730 detail++;
1731 continue;
1732 }
1733
1734 if (!is_router) {
1735 ret = str2prefix(argv[i]->arg, &router);
1736 if (ret == 1 && router.family == AF_INET) {
1737 is_router++;
1738 continue;
1739 }
1740 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1741 return CMD_SUCCESS;
1742 }
1743
1744 if (!is_id) {
1745 ret = str2prefix(argv[i]->arg, &id);
1746 if (ret == 1 && id.family == AF_INET) {
1747 is_id++;
1748 continue;
1749 }
1750 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1751 return CMD_SUCCESS;
1752 }
1753
1754 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1755 return CMD_SUCCESS;
1756 }
1757
1758 if (is_router)
1759 ospf6_linkstate_prefix(router.u.prefix4.s_addr,
1760 id.u.prefix4.s_addr, &prefix);
1761
1762 if (prefix.family)
1763 ospf6_linkstate_show_table_exact(vty, &prefix, table);
1764 else
1765 ospf6_linkstate_show_table(vty, detail, table);
1766
1767 return CMD_SUCCESS;
508e53e2 1768}
718e3744 1769
4846ef64 1770
d62a17ae 1771void ospf6_brouter_show_header(struct vty *vty)
6452df09 1772{
d62a17ae 1773 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", "Router-ID", "Rtr-Bits",
1774 "Options", "Path-Type", "Area");
6452df09 1775}
1776
d62a17ae 1777void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route)
6452df09 1778{
d7c0a89a 1779 uint32_t adv_router;
6cb85350 1780 char adv[16], rbits[16], options[32], area[16];
d62a17ae 1781
1782 adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1783 inet_ntop(AF_INET, &adv_router, adv, sizeof(adv));
1784 ospf6_capability_printbuf(route->path.router_bits, rbits,
1785 sizeof(rbits));
1786 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1787 inet_ntop(AF_INET, &route->path.area_id, area, sizeof(area));
1788
1789 /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s\n",
1790 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area"); */
1791 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", adv, rbits, options,
1792 OSPF6_PATH_TYPE_NAME(route->path.type), area);
6452df09 1793}
1794
d5cb3508
YR
1795DEFPY(debug_ospf6_route,
1796 debug_ospf6_route_cmd,
1797 "[no$no] debug ospf6 route <all|table|intra-area|inter-area|memory>",
1798 NO_STR
1799 DEBUG_STR
1800 OSPF6_STR
1801 "Debug routes\n"
1802 "Debug for all types of route calculation\n"
1803 "Debug route table calculation\n"
1804 "Debug intra-area route calculation\n"
1805 "Debug inter-area route calculation\n"
1806 "Debug route memory use\n")
508e53e2 1807{
d5cb3508 1808 int idx_type;
d62a17ae 1809 unsigned char level = 0;
1810
d5cb3508 1811 idx_type = ((no) ? 4 : 3);
d62a17ae 1812
d5cb3508
YR
1813 if (!strcmp(argv[idx_type]->text, "all"))
1814 level = OSPF6_DEBUG_ROUTE_ALL;
1815 else if (!strcmp(argv[idx_type]->text, "table"))
d62a17ae 1816 level = OSPF6_DEBUG_ROUTE_TABLE;
8034beff 1817 else if (!strcmp(argv[idx_type]->text, "intra-area"))
d62a17ae 1818 level = OSPF6_DEBUG_ROUTE_INTRA;
8034beff 1819 else if (!strcmp(argv[idx_type]->text, "inter-area"))
d62a17ae 1820 level = OSPF6_DEBUG_ROUTE_INTER;
8034beff 1821 else if (!strcmp(argv[idx_type]->text, "memory"))
d62a17ae 1822 level = OSPF6_DEBUG_ROUTE_MEMORY;
d5cb3508
YR
1823
1824 if (no)
1825 OSPF6_DEBUG_ROUTE_OFF(level);
1826 else
1827 OSPF6_DEBUG_ROUTE_ON(level);
d62a17ae 1828 return CMD_SUCCESS;
718e3744 1829}
1830
d62a17ae 1831int config_write_ospf6_debug_route(struct vty *vty)
508e53e2 1832{
d5cb3508
YR
1833 if (IS_OSPF6_DEBUG_ROUTE(ALL) == OSPF6_DEBUG_ROUTE_ALL) {
1834 vty_out(vty, "debug ospf6 route all\n");
1835 return 0;
1836 }
d62a17ae 1837 if (IS_OSPF6_DEBUG_ROUTE(TABLE))
1838 vty_out(vty, "debug ospf6 route table\n");
1839 if (IS_OSPF6_DEBUG_ROUTE(INTRA))
1840 vty_out(vty, "debug ospf6 route intra-area\n");
1841 if (IS_OSPF6_DEBUG_ROUTE(INTER))
1842 vty_out(vty, "debug ospf6 route inter-area\n");
6f7af48c
CS
1843 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
1844 vty_out(vty, "debug ospf6 route memory\n");
1845
d62a17ae 1846 return 0;
508e53e2 1847}
1848
d62a17ae 1849void install_element_ospf6_debug_route(void)
508e53e2 1850{
d62a17ae 1851 install_element(ENABLE_NODE, &debug_ospf6_route_cmd);
d62a17ae 1852 install_element(CONFIG_NODE, &debug_ospf6_route_cmd);
508e53e2 1853}