]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_route.c
debian: add pkg-config to build-depends
[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 *
16 * You should have received a copy of the GNU General Public License
ac4d0be5 17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
718e3744 20 */
21
508e53e2 22#include <zebra.h>
23
24#include "log.h"
25#include "memory.h"
26#include "prefix.h"
27#include "table.h"
28#include "vty.h"
29#include "command.h"
cf1ce250 30#include "linklist.h"
508e53e2 31
508e53e2 32#include "ospf6_proto.h"
33#include "ospf6_lsa.h"
049207c3 34#include "ospf6_lsdb.h"
508e53e2 35#include "ospf6_route.h"
cf1ce250
PJ
36#include "ospf6_top.h"
37#include "ospf6_area.h"
38#include "ospf6_interface.h"
049207c3 39#include "ospf6d.h"
c3c0ac83 40#include "ospf6_zebra.h"
718e3744 41
508e53e2 42unsigned char conf_debug_ospf6_route = 0;
718e3744 43
ac4d0be5 44static char *ospf6_route_table_name(struct ospf6_route_table *table)
cf1ce250 45{
ac4d0be5 46 static char name[32];
47 switch (table->scope_type) {
48 case OSPF6_SCOPE_TYPE_GLOBAL: {
49 switch (table->table_type) {
50 case OSPF6_TABLE_TYPE_ROUTES:
51 snprintf(name, sizeof(name), "global route table");
52 break;
53 case OSPF6_TABLE_TYPE_BORDER_ROUTERS:
54 snprintf(name, sizeof(name), "global brouter table");
55 break;
56 case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES:
57 snprintf(name, sizeof(name), "global external table");
58 break;
59 default:
60 snprintf(name, sizeof(name), "global unknown table");
61 break;
62 }
63 } break;
64
65 case OSPF6_SCOPE_TYPE_AREA: {
66 struct ospf6_area *oa = (struct ospf6_area *)table->scope;
67 switch (table->table_type) {
68 case OSPF6_TABLE_TYPE_SPF_RESULTS:
69 snprintf(name, sizeof(name), "area %s spf table",
70 oa->name);
71 break;
72 case OSPF6_TABLE_TYPE_ROUTES:
73 snprintf(name, sizeof(name), "area %s route table",
74 oa->name);
75 break;
76 case OSPF6_TABLE_TYPE_PREFIX_RANGES:
77 snprintf(name, sizeof(name), "area %s range table",
78 oa->name);
79 break;
80 case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES:
81 snprintf(name, sizeof(name),
82 "area %s summary prefix table", oa->name);
83 break;
84 case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS:
85 snprintf(name, sizeof(name),
86 "area %s summary router table", oa->name);
87 break;
88 default:
89 snprintf(name, sizeof(name), "area %s unknown table",
90 oa->name);
91 break;
92 }
93 } break;
94
95 case OSPF6_SCOPE_TYPE_INTERFACE: {
96 struct ospf6_interface *oi =
97 (struct ospf6_interface *)table->scope;
98 switch (table->table_type) {
99 case OSPF6_TABLE_TYPE_CONNECTED_ROUTES:
100 snprintf(name, sizeof(name),
101 "interface %s connected table",
102 oi->interface->name);
103 break;
104 default:
105 snprintf(name, sizeof(name),
106 "interface %s unknown table",
107 oi->interface->name);
108 break;
109 }
110 } break;
111
112 default: {
113 switch (table->table_type) {
114 case OSPF6_TABLE_TYPE_SPF_RESULTS:
115 snprintf(name, sizeof(name), "temporary spf table");
116 break;
117 default:
118 snprintf(name, sizeof(name), "temporary unknown table");
119 break;
120 }
121 } break;
122 }
123 return name;
cf1ce250
PJ
124}
125
ac4d0be5 126void ospf6_linkstate_prefix(u_int32_t adv_router, u_int32_t id,
127 struct prefix *prefix)
508e53e2 128{
ac4d0be5 129 memset(prefix, 0, sizeof(struct prefix));
130 prefix->family = AF_INET6;
131 prefix->prefixlen = 64;
132 memcpy(&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
133 memcpy(&prefix->u.prefix6.s6_addr[4], &id, 4);
508e53e2 134}
718e3744 135
ac4d0be5 136void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, int size)
718e3744 137{
ac4d0be5 138 u_int32_t adv_router, id;
139 char adv_router_str[16], id_str[16];
140 memcpy(&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
141 memcpy(&id, &prefix->u.prefix6.s6_addr[4], 4);
142 inet_ntop(AF_INET, &adv_router, adv_router_str, sizeof(adv_router_str));
143 inet_ntop(AF_INET, &id, id_str, sizeof(id_str));
144 if (ntohl(id))
145 snprintf(buf, size, "%s Net-ID: %s", adv_router_str, id_str);
146 else
147 snprintf(buf, size, "%s", adv_router_str);
508e53e2 148}
718e3744 149
508e53e2 150/* Global strings for logging */
ac4d0be5 151const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = {
152 "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange",
153};
718e3744 154
ac4d0be5 155const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = {
156 "?", "R", "N", "D", "L", "A",
157};
718e3744 158
ac4d0be5 159const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = {
160 "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2",
161};
718e3744 162
ac4d0be5 163const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = {
164 "??", "IA", "IE", "E1", "E2",
165};
718e3744 166
718e3744 167
ac4d0be5 168struct ospf6_nexthop *ospf6_nexthop_create(void)
c3c0ac83 169{
ac4d0be5 170 struct ospf6_nexthop *nh;
c3c0ac83 171
ac4d0be5 172 nh = XCALLOC(MTYPE_OSPF6_NEXTHOP, sizeof(struct ospf6_nexthop));
173 return nh;
c3c0ac83
DS
174}
175
ac4d0be5 176void ospf6_nexthop_delete(struct ospf6_nexthop *nh)
c3c0ac83 177{
ac4d0be5 178 if (nh)
179 XFREE(MTYPE_OSPF6_NEXTHOP, nh);
c3c0ac83
DS
180}
181
ac4d0be5 182void ospf6_free_nexthops(struct list *nh_list)
c3c0ac83 183{
ac4d0be5 184 struct ospf6_nexthop *nh;
185 struct listnode *node, *nnode;
186
187 if (nh_list) {
188 for (ALL_LIST_ELEMENTS(nh_list, node, nnode, nh))
189 ospf6_nexthop_delete(nh);
190 }
c3c0ac83
DS
191}
192
ac4d0be5 193void ospf6_clear_nexthops(struct list *nh_list)
c3c0ac83 194{
ac4d0be5 195 struct listnode *node;
196 struct ospf6_nexthop *nh;
197
198 if (nh_list) {
199 for (ALL_LIST_ELEMENTS_RO(nh_list, node, nh))
200 ospf6_nexthop_clear(nh);
201 }
c3c0ac83
DS
202}
203
204static struct ospf6_nexthop *
ac4d0be5 205ospf6_route_find_nexthop(struct list *nh_list, struct ospf6_nexthop *nh_match)
c3c0ac83 206{
ac4d0be5 207 struct listnode *node;
208 struct ospf6_nexthop *nh;
209
210 if (nh_list && nh_match) {
211 for (ALL_LIST_ELEMENTS_RO(nh_list, node, nh)) {
212 if (ospf6_nexthop_is_same(nh, nh_match))
213 return (nh);
214 }
c3c0ac83 215 }
c3c0ac83 216
ac4d0be5 217 return (NULL);
c3c0ac83
DS
218}
219
ac4d0be5 220void ospf6_copy_nexthops(struct list *dst, struct list *src)
c3c0ac83 221{
ac4d0be5 222 struct ospf6_nexthop *nh_new, *nh;
223 struct listnode *node;
224
225 if (dst && src) {
226 for (ALL_LIST_ELEMENTS_RO(src, node, nh)) {
227 if (ospf6_nexthop_is_set(nh)) {
228 nh_new = ospf6_nexthop_create();
229 ospf6_nexthop_copy(nh_new, nh);
230 listnode_add(dst, nh_new);
231 }
232 }
c3c0ac83 233 }
c3c0ac83
DS
234}
235
ac4d0be5 236void ospf6_merge_nexthops(struct list *dst, struct list *src)
c3c0ac83 237{
ac4d0be5 238 struct listnode *node;
239 struct ospf6_nexthop *nh, *nh_new;
240
241 if (src && dst) {
242 for (ALL_LIST_ELEMENTS_RO(src, node, nh)) {
243 if (!ospf6_route_find_nexthop(dst, nh)) {
244 nh_new = ospf6_nexthop_create();
245 ospf6_nexthop_copy(nh_new, nh);
246 listnode_add(dst, nh_new);
247 }
248 }
c3c0ac83 249 }
c3c0ac83
DS
250}
251
ac4d0be5 252int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
c3c0ac83 253{
ac4d0be5 254 struct listnode *anode, *bnode;
255 struct ospf6_nexthop *anh, *bnh;
256
257 if (a && b) {
258 if (listcount(a->nh_list) == listcount(b->nh_list)) {
259 for (ALL_LIST_ELEMENTS_RO(a->nh_list, anode, anh)) {
260 for (ALL_LIST_ELEMENTS_RO(b->nh_list, bnode,
261 bnh))
262 if (!ospf6_nexthop_is_same(anh, bnh))
263 return (1);
264 }
265 return (0);
266 } else
267 return (1);
c3c0ac83 268 }
ac4d0be5 269 /* One of the routes doesn't exist ? */
c3c0ac83 270 return (1);
c3c0ac83
DS
271}
272
ac4d0be5 273int ospf6_num_nexthops(struct list *nh_list)
c3c0ac83 274{
ac4d0be5 275 return (listcount(nh_list));
c3c0ac83
DS
276}
277
ac4d0be5 278void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
c3c0ac83 279{
ac4d0be5 280 struct ospf6_nexthop *nh;
281 struct ospf6_nexthop nh_match;
282
283 if (nh_list) {
284 nh_match.ifindex = ifindex;
285 if (addr != NULL)
286 memcpy(&nh_match.address, addr,
287 sizeof(struct in6_addr));
288 else
289 memset(&nh_match.address, 0, sizeof(struct in6_addr));
290
291 if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
292 nh = ospf6_nexthop_create();
293 ospf6_nexthop_copy(nh, &nh_match);
294 listnode_add(nh_list, nh);
295 }
c3c0ac83 296 }
c3c0ac83
DS
297}
298
ac4d0be5 299void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
300 ifindex_t *ifindexes,
301 struct in6_addr **nexthop_addr,
302 int entries)
c3c0ac83 303{
ac4d0be5 304 struct ospf6_nexthop *nh;
305 struct listnode *node;
306 char buf[64];
307 int i;
308
309 if (route) {
310 i = 0;
311 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
312 if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
313 const char *ifname;
314 inet_ntop(AF_INET6, &nh->address, buf,
315 sizeof(buf));
316 ifname = ifindex2ifname(nh->ifindex,
317 VRF_DEFAULT);
318 zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
319 IFNAMSIZ, ifname, nh->ifindex);
320 }
321 if (i < entries) {
322 nexthop_addr[i] = &nh->address;
323 ifindexes[i] = nh->ifindex;
324 i++;
325 } else {
326 return;
327 }
328 }
c3c0ac83 329 }
c3c0ac83
DS
330}
331
ac4d0be5 332int ospf6_route_get_first_nh_index(struct ospf6_route *route)
c3c0ac83 333{
ac4d0be5 334 struct ospf6_nexthop *nh;
c3c0ac83 335
ac4d0be5 336 if (route) {
337 if ((nh = (struct ospf6_nexthop *)listhead(route->nh_list)))
338 return (nh->ifindex);
339 }
c3c0ac83 340
ac4d0be5 341 return (-1);
c3c0ac83
DS
342}
343
ac4d0be5 344struct ospf6_route *ospf6_route_create(void)
718e3744 345{
ac4d0be5 346 struct ospf6_route *route;
347 route = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route));
348 route->nh_list = list_new();
349 return route;
508e53e2 350}
718e3744 351
ac4d0be5 352void ospf6_route_delete(struct ospf6_route *route)
508e53e2 353{
ac4d0be5 354 if (route) {
355 ospf6_free_nexthops(route->nh_list);
356 list_free(route->nh_list);
357 XFREE(MTYPE_OSPF6_ROUTE, route);
358 }
718e3744 359}
360
ac4d0be5 361struct ospf6_route *ospf6_route_copy(struct ospf6_route *route)
718e3744 362{
ac4d0be5 363 struct ospf6_route *new;
364
365 new = ospf6_route_create();
366 new->type = route->type;
367 memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
368 new->installed = route->installed;
369 new->changed = route->changed;
370 new->flag = route->flag;
371 new->route_option = route->route_option;
372 new->linkstate_id = route->linkstate_id;
373 new->path = route->path;
374 ospf6_copy_nexthops(new->nh_list, route->nh_list);
375 new->rnode = NULL;
376 new->prev = NULL;
377 new->next = NULL;
378 new->table = NULL;
379 new->lock = 0;
380 return new;
508e53e2 381}
718e3744 382
ac4d0be5 383void ospf6_route_lock(struct ospf6_route *route)
508e53e2 384{
ac4d0be5 385 route->lock++;
508e53e2 386}
718e3744 387
ac4d0be5 388void ospf6_route_unlock(struct ospf6_route *route)
508e53e2 389{
ac4d0be5 390 assert(route->lock > 0);
391 route->lock--;
392 if (route->lock == 0) {
393 /* Can't detach from the table until here
394 because ospf6_route_next () will use
395 the 'route->table' pointer for logging */
396 route->table = NULL;
397 ospf6_route_delete(route);
398 }
508e53e2 399}
718e3744 400
508e53e2 401/* Route compare function. If ra is more preferred, it returns
402 less than 0. If rb is more preferred returns greater than 0.
403 Otherwise (neither one is preferred), returns 0 */
ac4d0be5 404int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
508e53e2 405{
ac4d0be5 406 assert(ospf6_route_is_same(ra, rb));
407 assert(OSPF6_PATH_TYPE_NONE < ra->path.type
408 && ra->path.type < OSPF6_PATH_TYPE_MAX);
409 assert(OSPF6_PATH_TYPE_NONE < rb->path.type
410 && rb->path.type < OSPF6_PATH_TYPE_MAX);
411
412 if (ra->type != rb->type)
413 return (ra->type - rb->type);
414
415 if (ra->path.area_id != rb->path.area_id)
416 return (ntohl(ra->path.area_id) - ntohl(rb->path.area_id));
417
418 if (ra->path.type != rb->path.type)
419 return (ra->path.type - rb->path.type);
420
421 if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
422 if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
423 return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
424 } else {
425 if (ra->path.cost != rb->path.cost)
426 return (ra->path.cost - rb->path.cost);
427 }
428
429 return 0;
718e3744 430}
431
ac4d0be5 432struct ospf6_route *ospf6_route_lookup(struct prefix *prefix,
433 struct ospf6_route_table *table)
718e3744 434{
ac4d0be5 435 struct route_node *node;
436 struct ospf6_route *route;
718e3744 437
ac4d0be5 438 node = route_node_lookup(table->table, prefix);
439 if (node == NULL)
440 return NULL;
508e53e2 441
ac4d0be5 442 route = (struct ospf6_route *)node->info;
443 return route;
508e53e2 444}
718e3744 445
508e53e2 446struct ospf6_route *
ac4d0be5 447ospf6_route_lookup_identical(struct ospf6_route *route,
448 struct ospf6_route_table *table)
508e53e2 449{
ac4d0be5 450 struct ospf6_route *target;
451
452 for (target = ospf6_route_lookup(&route->prefix, table); target;
453 target = target->next) {
454 if (ospf6_route_is_identical(target, route))
455 return target;
456 }
457 return NULL;
718e3744 458}
459
508e53e2 460struct ospf6_route *
ac4d0be5 461ospf6_route_lookup_bestmatch(struct prefix *prefix,
462 struct ospf6_route_table *table)
718e3744 463{
ac4d0be5 464 struct route_node *node;
465 struct ospf6_route *route;
718e3744 466
ac4d0be5 467 node = route_node_match(table->table, prefix);
468 if (node == NULL)
469 return NULL;
470 route_unlock_node(node);
718e3744 471
ac4d0be5 472 route = (struct ospf6_route *)node->info;
473 return route;
718e3744 474}
475
e39d0538 476#ifdef DEBUG
ac4d0be5 477static void route_table_assert(struct ospf6_route_table *table)
718e3744 478{
ac4d0be5 479 struct ospf6_route *prev, *r, *next;
480 char buf[PREFIX2STR_BUFFER];
481 unsigned int link_error = 0, num = 0;
482
483 r = ospf6_route_head(table);
484 prev = NULL;
485 while (r) {
486 if (r->prev != prev)
487 link_error++;
488
489 next = ospf6_route_next(r);
490
491 if (r->next != next)
492 link_error++;
493
494 prev = r;
495 r = next;
496 }
497
498 for (r = ospf6_route_head(table); r; r = ospf6_route_next(r))
499 num++;
500
501 if (link_error == 0 && num == table->count)
502 return;
503
504 zlog_err("PANIC !!");
505 zlog_err("Something has gone wrong with ospf6_route_table[%p]", table);
506 zlog_debug("table count = %d, real number = %d", table->count, num);
507 zlog_debug("DUMP START");
508 for (r = ospf6_route_head(table); r; r = ospf6_route_next(r)) {
509 prefix2str(&r->prefix, buf, sizeof(buf));
510 zlog_info("%p<-[%p]->%p : %s", r->prev, r, r->next, buf);
511 }
512 zlog_debug("DUMP END");
513
514 assert(link_error == 0 && num == table->count);
718e3744 515}
cf1ce250 516#define ospf6_route_table_assert(t) (route_table_assert (t))
508e53e2 517#else
cf1ce250 518#define ospf6_route_table_assert(t) ((void) 0)
e39d0538 519#endif /*DEBUG*/
718e3744 520
ac4d0be5 521struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
522 struct ospf6_route_table *table)
718e3744 523{
ac4d0be5 524 struct route_node *node, *nextnode, *prevnode;
525 struct ospf6_route *current = NULL;
526 struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
527 char buf[PREFIX2STR_BUFFER];
528 struct timeval now;
529
530 assert(route->rnode == NULL);
531 assert(route->lock == 0);
532 assert(route->next == NULL);
533 assert(route->prev == NULL);
534
535 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
536 ospf6_linkstate_prefix2str(&route->prefix, buf, sizeof(buf));
537 else
538 prefix2str(&route->prefix, buf, sizeof(buf));
539
540 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
541 zlog_debug("%s %p: route add %p: %s",
542 ospf6_route_table_name(table), (void *)table,
543 (void *)route, buf);
544 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
545 zlog_debug("%s: route add: %s", ospf6_route_table_name(table),
546 buf);
547
548 monotime(&now);
549
550 node = route_node_get(table->table, &route->prefix);
551 route->rnode = node;
552
553 /* find place to insert */
554 for (current = node->info; current; current = current->next) {
555 if (!ospf6_route_is_same(current, route))
556 next = current;
557 else if (current->type != route->type)
558 prev = current;
559 else if (ospf6_route_is_same_origin(current, route))
560 old = current;
561 else if (ospf6_route_cmp(current, route) > 0)
562 next = current;
563 else
564 prev = current;
565
566 if (old || next)
567 break;
568 }
718e3744 569
ac4d0be5 570 if (old) {
571 /* if route does not actually change, return unchanged */
572 if (ospf6_route_is_identical(old, route)) {
573 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
574 zlog_debug(
575 "%s %p: route add %p: needless update of %p",
576 ospf6_route_table_name(table),
577 (void *)table, (void *)route,
578 (void *)old);
579 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
580 zlog_debug("%s: route add: needless update",
581 ospf6_route_table_name(table));
582
583 ospf6_route_delete(route);
584 SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
585 ospf6_route_table_assert(table);
586
587 return old;
588 }
589
590 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
591 zlog_debug("%s %p: route add %p: update of %p",
592 ospf6_route_table_name(table), (void *)table,
593 (void *)route, (void *)old);
594 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
595 zlog_debug("%s: route add: update",
596 ospf6_route_table_name(table));
597
598 /* replace old one if exists */
599 if (node->info == old) {
600 node->info = route;
601 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
602 }
603
604 if (old->prev)
605 old->prev->next = route;
606 route->prev = old->prev;
607 if (old->next)
608 old->next->prev = route;
609 route->next = old->next;
610
611 route->installed = old->installed;
612 route->changed = now;
613 assert(route->table == NULL);
614 route->table = table;
615
616 ospf6_route_unlock(old); /* will be deleted later */
617 ospf6_route_lock(route);
618
619 SET_FLAG(route->flag, OSPF6_ROUTE_CHANGE);
620 ospf6_route_table_assert(table);
621
622 if (table->hook_add)
623 (*table->hook_add)(route);
624
625 return route;
626 }
627
628 /* insert if previous or next node found */
629 if (prev || next) {
630 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
631 zlog_debug(
632 "%s %p: route add %p: another path: prev %p, next %p",
633 ospf6_route_table_name(table), (void *)table,
634 (void *)route, (void *)prev, (void *)next);
635 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
636 zlog_debug("%s: route add: another path found",
637 ospf6_route_table_name(table));
638
639 if (prev == NULL)
640 prev = next->prev;
641 if (next == NULL)
642 next = prev->next;
643
644 if (prev)
645 prev->next = route;
646 route->prev = prev;
647 if (next)
648 next->prev = route;
649 route->next = next;
650
651 if (node->info == next) {
652 assert(next->rnode == node);
653 node->info = route;
654 UNSET_FLAG(next->flag, OSPF6_ROUTE_BEST);
655 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
656 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
657 zlog_info(
658 "%s %p: route add %p: replacing previous best: %p",
659 ospf6_route_table_name(table),
660 (void *)table, (void *)route,
661 (void *)next);
662 }
663
664 route->installed = now;
665 route->changed = now;
666 assert(route->table == NULL);
667 route->table = table;
668
669 ospf6_route_lock(route);
670 table->count++;
671 ospf6_route_table_assert(table);
672
673 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
674 if (table->hook_add)
675 (*table->hook_add)(route);
676
677 return route;
678 }
679
680 /* Else, this is the brand new route regarding to the prefix */
681 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
682 zlog_debug("%s %p: route add %p: brand new route",
683 ospf6_route_table_name(table), (void *)table,
684 (void *)route);
685 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
686 zlog_debug("%s: route add: brand new route",
687 ospf6_route_table_name(table));
688
689 assert(node->info == NULL);
690 node->info = route;
691 SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
692 ospf6_route_lock(route);
693 route->installed = now;
694 route->changed = now;
695 assert(route->table == NULL);
696 route->table = table;
697
698 /* lookup real existing next route */
699 nextnode = node;
700 route_lock_node(nextnode);
701 do {
702 nextnode = route_next(nextnode);
703 } while (nextnode && nextnode->info == NULL);
704
705 /* set next link */
706 if (nextnode == NULL)
707 route->next = NULL;
708 else {
709 route_unlock_node(nextnode);
710
711 next = nextnode->info;
712 route->next = next;
713 next->prev = route;
714 }
715
716 /* lookup real existing prev route */
717 prevnode = node;
718 route_lock_node(prevnode);
719 do {
720 prevnode = route_prev(prevnode);
721 } while (prevnode && prevnode->info == NULL);
722
723 /* set prev link */
724 if (prevnode == NULL)
725 route->prev = NULL;
726 else {
727 route_unlock_node(prevnode);
728
729 prev = prevnode->info;
730 while (prev->next && ospf6_route_is_same(prev, prev->next))
731 prev = prev->next;
732 route->prev = prev;
733 prev->next = route;
734 }
735
736 table->count++;
737 ospf6_route_table_assert(table);
738
739 SET_FLAG(route->flag, OSPF6_ROUTE_ADD);
740 if (table->hook_add)
741 (*table->hook_add)(route);
742
743 return route;
508e53e2 744}
718e3744 745
ac4d0be5 746void ospf6_route_remove(struct ospf6_route *route,
747 struct ospf6_route_table *table)
508e53e2 748{
ac4d0be5 749 struct route_node *node;
750 struct ospf6_route *current;
751 char buf[PREFIX2STR_BUFFER];
752
753 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
754 ospf6_linkstate_prefix2str(&route->prefix, buf, sizeof(buf));
755 else
756 prefix2str(&route->prefix, buf, sizeof(buf));
757
758 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
759 zlog_debug("%s %p: route remove %p: %s",
760 ospf6_route_table_name(table), (void *)table,
761 (void *)route, buf);
762 else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
763 zlog_debug("%s: route remove: %s",
764 ospf6_route_table_name(table), buf);
765
766 node = route_node_lookup(table->table, &route->prefix);
767 assert(node);
768
769 /* find the route to remove, making sure that the route pointer
770 is from the route table. */
771 current = node->info;
772 while (current && ospf6_route_is_same(current, route)) {
773 if (current == route)
774 break;
775 current = current->next;
776 }
777 assert(current == route);
778
779 /* adjust doubly linked list */
780 if (route->prev)
781 route->prev->next = route->next;
782 if (route->next)
783 route->next->prev = route->prev;
784
785 if (node->info == route) {
786 if (route->next && route->next->rnode == node) {
787 node->info = route->next;
788 SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST);
789 } else
790 node->info = NULL; /* should unlock route_node here ? */
791 }
508e53e2 792
ac4d0be5 793 table->count--;
794 ospf6_route_table_assert(table);
718e3744 795
ac4d0be5 796 SET_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED);
508e53e2 797
ac4d0be5 798 if (table->hook_remove)
799 (*table->hook_remove)(route);
cf1ce250 800
ac4d0be5 801 ospf6_route_unlock(route);
802}
cf1ce250 803
ac4d0be5 804struct ospf6_route *ospf6_route_head(struct ospf6_route_table *table)
805{
806 struct route_node *node;
807 struct ospf6_route *route;
808
809 node = route_top(table->table);
810 if (node == NULL)
811 return NULL;
812
813 /* skip to the real existing entry */
814 while (node && node->info == NULL)
815 node = route_next(node);
816 if (node == NULL)
817 return NULL;
818
819 route_unlock_node(node);
820 assert(node->info);
821
822 route = (struct ospf6_route *)node->info;
823 assert(route->prev == NULL);
824 assert(route->table == table);
825 ospf6_route_lock(route);
826
827 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
828 zlog_info("%s %p: route head: %p<-[%p]->%p",
829 ospf6_route_table_name(table), (void *)table,
830 (void *)route->prev, (void *)route,
831 (void *)route->next);
832
833 return route;
718e3744 834}
835
ac4d0be5 836struct ospf6_route *ospf6_route_next(struct ospf6_route *route)
718e3744 837{
ac4d0be5 838 struct ospf6_route *next = route->next;
718e3744 839
ac4d0be5 840 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
841 zlog_info("%s %p: route next: %p<-[%p]->%p",
842 ospf6_route_table_name(route->table),
843 (void *)route->table, (void *)route->prev,
844 (void *)route, (void *)route->next);
cf1ce250 845
ac4d0be5 846 ospf6_route_unlock(route);
847 if (next)
848 ospf6_route_lock(next);
718e3744 849
ac4d0be5 850 return next;
508e53e2 851}
718e3744 852
ac4d0be5 853struct ospf6_route *ospf6_route_best_next(struct ospf6_route *route)
508e53e2 854{
ac4d0be5 855 struct route_node *rnode;
856 struct ospf6_route *next;
857
858 ospf6_route_unlock(route);
859
860 rnode = route->rnode;
861 route_lock_node(rnode);
862 rnode = route_next(rnode);
863 while (rnode && rnode->info == NULL)
864 rnode = route_next(rnode);
865 if (rnode == NULL)
866 return NULL;
867 route_unlock_node(rnode);
868
869 assert(rnode->info);
870 next = (struct ospf6_route *)rnode->info;
871 ospf6_route_lock(next);
872 return next;
508e53e2 873}
718e3744 874
ac4d0be5 875struct ospf6_route *ospf6_route_match_head(struct prefix *prefix,
876 struct ospf6_route_table *table)
508e53e2 877{
ac4d0be5 878 struct route_node *node;
879 struct ospf6_route *route;
880
881 /* Walk down tree. */
882 node = table->table->top;
883 while (node && node->p.prefixlen < prefix->prefixlen
884 && prefix_match(&node->p, prefix))
885 node = node->link[prefix_bit(&prefix->u.prefix,
886 node->p.prefixlen)];
887
888 if (node)
889 route_lock_node(node);
890 while (node && node->info == NULL)
891 node = route_next(node);
892 if (node == NULL)
893 return NULL;
894 route_unlock_node(node);
895
896 if (!prefix_match(prefix, &node->p))
897 return NULL;
898
899 route = node->info;
900 ospf6_route_lock(route);
901 return route;
508e53e2 902}
718e3744 903
ac4d0be5 904struct ospf6_route *ospf6_route_match_next(struct prefix *prefix,
905 struct ospf6_route *route)
508e53e2 906{
ac4d0be5 907 struct ospf6_route *next;
508e53e2 908
ac4d0be5 909 next = ospf6_route_next(route);
910 if (next && !prefix_match(prefix, &next->prefix)) {
911 ospf6_route_unlock(next);
912 next = NULL;
913 }
508e53e2 914
ac4d0be5 915 return next;
718e3744 916}
917
ac4d0be5 918void ospf6_route_remove_all(struct ospf6_route_table *table)
718e3744 919{
ac4d0be5 920 struct ospf6_route *route;
921 for (route = ospf6_route_head(table); route;
922 route = ospf6_route_next(route))
923 ospf6_route_remove(route, table);
718e3744 924}
925
ac4d0be5 926struct ospf6_route_table *ospf6_route_table_create(int s, int t)
718e3744 927{
ac4d0be5 928 struct ospf6_route_table *new;
929 new = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route_table));
930 new->table = route_table_init();
931 new->scope_type = s;
932 new->table_type = t;
933 return new;
718e3744 934}
935
ac4d0be5 936void ospf6_route_table_delete(struct ospf6_route_table *table)
718e3744 937{
ac4d0be5 938 ospf6_route_remove_all(table);
939 route_table_finish(table->table);
940 XFREE(MTYPE_OSPF6_ROUTE, table);
718e3744 941}
942
6b0655a2 943
508e53e2 944/* VTY commands */
ac4d0be5 945void ospf6_route_show(struct vty *vty, struct ospf6_route *route)
718e3744 946{
ac4d0be5 947 int i;
948 char destination[PREFIX2STR_BUFFER], nexthop[64];
949 char duration[16];
950 const char *ifname;
951 struct timeval now, res;
952 struct listnode *node;
953 struct ospf6_nexthop *nh;
954
955 monotime(&now);
956 timersub(&now, &route->changed, &res);
957 timerstring(&res, duration, sizeof(duration));
958
959 /* destination */
960 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
961 ospf6_linkstate_prefix2str(&route->prefix, destination,
962 sizeof(destination));
963 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
964 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
965 destination, sizeof(destination));
966 else
967 prefix2str(&route->prefix, destination, sizeof(destination));
968
969 i = 0;
970 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
971 /* nexthop */
972 inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
973 ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT);
974
975 if (!i) {
976 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
977 (ospf6_route_is_best(route) ? '*' : ' '),
978 OSPF6_DEST_TYPE_SUBSTR(route->type),
979 OSPF6_PATH_TYPE_SUBSTR(route->path.type),
980 destination, nexthop, IFNAMSIZ, ifname,
981 duration, VNL);
982 i++;
983 } else
984 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", ' ',
985 "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
c3c0ac83 986 }
718e3744 987}
988
ac4d0be5 989void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
718e3744 990{
ac4d0be5 991 const char *ifname;
992 char destination[PREFIX2STR_BUFFER], nexthop[64];
993 char area_id[16], id[16], adv_router[16], capa[16], options[16];
994 struct timeval now, res;
995 char duration[16];
996 struct listnode *node;
997 struct ospf6_nexthop *nh;
998
999 monotime(&now);
1000
1001 /* destination */
1002 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1003 ospf6_linkstate_prefix2str(&route->prefix, destination,
1004 sizeof(destination));
1005 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1006 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1007 destination, sizeof(destination));
1008 else
1009 prefix2str(&route->prefix, destination, sizeof(destination));
1010 vty_out(vty, "Destination: %s%s", destination, VNL);
1011
1012 /* destination type */
1013 vty_out(vty, "Destination type: %s%s",
1014 OSPF6_DEST_TYPE_NAME(route->type), VNL);
1015
1016 /* Time */
1017 timersub(&now, &route->installed, &res);
1018 timerstring(&res, duration, sizeof(duration));
1019 vty_out(vty, "Installed Time: %s ago%s", duration, VNL);
1020
1021 timersub(&now, &route->changed, &res);
1022 timerstring(&res, duration, sizeof(duration));
1023 vty_out(vty, " Changed Time: %s ago%s", duration, VNL);
1024
1025 /* Debugging info */
1026 vty_out(vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
1027 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1028 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1029 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
1030 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"), VNL);
1031 vty_out(vty, "Memory: prev: %p this: %p next: %p%s",
1032 (void *)route->prev, (void *)route, (void *)route->next, VNL);
1033
1034 /* Path section */
1035
1036 /* Area-ID */
1037 inet_ntop(AF_INET, &route->path.area_id, area_id, sizeof(area_id));
1038 vty_out(vty, "Associated Area: %s%s", area_id, VNL);
1039
1040 /* Path type */
1041 vty_out(vty, "Path Type: %s%s", OSPF6_PATH_TYPE_NAME(route->path.type),
1042 VNL);
1043
1044 /* LS Origin */
1045 inet_ntop(AF_INET, &route->path.origin.id, id, sizeof(id));
1046 inet_ntop(AF_INET, &route->path.origin.adv_router, adv_router,
1047 sizeof(adv_router));
1048 vty_out(vty, "LS Origin: %s Id: %s Adv: %s%s",
1049 ospf6_lstype_name(route->path.origin.type), id, adv_router,
1050 VNL);
1051
1052 /* Options */
1053 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1054 vty_out(vty, "Options: %s%s", options, VNL);
1055
1056 /* Router Bits */
1057 ospf6_capability_printbuf(route->path.router_bits, capa, sizeof(capa));
1058 vty_out(vty, "Router Bits: %s%s", capa, VNL);
1059
1060 /* Prefix Options */
1061 vty_out(vty, "Prefix Options: xxx%s", VNL);
1062
1063 /* Metrics */
1064 vty_out(vty, "Metric Type: %d%s", route->path.metric_type, VNL);
1065 vty_out(vty, "Metric: %d (%d)%s", route->path.cost,
1066 route->path.u.cost_e2, VNL);
1067
1068 /* Nexthops */
1069 vty_out(vty, "Nexthop:%s", VNL);
1070 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
1071 /* nexthop */
1072 inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
1073 ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT);
1074 vty_out(vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
1075 }
1076 vty_out(vty, "%s", VNL);
508e53e2 1077}
718e3744 1078
ac4d0be5 1079static void ospf6_route_show_table_summary(struct vty *vty,
1080 struct ospf6_route_table *table)
508e53e2 1081{
ac4d0be5 1082 struct ospf6_route *route, *prev = NULL;
1083 int i, pathtype[OSPF6_PATH_TYPE_MAX];
1084 unsigned int number = 0;
1085 int nh_count = 0, nhinval = 0, ecmp = 0;
1086 int alternative = 0, destination = 0;
1087
1088 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
1089 pathtype[i] = 0;
1090
1091 for (route = ospf6_route_head(table); route;
1092 route = ospf6_route_next(route)) {
1093 if (prev == NULL || !ospf6_route_is_same(prev, route))
1094 destination++;
1095 else
1096 alternative++;
1097 nh_count = ospf6_num_nexthops(route->nh_list);
1098 if (!nh_count)
1099 nhinval++;
1100 else if (nh_count > 1)
1101 ecmp++;
1102 pathtype[route->path.type]++;
1103 number++;
1104
1105 prev = route;
1106 }
1107
1108 assert(number == table->count);
1109
1110 vty_out(vty, "Number of OSPFv3 routes: %d%s", number, VNL);
1111 vty_out(vty, "Number of Destination: %d%s", destination, VNL);
1112 vty_out(vty, "Number of Alternative routes: %d%s", alternative, VNL);
1113 vty_out(vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL);
1114 for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) {
1115 vty_out(vty, "Number of %s routes: %d%s",
1116 OSPF6_PATH_TYPE_NAME(i), pathtype[i], VNL);
1117 }
4846ef64 1118}
1119
ac4d0be5 1120static void ospf6_route_show_table_prefix(struct vty *vty,
1121 struct prefix *prefix,
1122 struct ospf6_route_table *table)
4846ef64 1123{
ac4d0be5 1124 struct ospf6_route *route;
1125
1126 route = ospf6_route_lookup(prefix, table);
1127 if (route == NULL)
1128 return;
1129
1130 ospf6_route_lock(route);
1131 while (route && ospf6_route_is_prefix(prefix, route)) {
1132 /* Specifying a prefix will always display details */
1133 ospf6_route_show_detail(vty, route);
1134 route = ospf6_route_next(route);
1135 }
1136 if (route)
1137 ospf6_route_unlock(route);
4846ef64 1138}
1139
ac4d0be5 1140static void ospf6_route_show_table_address(struct vty *vty,
1141 struct prefix *prefix,
1142 struct ospf6_route_table *table)
4846ef64 1143{
ac4d0be5 1144 struct ospf6_route *route;
1145
1146 route = ospf6_route_lookup_bestmatch(prefix, table);
1147 if (route == NULL)
1148 return;
1149
1150 prefix = &route->prefix;
1151 ospf6_route_lock(route);
1152 while (route && ospf6_route_is_prefix(prefix, route)) {
1153 /* Specifying a prefix will always display details */
1154 ospf6_route_show_detail(vty, route);
1155 route = ospf6_route_next(route);
1156 }
1157 if (route)
1158 ospf6_route_unlock(route);
4846ef64 1159}
1160
ac4d0be5 1161static void ospf6_route_show_table_match(struct vty *vty, int detail,
1162 struct prefix *prefix,
1163 struct ospf6_route_table *table)
4846ef64 1164{
ac4d0be5 1165 struct ospf6_route *route;
1166 assert(prefix->family);
1167
1168 route = ospf6_route_match_head(prefix, table);
1169 while (route) {
1170 if (detail)
1171 ospf6_route_show_detail(vty, route);
1172 else
1173 ospf6_route_show(vty, route);
1174 route = ospf6_route_match_next(prefix, route);
1175 }
4846ef64 1176}
1177
ac4d0be5 1178static void ospf6_route_show_table_type(struct vty *vty, int detail,
1179 u_char type,
1180 struct ospf6_route_table *table)
4846ef64 1181{
ac4d0be5 1182 struct ospf6_route *route;
1183
1184 route = ospf6_route_head(table);
1185 while (route) {
1186 if (route->path.type == type) {
1187 if (detail)
1188 ospf6_route_show_detail(vty, route);
1189 else
1190 ospf6_route_show(vty, route);
1191 }
1192 route = ospf6_route_next(route);
1193 }
4846ef64 1194}
1195
ac4d0be5 1196static void ospf6_route_show_table(struct vty *vty, int detail,
1197 struct ospf6_route_table *table)
4846ef64 1198{
ac4d0be5 1199 struct ospf6_route *route;
1200
1201 route = ospf6_route_head(table);
1202 while (route) {
1203 if (detail)
1204 ospf6_route_show_detail(vty, route);
1205 else
1206 ospf6_route_show(vty, route);
1207 route = ospf6_route_next(route);
1208 }
718e3744 1209}
1210
ac4d0be5 1211int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
1212 struct cmd_token **argv,
1213 struct ospf6_route_table *table)
718e3744 1214{
ac4d0be5 1215 int summary = 0;
1216 int match = 0;
1217 int detail = 0;
1218 int slash = 0;
1219 int isprefix = 0;
1220 int i, ret;
1221 struct prefix prefix;
1222 u_char type = 0;
1223
1224 memset(&prefix, 0, sizeof(struct prefix));
1225
1226 for (i = argc_start; i < argc; i++) {
1227 if (!strcmp(argv[i]->arg, "summary")) {
1228 summary++;
1229 continue;
1230 }
1231
1232 if (!strcmp(argv[i]->arg, "intra-area")) {
1233 type = OSPF6_PATH_TYPE_INTRA;
1234 continue;
1235 }
1236
1237 if (!strcmp(argv[i]->arg, "inter-area")) {
1238 type = OSPF6_PATH_TYPE_INTER;
1239 continue;
1240 }
1241
1242 if (!strcmp(argv[i]->arg, "external-1")) {
1243 type = OSPF6_PATH_TYPE_EXTERNAL1;
1244 continue;
1245 }
1246
1247 if (!strcmp(argv[i]->arg, "external-2")) {
1248 type = OSPF6_PATH_TYPE_EXTERNAL2;
1249 continue;
1250 }
1251
1252 if (!strcmp(argv[i]->arg, "detail")) {
1253 detail++;
1254 continue;
1255 }
1256
1257 if (!strcmp(argv[i]->arg, "match")) {
1258 match++;
1259 continue;
1260 }
1261
1262 ret = str2prefix(argv[i]->arg, &prefix);
1263 if (ret == 1 && prefix.family == AF_INET6) {
1264 isprefix++;
1265 if (strchr(argv[i]->arg, '/'))
1266 slash++;
1267 continue;
1268 }
1269
1270 vty_out(vty, "Malformed argument: %s%s", argv[i]->arg, VNL);
1271 return CMD_SUCCESS;
1272 }
1273
1274 /* Give summary of this route table */
1275 if (summary) {
1276 ospf6_route_show_table_summary(vty, table);
1277 return CMD_SUCCESS;
1278 }
1279
1280 /* Give exact prefix-match route */
1281 if (isprefix && !match) {
1282 /* If exact address, give best matching route */
1283 if (!slash)
1284 ospf6_route_show_table_address(vty, &prefix, table);
1285 else
1286 ospf6_route_show_table_prefix(vty, &prefix, table);
1287
1288 return CMD_SUCCESS;
1289 }
1290
1291 if (match)
1292 ospf6_route_show_table_match(vty, detail, &prefix, table);
1293 else if (type)
1294 ospf6_route_show_table_type(vty, detail, type, table);
1295 else
1296 ospf6_route_show_table(vty, detail, table);
1297
1298 return CMD_SUCCESS;
4846ef64 1299}
508e53e2 1300
ac4d0be5 1301static void ospf6_linkstate_show_header(struct vty *vty)
4846ef64 1302{
ac4d0be5 1303 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %s%s", "Type", "Router-ID",
1304 "Net-ID", "Rtr-Bits", "Options", "Cost", VNL);
4846ef64 1305}
1306
ac4d0be5 1307static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route)
4846ef64 1308{
ac4d0be5 1309 u_int32_t router, id;
1310 char routername[16], idname[16], rbits[16], options[16];
1311
1312 router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1313 inet_ntop(AF_INET, &router, routername, sizeof(routername));
1314 id = ospf6_linkstate_prefix_id(&route->prefix);
1315 inet_ntop(AF_INET, &id, idname, sizeof(idname));
1316
1317 ospf6_capability_printbuf(route->path.router_bits, rbits,
1318 sizeof(rbits));
1319 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1320
1321 if (ntohl(id))
1322 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", "Network",
1323 routername, idname, rbits, options,
1324 (unsigned long)route->path.cost, VNL);
1325 else
1326 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", "Router",
1327 routername, idname, rbits, options,
1328 (unsigned long)route->path.cost, VNL);
4846ef64 1329}
1330
1331
ac4d0be5 1332static void ospf6_linkstate_show_table_exact(struct vty *vty,
1333 struct prefix *prefix,
1334 struct ospf6_route_table *table)
4846ef64 1335{
ac4d0be5 1336 struct ospf6_route *route;
1337
1338 route = ospf6_route_lookup(prefix, table);
1339 if (route == NULL)
1340 return;
1341
1342 ospf6_route_lock(route);
1343 while (route && ospf6_route_is_prefix(prefix, route)) {
1344 /* Specifying a prefix will always display details */
1345 ospf6_route_show_detail(vty, route);
1346 route = ospf6_route_next(route);
1347 }
1348 if (route)
1349 ospf6_route_unlock(route);
4846ef64 1350}
1351
ac4d0be5 1352static void ospf6_linkstate_show_table(struct vty *vty, int detail,
1353 struct ospf6_route_table *table)
4846ef64 1354{
ac4d0be5 1355 struct ospf6_route *route;
1356
1357 if (!detail)
1358 ospf6_linkstate_show_header(vty);
1359
1360 route = ospf6_route_head(table);
1361 while (route) {
1362 if (detail)
1363 ospf6_route_show_detail(vty, route);
1364 else
1365 ospf6_linkstate_show(vty, route);
1366 route = ospf6_route_next(route);
1367 }
718e3744 1368}
1369
ac4d0be5 1370int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
1371 struct cmd_token **argv,
1372 struct ospf6_route_table *table)
718e3744 1373{
ac4d0be5 1374 int detail = 0;
1375 int is_id = 0;
1376 int is_router = 0;
1377 int i, ret;
1378 struct prefix router, id, prefix;
1379
1380 memset(&router, 0, sizeof(struct prefix));
1381 memset(&id, 0, sizeof(struct prefix));
1382 memset(&prefix, 0, sizeof(struct prefix));
1383
1384 for (i = idx_ipv4; i < argc; i++) {
1385 if (!strcmp(argv[i]->arg, "detail")) {
1386 detail++;
1387 continue;
1388 }
1389
1390 if (!is_router) {
1391 ret = str2prefix(argv[i]->arg, &router);
1392 if (ret == 1 && router.family == AF_INET) {
1393 is_router++;
1394 continue;
1395 }
1396 vty_out(vty, "Malformed argument: %s%s", argv[i]->arg,
1397 VNL);
1398 return CMD_SUCCESS;
1399 }
1400
1401 if (!is_id) {
1402 ret = str2prefix(argv[i]->arg, &id);
1403 if (ret == 1 && id.family == AF_INET) {
1404 is_id++;
1405 continue;
1406 }
1407 vty_out(vty, "Malformed argument: %s%s", argv[i]->arg,
1408 VNL);
1409 return CMD_SUCCESS;
1410 }
1411
1412 vty_out(vty, "Malformed argument: %s%s", argv[i]->arg, VNL);
1413 return CMD_SUCCESS;
1414 }
1415
1416 if (is_router)
1417 ospf6_linkstate_prefix(router.u.prefix4.s_addr,
1418 id.u.prefix4.s_addr, &prefix);
1419
1420 if (prefix.family)
1421 ospf6_linkstate_show_table_exact(vty, &prefix, table);
1422 else
1423 ospf6_linkstate_show_table(vty, detail, table);
1424
1425 return CMD_SUCCESS;
508e53e2 1426}
718e3744 1427
4846ef64 1428
ac4d0be5 1429void ospf6_brouter_show_header(struct vty *vty)
6452df09 1430{
ac4d0be5 1431 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s%s", "Router-ID", "Rtr-Bits",
1432 "Options", "Path-Type", "Area", VNL);
6452df09 1433}
1434
ac4d0be5 1435void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route)
6452df09 1436{
ac4d0be5 1437 u_int32_t adv_router;
1438 char adv[16], rbits[16], options[16], area[16];
1439
1440 adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1441 inet_ntop(AF_INET, &adv_router, adv, sizeof(adv));
1442 ospf6_capability_printbuf(route->path.router_bits, rbits,
1443 sizeof(rbits));
1444 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1445 inet_ntop(AF_INET, &route->path.area_id, area, sizeof(area));
1446
1447 /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1448 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL);
1449 */
1450 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s%s", adv, rbits, options,
1451 OSPF6_PATH_TYPE_NAME(route->path.type), area, VNL);
6452df09 1452}
1453
508e53e2 1454DEFUN (debug_ospf6_route,
1455 debug_ospf6_route_cmd,
6147e2c6 1456 "debug ospf6 route <table|intra-area|inter-area|memory>",
508e53e2 1457 DEBUG_STR
1458 OSPF6_STR
16cedbb0 1459 "Debug routes\n"
508e53e2 1460 "Debug route table calculation\n"
508e53e2 1461 "Debug intra-area route calculation\n"
1462 "Debug inter-area route calculation\n"
8f228de7 1463 "Debug route memory use\n"
508e53e2 1464 )
1465{
ac4d0be5 1466 int idx_type = 3;
1467 unsigned char level = 0;
1468
1469 if (!strncmp(argv[idx_type]->arg, "table", 5))
1470 level = OSPF6_DEBUG_ROUTE_TABLE;
1471 else if (!strncmp(argv[idx_type]->arg, "intra", 5))
1472 level = OSPF6_DEBUG_ROUTE_INTRA;
1473 else if (!strncmp(argv[idx_type]->arg, "inter", 5))
1474 level = OSPF6_DEBUG_ROUTE_INTER;
1475 else if (!strncmp(argv[idx_type]->arg, "memor", 5))
1476 level = OSPF6_DEBUG_ROUTE_MEMORY;
1477 OSPF6_DEBUG_ROUTE_ON(level);
1478 return CMD_SUCCESS;
508e53e2 1479}
1480
1481DEFUN (no_debug_ospf6_route,
1482 no_debug_ospf6_route_cmd,
6147e2c6 1483 "no debug ospf6 route <table|intra-area|inter-area|memory>",
508e53e2 1484 NO_STR
1485 DEBUG_STR
1486 OSPF6_STR
16cedbb0 1487 "Debug routes\n"
508e53e2 1488 "Debug route table calculation\n"
8f228de7 1489 "Debug intra-area route calculation\n"
16cedbb0 1490 "Debug inter-area route calculation\n"
8f228de7 1491 "Debug route memory use\n")
508e53e2 1492{
ac4d0be5 1493 int idx_type = 4;
1494 unsigned char level = 0;
1495
1496 if (!strncmp(argv[idx_type]->arg, "table", 5))
1497 level = OSPF6_DEBUG_ROUTE_TABLE;
1498 else if (!strncmp(argv[idx_type]->arg, "intra", 5))
1499 level = OSPF6_DEBUG_ROUTE_INTRA;
1500 else if (!strncmp(argv[idx_type]->arg, "inter", 5))
1501 level = OSPF6_DEBUG_ROUTE_INTER;
1502 else if (!strncmp(argv[idx_type]->arg, "memor", 5))
1503 level = OSPF6_DEBUG_ROUTE_MEMORY;
1504 OSPF6_DEBUG_ROUTE_OFF(level);
1505 return CMD_SUCCESS;
718e3744 1506}
1507
ac4d0be5 1508int config_write_ospf6_debug_route(struct vty *vty)
508e53e2 1509{
ac4d0be5 1510 if (IS_OSPF6_DEBUG_ROUTE(TABLE))
1511 vty_out(vty, "debug ospf6 route table%s", VNL);
1512 if (IS_OSPF6_DEBUG_ROUTE(INTRA))
1513 vty_out(vty, "debug ospf6 route intra-area%s", VNL);
1514 if (IS_OSPF6_DEBUG_ROUTE(INTER))
1515 vty_out(vty, "debug ospf6 route inter-area%s", VNL);
1516 return 0;
508e53e2 1517}
1518
ac4d0be5 1519void install_element_ospf6_debug_route(void)
508e53e2 1520{
ac4d0be5 1521 install_element(ENABLE_NODE, &debug_ospf6_route_cmd);
1522 install_element(ENABLE_NODE, &no_debug_ospf6_route_cmd);
1523 install_element(CONFIG_NODE, &debug_ospf6_route_cmd);
1524 install_element(CONFIG_NODE, &no_debug_ospf6_route_cmd);
508e53e2 1525}