Bug #362 is fixed now.
[jleu-quagga.git] / ospf6d / ospf6_route.c
blob38fdd51a6cc613c48298fc12f2cfe37ff4f79309
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <zebra.h>
24 #include "log.h"
25 #include "memory.h"
26 #include "prefix.h"
27 #include "table.h"
28 #include "vty.h"
29 #include "command.h"
30 #include "linklist.h"
32 #include "ospf6_proto.h"
33 #include "ospf6_lsa.h"
34 #include "ospf6_lsdb.h"
35 #include "ospf6_route.h"
36 #include "ospf6_top.h"
37 #include "ospf6_area.h"
38 #include "ospf6_interface.h"
39 #include "ospf6d.h"
41 unsigned char conf_debug_ospf6_route = 0;
43 static char *
44 ospf6_route_table_name (struct ospf6_route_table *table)
46 static char name[32];
47 switch (table->scope_type)
49 case OSPF6_SCOPE_TYPE_GLOBAL:
51 switch (table->table_type)
53 case OSPF6_TABLE_TYPE_ROUTES:
54 snprintf (name, sizeof (name), "global route table");
55 break;
56 case OSPF6_TABLE_TYPE_BORDER_ROUTERS:
57 snprintf (name, sizeof (name), "global brouter table");
58 break;
59 case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES:
60 snprintf (name, sizeof (name), "global external table");
61 break;
62 default:
63 snprintf (name, sizeof (name), "global unknown table");
64 break;
67 break;
69 case OSPF6_SCOPE_TYPE_AREA:
71 struct ospf6_area *oa = (struct ospf6_area *) table->scope;
72 switch (table->table_type)
74 case OSPF6_TABLE_TYPE_SPF_RESULTS:
75 snprintf (name, sizeof (name),
76 "area %s spf table", oa->name);
77 break;
78 case OSPF6_TABLE_TYPE_ROUTES:
79 snprintf (name, sizeof (name),
80 "area %s route table", oa->name);
81 break;
82 case OSPF6_TABLE_TYPE_PREFIX_RANGES:
83 snprintf (name, sizeof (name),
84 "area %s range table", oa->name);
85 break;
86 case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES:
87 snprintf (name, sizeof (name),
88 "area %s summary prefix table", oa->name);
89 break;
90 case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS:
91 snprintf (name, sizeof (name),
92 "area %s summary router table", oa->name);
93 break;
94 default:
95 snprintf (name, sizeof (name),
96 "area %s unknown table", oa->name);
97 break;
100 break;
102 case OSPF6_SCOPE_TYPE_INTERFACE:
104 struct ospf6_interface *oi = (struct ospf6_interface *) table->scope;
105 switch (table->table_type)
107 case OSPF6_TABLE_TYPE_CONNECTED_ROUTES:
108 snprintf (name, sizeof (name), "interface %s connected table",
109 oi->interface->name);
110 break;
111 default:
112 snprintf (name, sizeof (name), "interface %s unknown table",
113 oi->interface->name);
114 break;
117 break;
119 default:
121 switch (table->table_type)
123 case OSPF6_TABLE_TYPE_SPF_RESULTS:
124 snprintf (name, sizeof (name), "temporary spf table");
125 break;
126 default:
127 snprintf (name, sizeof (name), "temporary unknown table");
128 break;
131 break;
133 return name;
136 void
137 ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
138 struct prefix *prefix)
140 memset (prefix, 0, sizeof (struct prefix));
141 prefix->family = AF_INET6;
142 prefix->prefixlen = 64;
143 memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
144 memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
147 void
148 ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
150 u_int32_t adv_router, id;
151 char adv_router_str[16], id_str[16];
152 memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
153 memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
154 inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
155 inet_ntop (AF_INET, &id, id_str, sizeof (id_str));
156 if (ntohl (id))
157 snprintf (buf, size, "%s Net-ID: %s", adv_router_str, id_str);
158 else
159 snprintf (buf, size, "%s", adv_router_str);
162 /* Global strings for logging */
163 const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
164 { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", };
166 const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
167 { "?", "R", "N", "D", "L", "A", };
169 const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
170 { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
172 const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
173 { "??", "IA", "IE", "E1", "E2", };
176 struct ospf6_route *
177 ospf6_route_create ()
179 struct ospf6_route *route;
180 route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
181 return route;
184 void
185 ospf6_route_delete (struct ospf6_route *route)
187 XFREE (MTYPE_OSPF6_ROUTE, route);
190 struct ospf6_route *
191 ospf6_route_copy (struct ospf6_route *route)
193 struct ospf6_route *new;
195 new = ospf6_route_create ();
196 memcpy (new, route, sizeof (struct ospf6_route));
197 new->rnode = NULL;
198 new->prev = NULL;
199 new->next = NULL;
200 new->table = NULL;
201 new->lock = 0;
202 return new;
205 void
206 ospf6_route_lock (struct ospf6_route *route)
208 route->lock++;
211 void
212 ospf6_route_unlock (struct ospf6_route *route)
214 assert (route->lock > 0);
215 route->lock--;
216 if (route->lock == 0)
218 /* Can't detach from the table until here
219 because ospf6_route_next () will use
220 the 'route->table' pointer for logging */
221 route->table = NULL;
222 ospf6_route_delete (route);
226 /* Route compare function. If ra is more preferred, it returns
227 less than 0. If rb is more preferred returns greater than 0.
228 Otherwise (neither one is preferred), returns 0 */
229 static int
230 ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
232 assert (ospf6_route_is_same (ra, rb));
233 assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
234 ra->path.type < OSPF6_PATH_TYPE_MAX);
235 assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
236 rb->path.type < OSPF6_PATH_TYPE_MAX);
238 if (ra->type != rb->type)
239 return (ra->type - rb->type);
241 if (ra->path.area_id != rb->path.area_id)
242 return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
244 if (ra->path.type != rb->path.type)
245 return (ra->path.type - rb->path.type);
247 if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
249 if (ra->path.cost_e2 != rb->path.cost_e2)
250 return (ra->path.cost_e2 - rb->path.cost_e2);
252 else
254 if (ra->path.cost != rb->path.cost)
255 return (ra->path.cost - rb->path.cost);
258 return 0;
261 struct ospf6_route *
262 ospf6_route_lookup (struct prefix *prefix,
263 struct ospf6_route_table *table)
265 struct route_node *node;
266 struct ospf6_route *route;
268 node = route_node_lookup (table->table, prefix);
269 if (node == NULL)
270 return NULL;
272 route = (struct ospf6_route *) node->info;
273 return route;
276 struct ospf6_route *
277 ospf6_route_lookup_identical (struct ospf6_route *route,
278 struct ospf6_route_table *table)
280 struct ospf6_route *target;
282 for (target = ospf6_route_lookup (&route->prefix, table);
283 target; target = target->next)
285 if (ospf6_route_is_identical (target, route))
286 return target;
288 return NULL;
291 struct ospf6_route *
292 ospf6_route_lookup_bestmatch (struct prefix *prefix,
293 struct ospf6_route_table *table)
295 struct route_node *node;
296 struct ospf6_route *route;
298 node = route_node_match (table->table, prefix);
299 if (node == NULL)
300 return NULL;
301 route_unlock_node (node);
303 route = (struct ospf6_route *) node->info;
304 return route;
307 #ifndef NDEBUG
308 static void
309 route_table_assert (struct ospf6_route_table *table)
311 struct ospf6_route *prev, *r, *next;
312 char buf[64];
313 unsigned int link_error = 0, num = 0;
315 r = ospf6_route_head (table);
316 prev = NULL;
317 while (r)
319 if (r->prev != prev)
320 link_error++;
322 next = ospf6_route_next (r);
324 if (r->next != next)
325 link_error++;
327 prev = r;
328 r = next;
331 for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
332 num++;
334 if (link_error == 0 && num == table->count)
335 return;
337 zlog_err ("PANIC !!");
338 zlog_err ("Something has gone wrong with ospf6_route_table[%p]", table);
339 zlog_debug ("table count = %d, real number = %d", table->count, num);
340 zlog_debug ("DUMP START");
341 for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
343 prefix2str (&r->prefix, buf, sizeof (buf));
344 zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf);
346 zlog_debug ("DUMP END");
348 assert (link_error == 0 && num == table->count);
350 #define ospf6_route_table_assert(t) (route_table_assert (t))
351 #else
352 #define ospf6_route_table_assert(t) ((void) 0)
353 #endif /*NDEBUG*/
355 struct ospf6_route *
356 ospf6_route_add (struct ospf6_route *route,
357 struct ospf6_route_table *table)
359 struct route_node *node, *nextnode, *prevnode;
360 struct ospf6_route *current = NULL;
361 struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
362 char buf[64];
363 struct timeval now;
365 assert (route->rnode == NULL);
366 assert (route->lock == 0);
367 assert (route->next == NULL);
368 assert (route->prev == NULL);
370 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
371 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
372 else
373 prefix2str (&route->prefix, buf, sizeof (buf));
375 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
376 zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table),
377 table, route, buf);
378 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
379 zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
381 gettimeofday (&now, NULL);
383 node = route_node_get (table->table, &route->prefix);
384 route->rnode = node;
386 /* find place to insert */
387 for (current = node->info; current; current = current->next)
389 if (! ospf6_route_is_same (current, route))
390 next = current;
391 else if (current->type != route->type)
392 prev = current;
393 else if (ospf6_route_is_same_origin (current, route))
394 old = current;
395 else if (ospf6_route_cmp (current, route) > 0)
396 next = current;
397 else
398 prev = current;
400 if (old || next)
401 break;
404 if (old)
406 /* if route does not actually change, return unchanged */
407 if (ospf6_route_is_identical (old, route))
409 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
410 zlog_debug ("%s %p: route add %p: needless update of %p",
411 ospf6_route_table_name (table), table, route, old);
412 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
413 zlog_debug ("%s: route add: needless update",
414 ospf6_route_table_name (table));
416 ospf6_route_delete (route);
417 SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
418 ospf6_route_table_assert (table);
420 return old;
423 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
424 zlog_debug ("%s %p: route add %p: update of %p",
425 ospf6_route_table_name (table), table, route, old);
426 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
427 zlog_debug ("%s: route add: update",
428 ospf6_route_table_name (table));
430 /* replace old one if exists */
431 if (node->info == old)
433 node->info = route;
434 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
437 if (old->prev)
438 old->prev->next = route;
439 route->prev = old->prev;
440 if (old->next)
441 old->next->prev = route;
442 route->next = old->next;
444 route->installed = old->installed;
445 route->changed = now;
446 assert (route->table == NULL);
447 route->table = table;
449 ospf6_route_unlock (old); /* will be deleted later */
450 ospf6_route_lock (route);
452 SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
453 ospf6_route_table_assert (table);
455 if (table->hook_add)
456 (*table->hook_add) (route);
458 return route;
461 /* insert if previous or next node found */
462 if (prev || next)
464 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
465 zlog_debug ("%s %p: route add %p: another path: prev %p, next %p",
466 ospf6_route_table_name (table), table, route, prev, next);
467 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
468 zlog_debug ("%s: route add: another path found",
469 ospf6_route_table_name (table));
471 if (prev == NULL)
472 prev = next->prev;
473 if (next == NULL)
474 next = prev->next;
476 if (prev)
477 prev->next = route;
478 route->prev = prev;
479 if (next)
480 next->prev = route;
481 route->next = next;
483 if (node->info == next)
485 assert (next->rnode == node);
486 node->info = route;
487 UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
488 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
489 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
490 zlog_info ("%s %p: route add %p: replacing previous best: %p",
491 ospf6_route_table_name (table), table, route, next);
494 route->installed = now;
495 route->changed = now;
496 assert (route->table == NULL);
497 route->table = table;
499 ospf6_route_lock (route);
500 table->count++;
501 ospf6_route_table_assert (table);
503 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
504 if (table->hook_add)
505 (*table->hook_add) (route);
507 return route;
510 /* Else, this is the brand new route regarding to the prefix */
511 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
512 zlog_debug ("%s %p: route add %p: brand new route",
513 ospf6_route_table_name (table), table, route);
514 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
515 zlog_debug ("%s: route add: brand new route",
516 ospf6_route_table_name (table));
518 assert (node->info == NULL);
519 node->info = route;
520 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
521 ospf6_route_lock (route);
522 route->installed = now;
523 route->changed = now;
524 assert (route->table == NULL);
525 route->table = table;
527 /* lookup real existing next route */
528 nextnode = node;
529 route_lock_node (nextnode);
530 do {
531 nextnode = route_next (nextnode);
532 } while (nextnode && nextnode->info == NULL);
534 /* set next link */
535 if (nextnode == NULL)
536 route->next = NULL;
537 else
539 route_unlock_node (nextnode);
541 next = nextnode->info;
542 route->next = next;
543 next->prev = route;
546 /* lookup real existing prev route */
547 prevnode = node;
548 route_lock_node (prevnode);
549 do {
550 prevnode = route_prev (prevnode);
551 } while (prevnode && prevnode->info == NULL);
553 /* set prev link */
554 if (prevnode == NULL)
555 route->prev = NULL;
556 else
558 route_unlock_node (prevnode);
560 prev = prevnode->info;
561 while (prev->next && ospf6_route_is_same (prev, prev->next))
562 prev = prev->next;
563 route->prev = prev;
564 prev->next = route;
567 table->count++;
568 ospf6_route_table_assert (table);
570 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
571 if (table->hook_add)
572 (*table->hook_add) (route);
574 return route;
577 void
578 ospf6_route_remove (struct ospf6_route *route,
579 struct ospf6_route_table *table)
581 struct route_node *node;
582 struct ospf6_route *current;
583 char buf[64];
585 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
586 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
587 else
588 prefix2str (&route->prefix, buf, sizeof (buf));
590 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
591 zlog_debug ("%s %p: route remove %p: %s",
592 ospf6_route_table_name (table), table, route, buf);
593 else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
594 zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf);
596 node = route_node_lookup (table->table, &route->prefix);
597 assert (node);
599 /* find the route to remove, making sure that the route pointer
600 is from the route table. */
601 current = node->info;
602 while (current && ospf6_route_is_same (current, route))
604 if (current == route)
605 break;
606 current = current->next;
608 assert (current == route);
610 /* adjust doubly linked list */
611 if (route->prev)
612 route->prev->next = route->next;
613 if (route->next)
614 route->next->prev = route->prev;
616 if (node->info == route)
618 if (route->next && ospf6_route_is_same (route->next, route))
620 node->info = route->next;
621 SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
623 else
624 node->info = NULL; /* should unlock route_node here ? */
627 table->count--;
628 ospf6_route_table_assert (table);
630 SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED);
632 if (table->hook_remove)
633 (*table->hook_remove) (route);
635 ospf6_route_unlock (route);
638 struct ospf6_route *
639 ospf6_route_head (struct ospf6_route_table *table)
641 struct route_node *node;
642 struct ospf6_route *route;
644 node = route_top (table->table);
645 if (node == NULL)
646 return NULL;
648 /* skip to the real existing entry */
649 while (node && node->info == NULL)
650 node = route_next (node);
651 if (node == NULL)
652 return NULL;
654 route_unlock_node (node);
655 assert (node->info);
657 route = (struct ospf6_route *) node->info;
658 assert (route->prev == NULL);
659 assert (route->table == table);
660 ospf6_route_lock (route);
662 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
663 zlog_info ("%s %p: route head: %p<-[%p]->%p",
664 ospf6_route_table_name (table), table,
665 route->prev, route, route->next);
667 return route;
670 struct ospf6_route *
671 ospf6_route_next (struct ospf6_route *route)
673 struct ospf6_route *next = route->next;
675 if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
676 zlog_info ("%s %p: route next: %p<-[%p]->%p",
677 ospf6_route_table_name (route->table), route->table,
678 route->prev, route, route->next);
680 ospf6_route_unlock (route);
681 if (next)
682 ospf6_route_lock (next);
684 return next;
687 struct ospf6_route *
688 ospf6_route_best_next (struct ospf6_route *route)
690 struct route_node *rnode;
691 struct ospf6_route *next;
693 rnode = route->rnode;
694 route_lock_node (rnode);
695 rnode = route_next (rnode);
696 while (rnode && rnode->info == NULL)
697 rnode = route_next (rnode);
698 if (rnode == NULL)
699 return NULL;
700 route_unlock_node (rnode);
702 assert (rnode->info);
703 next = (struct ospf6_route *) rnode->info;
704 ospf6_route_unlock (route);
705 ospf6_route_lock (next);
706 return next;
709 /* Macro version of check_bit (). */
710 #define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
712 struct ospf6_route *
713 ospf6_route_match_head (struct prefix *prefix,
714 struct ospf6_route_table *table)
716 struct route_node *node;
717 struct ospf6_route *route;
719 /* Walk down tree. */
720 node = table->table->top;
721 while (node && node->p.prefixlen < prefix->prefixlen &&
722 prefix_match (&node->p, prefix))
723 node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
725 if (node)
726 route_lock_node (node);
727 while (node && node->info == NULL)
728 node = route_next (node);
729 if (node == NULL)
730 return NULL;
731 route_unlock_node (node);
733 if (! prefix_match (prefix, &node->p))
734 return NULL;
736 route = node->info;
737 ospf6_route_lock (route);
738 return route;
741 struct ospf6_route *
742 ospf6_route_match_next (struct prefix *prefix,
743 struct ospf6_route *route)
745 struct ospf6_route *next;
747 next = ospf6_route_next (route);
748 if (next && ! prefix_match (prefix, &next->prefix))
750 ospf6_route_unlock (next);
751 next = NULL;
754 return next;
757 void
758 ospf6_route_remove_all (struct ospf6_route_table *table)
760 struct ospf6_route *route;
761 for (route = ospf6_route_head (table); route;
762 route = ospf6_route_next (route))
763 ospf6_route_remove (route, table);
766 struct ospf6_route_table *
767 ospf6_route_table_create (int s, int t)
769 struct ospf6_route_table *new;
770 new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
771 new->table = route_table_init ();
772 new->scope_type = s;
773 new->table_type = t;
774 return new;
777 void
778 ospf6_route_table_delete (struct ospf6_route_table *table)
780 ospf6_route_remove_all (table);
781 route_table_finish (table->table);
782 XFREE (MTYPE_OSPF6_ROUTE, table);
786 /* VTY commands */
787 void
788 ospf6_route_show (struct vty *vty, struct ospf6_route *route)
790 int i;
791 char destination[64], nexthop[64];
792 char duration[16], ifname[IFNAMSIZ];
793 struct timeval now, res;
795 gettimeofday (&now, (struct timezone *) NULL);
796 timersub (&now, &route->changed, &res);
797 timerstring (&res, duration, sizeof (duration));
799 /* destination */
800 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
801 ospf6_linkstate_prefix2str (&route->prefix, destination,
802 sizeof (destination));
803 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
804 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
805 destination, sizeof (destination));
806 else
807 prefix2str (&route->prefix, destination, sizeof (destination));
809 /* nexthop */
810 inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
811 sizeof (nexthop));
812 if (! if_indextoname (route->nexthop[0].ifindex, ifname))
813 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
815 vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
816 (ospf6_route_is_best (route) ? '*' : ' '),
817 OSPF6_DEST_TYPE_SUBSTR (route->type),
818 OSPF6_PATH_TYPE_SUBSTR (route->path.type),
819 destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
821 for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
822 i < OSPF6_MULTI_PATH_LIMIT; i++)
824 /* nexthop */
825 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
826 sizeof (nexthop));
827 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
828 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
830 vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
831 ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
835 void
836 ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
838 char destination[64], nexthop[64], ifname[IFNAMSIZ];
839 char area_id[16], id[16], adv_router[16], capa[16], options[16];
840 struct timeval now, res;
841 char duration[16];
842 int i;
844 gettimeofday (&now, (struct timezone *) NULL);
846 /* destination */
847 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
848 ospf6_linkstate_prefix2str (&route->prefix, destination,
849 sizeof (destination));
850 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
851 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
852 destination, sizeof (destination));
853 else
854 prefix2str (&route->prefix, destination, sizeof (destination));
855 vty_out (vty, "Destination: %s%s", destination, VNL);
857 /* destination type */
858 vty_out (vty, "Destination type: %s%s",
859 OSPF6_DEST_TYPE_NAME (route->type),
860 VNL);
862 /* Time */
863 timersub (&now, &route->installed, &res);
864 timerstring (&res, duration, sizeof (duration));
865 vty_out (vty, "Installed Time: %s ago%s", duration, VNL);
867 timersub (&now, &route->changed, &res);
868 timerstring (&res, duration, sizeof (duration));
869 vty_out (vty, " Changed Time: %s ago%s", duration, VNL);
871 /* Debugging info */
872 vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
873 (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
874 (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
875 (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
876 (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
877 VNL);
878 vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
879 route->prev, route, route->next, VNL);
881 /* Path section */
883 /* Area-ID */
884 inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
885 vty_out (vty, "Associated Area: %s%s", area_id, VNL);
887 /* Path type */
888 vty_out (vty, "Path Type: %s%s",
889 OSPF6_PATH_TYPE_NAME (route->path.type), VNL);
891 /* LS Origin */
892 inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
893 inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
894 sizeof (adv_router));
895 vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
896 ospf6_lstype_name (route->path.origin.type),
897 id, adv_router, VNL);
899 /* Options */
900 ospf6_options_printbuf (route->path.options, options, sizeof (options));
901 vty_out (vty, "Options: %s%s", options, VNL);
903 /* Router Bits */
904 ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
905 vty_out (vty, "Router Bits: %s%s", capa, VNL);
907 /* Prefix Options */
908 vty_out (vty, "Prefix Options: xxx%s", VNL);
910 /* Metrics */
911 vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
912 VNL);
913 vty_out (vty, "Metric: %d (%d)%s",
914 route->path.cost, route->path.cost_e2, VNL);
916 /* Nexthops */
917 vty_out (vty, "Nexthop:%s", VNL);
918 for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
919 i < OSPF6_MULTI_PATH_LIMIT; i++)
921 /* nexthop */
922 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
923 sizeof (nexthop));
924 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
925 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
926 vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
928 vty_out (vty, "%s", VNL);
931 void
932 ospf6_route_show_table_summary (struct vty *vty,
933 struct ospf6_route_table *table)
935 struct ospf6_route *route, *prev = NULL;
936 int i, pathtype[OSPF6_PATH_TYPE_MAX];
937 unsigned int number = 0;
938 int nhinval = 0, ecmp = 0;
939 int alternative = 0, destination = 0;
941 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
942 pathtype[i] = 0;
944 for (route = ospf6_route_head (table); route;
945 route = ospf6_route_next (route))
947 if (prev == NULL || ! ospf6_route_is_same (prev, route))
948 destination++;
949 else
950 alternative++;
951 if (! ospf6_nexthop_is_set (&route->nexthop[0]))
952 nhinval++;
953 else if (ospf6_nexthop_is_set (&route->nexthop[1]))
954 ecmp++;
955 pathtype[route->path.type]++;
956 number++;
958 prev = route;
961 assert (number == table->count);
963 vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL);
964 vty_out (vty, "Number of Destination: %d%s", destination, VNL);
965 vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL);
966 vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL);
967 for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++)
969 vty_out (vty, "Number of %s routes: %d%s",
970 OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL);
974 void
975 ospf6_route_show_table_prefix (struct vty *vty,
976 struct prefix *prefix,
977 struct ospf6_route_table *table)
979 struct ospf6_route *route;
981 route = ospf6_route_lookup (prefix, table);
982 if (route == NULL)
983 return;
985 ospf6_route_lock (route);
986 while (route && ospf6_route_is_prefix (prefix, route))
988 /* Specifying a prefix will always display details */
989 ospf6_route_show_detail (vty, route);
990 route = ospf6_route_next (route);
992 if (route)
993 ospf6_route_unlock (route);
996 void
997 ospf6_route_show_table_address (struct vty *vty,
998 struct prefix *prefix,
999 struct ospf6_route_table *table)
1001 struct ospf6_route *route;
1003 route = ospf6_route_lookup_bestmatch (prefix, table);
1004 if (route == NULL)
1005 return;
1007 prefix = &route->prefix;
1008 ospf6_route_lock (route);
1009 while (route && ospf6_route_is_prefix (prefix, route))
1011 /* Specifying a prefix will always display details */
1012 ospf6_route_show_detail (vty, route);
1013 route = ospf6_route_next (route);
1015 if (route)
1016 ospf6_route_unlock (route);
1019 void
1020 ospf6_route_show_table_match (struct vty *vty, int detail,
1021 struct prefix *prefix,
1022 struct ospf6_route_table *table)
1024 struct ospf6_route *route;
1025 assert (prefix->family);
1027 route = ospf6_route_match_head (prefix, table);
1028 while (route)
1030 if (detail)
1031 ospf6_route_show_detail (vty, route);
1032 else
1033 ospf6_route_show (vty, route);
1034 route = ospf6_route_match_next (prefix, route);
1038 void
1039 ospf6_route_show_table_type (struct vty *vty, int detail, u_char type,
1040 struct ospf6_route_table *table)
1042 struct ospf6_route *route;
1044 route = ospf6_route_head (table);
1045 while (route)
1047 if (route->path.type == type)
1049 if (detail)
1050 ospf6_route_show_detail (vty, route);
1051 else
1052 ospf6_route_show (vty, route);
1054 route = ospf6_route_next (route);
1058 void
1059 ospf6_route_show_table (struct vty *vty, int detail,
1060 struct ospf6_route_table *table)
1062 struct ospf6_route *route;
1064 route = ospf6_route_head (table);
1065 while (route)
1067 if (detail)
1068 ospf6_route_show_detail (vty, route);
1069 else
1070 ospf6_route_show (vty, route);
1071 route = ospf6_route_next (route);
1076 ospf6_route_table_show (struct vty *vty, int argc, const char *argv[],
1077 struct ospf6_route_table *table)
1079 int summary = 0;
1080 int match = 0;
1081 int detail = 0;
1082 int slash = 0;
1083 int isprefix = 0;
1084 int i, ret;
1085 struct prefix prefix;
1086 u_char type = 0;
1088 memset (&prefix, 0, sizeof (struct prefix));
1090 for (i = 0; i < argc; i++)
1092 if (! strcmp (argv[i], "summary"))
1094 summary++;
1095 continue;
1098 if (! strcmp (argv[i], "intra-area"))
1100 type = OSPF6_PATH_TYPE_INTRA;
1101 continue;
1104 if (! strcmp (argv[i], "inter-area"))
1106 type = OSPF6_PATH_TYPE_INTER;
1107 continue;
1110 if (! strcmp (argv[i], "external-1"))
1112 type = OSPF6_PATH_TYPE_EXTERNAL1;
1113 continue;
1116 if (! strcmp (argv[i], "external-2"))
1118 type = OSPF6_PATH_TYPE_EXTERNAL2;
1119 continue;
1122 if (! strcmp (argv[i], "detail"))
1124 detail++;
1125 continue;
1128 if (! strcmp (argv[i], "match"))
1130 match++;
1131 continue;
1134 ret = str2prefix (argv[i], &prefix);
1135 if (ret == 1 && prefix.family == AF_INET6)
1137 isprefix++;
1138 if (strchr (argv[i], '/'))
1139 slash++;
1140 continue;
1143 vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1144 return CMD_SUCCESS;
1147 /* Give summary of this route table */
1148 if (summary)
1150 ospf6_route_show_table_summary (vty, table);
1151 return CMD_SUCCESS;
1154 /* Give exact prefix-match route */
1155 if (isprefix && ! match)
1157 /* If exact address, give best matching route */
1158 if (! slash)
1159 ospf6_route_show_table_address (vty, &prefix, table);
1160 else
1161 ospf6_route_show_table_prefix (vty, &prefix, table);
1163 return CMD_SUCCESS;
1166 if (match)
1167 ospf6_route_show_table_match (vty, detail, &prefix, table);
1168 else if (type)
1169 ospf6_route_show_table_type (vty, detail, type, table);
1170 else
1171 ospf6_route_show_table (vty, detail, table);
1173 return CMD_SUCCESS;
1176 void
1177 ospf6_linkstate_show_header (struct vty *vty)
1179 vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s",
1180 "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL);
1183 void
1184 ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route)
1186 u_int32_t router, id;
1187 char routername[16], idname[16], rbits[16], options[16];
1189 router = ospf6_linkstate_prefix_adv_router (&route->prefix);
1190 inet_ntop (AF_INET, &router, routername, sizeof (routername));
1191 id = ospf6_linkstate_prefix_id (&route->prefix);
1192 inet_ntop (AF_INET, &id, idname, sizeof (idname));
1194 ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
1195 ospf6_options_printbuf (route->path.options, options, sizeof (options));
1197 if (ntohl (id))
1198 vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
1199 "Network", routername, idname, rbits, options,
1200 (unsigned long) route->path.cost, VNL);
1201 else
1202 vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
1203 "Router", routername, idname, rbits, options,
1204 (unsigned long) route->path.cost, VNL);
1208 void
1209 ospf6_linkstate_show_table_exact (struct vty *vty,
1210 struct prefix *prefix,
1211 struct ospf6_route_table *table)
1213 struct ospf6_route *route;
1215 route = ospf6_route_lookup (prefix, table);
1216 if (route == NULL)
1217 return;
1219 ospf6_route_lock (route);
1220 while (route && ospf6_route_is_prefix (prefix, route))
1222 /* Specifying a prefix will always display details */
1223 ospf6_route_show_detail (vty, route);
1224 route = ospf6_route_next (route);
1226 if (route)
1227 ospf6_route_unlock (route);
1230 void
1231 ospf6_linkstate_show_table (struct vty *vty, int detail,
1232 struct ospf6_route_table *table)
1234 struct ospf6_route *route;
1236 if (! detail)
1237 ospf6_linkstate_show_header (vty);
1239 route = ospf6_route_head (table);
1240 while (route)
1242 if (detail)
1243 ospf6_route_show_detail (vty, route);
1244 else
1245 ospf6_linkstate_show (vty, route);
1246 route = ospf6_route_next (route);
1251 ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[],
1252 struct ospf6_route_table *table)
1254 int detail = 0;
1255 int is_id = 0;
1256 int is_router = 0;
1257 int i, ret;
1258 struct prefix router, id, prefix;
1260 memset (&router, 0, sizeof (struct prefix));
1261 memset (&id, 0, sizeof (struct prefix));
1262 memset (&prefix, 0, sizeof (struct prefix));
1264 for (i = 0; i < argc; i++)
1266 if (! strcmp (argv[i], "detail"))
1268 detail++;
1269 continue;
1272 if (! is_router)
1274 ret = str2prefix (argv[i], &router);
1275 if (ret == 1 && router.family == AF_INET)
1277 is_router++;
1278 continue;
1280 vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1281 return CMD_SUCCESS;
1284 if (! is_id)
1286 ret = str2prefix (argv[i], &id);
1287 if (ret == 1 && id.family == AF_INET)
1289 is_id++;
1290 continue;
1292 vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1293 return CMD_SUCCESS;
1296 vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1297 return CMD_SUCCESS;
1300 if (is_router)
1301 ospf6_linkstate_prefix (router.u.prefix4.s_addr,
1302 id.u.prefix4.s_addr, &prefix);
1304 if (prefix.family)
1305 ospf6_linkstate_show_table_exact (vty, &prefix, table);
1306 else
1307 ospf6_linkstate_show_table (vty, detail, table);
1309 return CMD_SUCCESS;
1313 void
1314 ospf6_brouter_show_header (struct vty *vty)
1316 vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1317 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL);
1320 void
1321 ospf6_brouter_show (struct vty *vty, struct ospf6_route *route)
1323 u_int32_t adv_router;
1324 char adv[16], rbits[16], options[16], area[16];
1326 adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix);
1327 inet_ntop (AF_INET, &adv_router, adv, sizeof (adv));
1328 ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
1329 ospf6_options_printbuf (route->path.options, options, sizeof (options));
1330 inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area));
1332 /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1333 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */
1334 vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1335 adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type),
1336 area, VNL);
1339 DEFUN (debug_ospf6_route,
1340 debug_ospf6_route_cmd,
1341 "debug ospf6 route (table|intra-area|inter-area)",
1342 DEBUG_STR
1343 OSPF6_STR
1344 "Debug route table calculation\n"
1345 "Debug detail\n"
1346 "Debug intra-area route calculation\n"
1347 "Debug inter-area route calculation\n"
1350 unsigned char level = 0;
1352 if (! strncmp (argv[0], "table", 5))
1353 level = OSPF6_DEBUG_ROUTE_TABLE;
1354 else if (! strncmp (argv[0], "intra", 5))
1355 level = OSPF6_DEBUG_ROUTE_INTRA;
1356 else if (! strncmp (argv[0], "inter", 5))
1357 level = OSPF6_DEBUG_ROUTE_INTER;
1358 OSPF6_DEBUG_ROUTE_ON (level);
1359 return CMD_SUCCESS;
1362 DEFUN (no_debug_ospf6_route,
1363 no_debug_ospf6_route_cmd,
1364 "no debug ospf6 route (table|intra-area|inter-area)",
1365 NO_STR
1366 DEBUG_STR
1367 OSPF6_STR
1368 "Debug route table calculation\n"
1369 "Debug intra-area route calculation\n")
1371 unsigned char level = 0;
1373 if (! strncmp (argv[0], "table", 5))
1374 level = OSPF6_DEBUG_ROUTE_TABLE;
1375 else if (! strncmp (argv[0], "intra", 5))
1376 level = OSPF6_DEBUG_ROUTE_INTRA;
1377 else if (! strncmp (argv[0], "inter", 5))
1378 level = OSPF6_DEBUG_ROUTE_INTER;
1379 OSPF6_DEBUG_ROUTE_OFF (level);
1380 return CMD_SUCCESS;
1384 config_write_ospf6_debug_route (struct vty *vty)
1386 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
1387 vty_out (vty, "debug ospf6 route table%s", VNL);
1388 if (IS_OSPF6_DEBUG_ROUTE (INTRA))
1389 vty_out (vty, "debug ospf6 route intra-area%s", VNL);
1390 if (IS_OSPF6_DEBUG_ROUTE (INTER))
1391 vty_out (vty, "debug ospf6 route inter-area%s", VNL);
1392 return 0;
1395 void
1396 install_element_ospf6_debug_route ()
1398 install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
1399 install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
1400 install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
1401 install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);