]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_route.c
9e64ea01efcfa20b9caa08ab0dee658acb56c024
[mirror_frr.git] / ospf6d / ospf6_route.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
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
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.
20 */
21
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"
30
31 #include "ospf6_proto.h"
32 #include "ospf6_lsa.h"
33 #include "ospf6_lsdb.h"
34 #include "ospf6_route.h"
35 #include "ospf6d.h"
36
37 unsigned char conf_debug_ospf6_route = 0;
38
39 void
40 ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
41 struct prefix *prefix)
42 {
43 memset (prefix, 0, sizeof (struct prefix));
44 prefix->family = AF_INET6;
45 prefix->prefixlen = 64;
46 memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
47 memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
48 }
49
50 void
51 ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
52 {
53 u_int32_t adv_router, id;
54 char adv_router_str[16];
55 memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
56 memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
57 inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
58 snprintf (buf, size, "%s(%lu)", adv_router_str, (u_long) ntohl (id));
59 }
60
61 /* Global strings for logging */
62 char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
63 { "Unknown", "Router", "Network", "Discard", "Linkstate", };
64
65 char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
66 { "?", "R", "N", "D", "L", };
67
68 char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
69 { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
70
71 char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
72 { "??", "Ia", "Ie", "E1", "E2", };
73
74
75 struct ospf6_route *
76 ospf6_route_create ()
77 {
78 struct ospf6_route *route;
79 route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
80 return route;
81 }
82
83 void
84 ospf6_route_delete (struct ospf6_route *route)
85 {
86 XFREE (MTYPE_OSPF6_ROUTE, route);
87 }
88
89 struct ospf6_route *
90 ospf6_route_copy (struct ospf6_route *route)
91 {
92 struct ospf6_route *new;
93
94 new = ospf6_route_create ();
95 memcpy (new, route, sizeof (struct ospf6_route));
96 new->rnode = NULL;
97 new->prev = NULL;
98 new->next = NULL;
99 new->lock = 0;
100 return new;
101 }
102
103 void
104 ospf6_route_lock (struct ospf6_route *route)
105 {
106 route->lock++;
107 }
108
109 void
110 ospf6_route_unlock (struct ospf6_route *route)
111 {
112 assert (route->lock > 0);
113 route->lock--;
114 if (route->lock == 0)
115 ospf6_route_delete (route);
116 }
117
118 /* Route compare function. If ra is more preferred, it returns
119 less than 0. If rb is more preferred returns greater than 0.
120 Otherwise (neither one is preferred), returns 0 */
121 static int
122 ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
123 {
124 assert (ospf6_route_is_same (ra, rb));
125 assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
126 ra->path.type < OSPF6_PATH_TYPE_MAX);
127 assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
128 rb->path.type < OSPF6_PATH_TYPE_MAX);
129
130 if (ra->type != rb->type)
131 return (ra->type - rb->type);
132
133 if (ra->path.area_id != rb->path.area_id)
134 return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
135
136 if (ra->path.type != rb->path.type)
137 return (ra->path.type - rb->path.type);
138
139 if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
140 {
141 if (ra->path.cost_e2 != rb->path.cost_e2)
142 return (ra->path.cost_e2 - rb->path.cost_e2);
143 }
144 else
145 {
146 if (ra->path.cost != rb->path.cost)
147 return (ra->path.cost - rb->path.cost);
148 }
149
150 return 0;
151 }
152
153 struct ospf6_route *
154 ospf6_route_lookup (struct prefix *prefix,
155 struct ospf6_route_table *table)
156 {
157 struct route_node *node;
158 struct ospf6_route *route;
159
160 node = route_node_lookup (table->table, prefix);
161 if (node == NULL)
162 return NULL;
163
164 route = (struct ospf6_route *) node->info;
165 return route;
166 }
167
168 struct ospf6_route *
169 ospf6_route_lookup_identical (struct ospf6_route *route,
170 struct ospf6_route_table *table)
171 {
172 struct ospf6_route *target;
173
174 for (target = ospf6_route_lookup (&route->prefix, table);
175 target; target = target->next)
176 {
177 if (ospf6_route_is_identical (target, route))
178 return target;
179 }
180 return NULL;
181 }
182
183 struct ospf6_route *
184 ospf6_route_lookup_bestmatch (struct prefix *prefix,
185 struct ospf6_route_table *table)
186 {
187 struct route_node *node;
188 struct ospf6_route *route;
189
190 node = route_node_match (table->table, prefix);
191 if (node == NULL)
192 return NULL;
193 route_unlock_node (node);
194
195 route = (struct ospf6_route *) node->info;
196 return route;
197 }
198
199 #ifndef NDEBUG
200 static void
201 _route_count_assert (struct ospf6_route_table *table)
202 {
203 struct ospf6_route *debug;
204 int num = 0;
205 for (debug = ospf6_route_head (table); debug;
206 debug = ospf6_route_next (debug))
207 num++;
208 assert (num == table->count);
209 }
210 #define ospf6_route_count_assert(t) (_route_count_assert (t))
211 #else
212 #define ospf6_route_count_assert(t) ((void) 0)
213 #endif /*NDEBUG*/
214
215 struct ospf6_route *
216 ospf6_route_add (struct ospf6_route *route,
217 struct ospf6_route_table *table)
218 {
219 struct route_node *node, *nextnode, *prevnode;
220 struct ospf6_route *current = NULL;
221 struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
222 char buf[64];
223 struct timeval now;
224
225 assert (route->rnode == NULL);
226 assert (route->lock == 0);
227 assert (route->next == NULL);
228 assert (route->prev == NULL);
229
230 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
231 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
232 else
233 prefix2str (&route->prefix, buf, sizeof (buf));
234
235 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
236 zlog_info ("route add %s", buf);
237
238 gettimeofday (&now, NULL);
239
240 node = route_node_get (table->table, &route->prefix);
241 route->rnode = node;
242
243 /* find place to insert */
244 for (current = node->info; current; current = current->next)
245 {
246 if (! ospf6_route_is_same (current, route))
247 next = current;
248 else if (current->type != route->type)
249 prev = current;
250 else if (ospf6_route_is_same_origin (current, route))
251 old = current;
252 else if (ospf6_route_cmp (current, route) > 0)
253 next = current;
254 else
255 prev = current;
256
257 if (old || next)
258 break;
259 }
260
261 if (old)
262 {
263 /* if route does not actually change, return unchanged */
264 if (ospf6_route_is_identical (old, route))
265 {
266 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
267 zlog_info (" identical route found, ignore");
268
269 ospf6_route_delete (route);
270 SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
271 ospf6_route_count_assert (table);
272 return old;
273 }
274
275 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
276 zlog_info (" old route found, replace");
277
278 /* replace old one if exists */
279 if (node->info == old)
280 {
281 node->info = route;
282 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
283 }
284
285 if (old->prev)
286 old->prev->next = route;
287 route->prev = old->prev;
288 if (old->next)
289 old->next->prev = route;
290 route->next = old->next;
291
292 route->installed = old->installed;
293 route->changed = now;
294
295 ospf6_route_unlock (old); /* will be deleted later */
296 ospf6_route_lock (route);
297
298 SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
299 if (table->hook_add)
300 (*table->hook_add) (route);
301
302 ospf6_route_count_assert (table);
303 return route;
304 }
305
306 /* insert if previous or next node found */
307 if (prev || next)
308 {
309 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
310 zlog_info (" another path found, insert");
311
312 if (prev == NULL)
313 prev = next->prev;
314 if (next == NULL)
315 next = prev->next;
316
317 if (prev)
318 prev->next = route;
319 route->prev = prev;
320 if (next)
321 next->prev = route;
322 route->next = next;
323
324 if (node->info == next)
325 {
326 assert (next->rnode == node);
327 node->info = route;
328 UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
329 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
330 }
331
332 route->installed = now;
333 route->changed = now;
334
335 ospf6_route_lock (route);
336 table->count++;
337
338 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
339 if (table->hook_add)
340 (*table->hook_add) (route);
341
342 ospf6_route_count_assert (table);
343 return route;
344 }
345
346 /* Else, this is the brand new route regarding to the prefix */
347 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
348 zlog_info (" brand new route, add");
349
350 assert (node->info == NULL);
351 node->info = route;
352 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
353 ospf6_route_lock (route);
354 route->installed = now;
355 route->changed = now;
356
357 /* lookup real existing next route */
358 nextnode = node;
359 route_lock_node (nextnode);
360 do {
361 nextnode = route_next (nextnode);
362 } while (nextnode && nextnode->info == NULL);
363
364 /* set next link */
365 if (nextnode == NULL)
366 route->next = NULL;
367 else
368 {
369 route_unlock_node (nextnode);
370
371 next = nextnode->info;
372 route->next = next;
373 next->prev = route;
374 }
375
376 /* lookup real existing prev route */
377 prevnode = node;
378 route_lock_node (prevnode);
379 do {
380 prevnode = route_prev (prevnode);
381 } while (prevnode && prevnode->info == NULL);
382
383 /* set prev link */
384 if (prevnode == NULL)
385 route->prev = NULL;
386 else
387 {
388 route_unlock_node (prevnode);
389
390 prev = prevnode->info;
391 while (prev->next && ospf6_route_is_same (prev, prev->next))
392 prev = prev->next;
393 route->prev = prev;
394 prev->next = route;
395 }
396
397 table->count++;
398
399 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
400 if (table->hook_add)
401 (*table->hook_add) (route);
402
403 ospf6_route_count_assert (table);
404 return route;
405 }
406
407 void
408 ospf6_route_remove (struct ospf6_route *route,
409 struct ospf6_route_table *table)
410 {
411 struct route_node *node;
412 struct ospf6_route *current;
413 char buf[64];
414
415 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
416 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
417 else
418 prefix2str (&route->prefix, buf, sizeof (buf));
419
420 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
421 zlog_info ("route remove: %s", buf);
422
423 node = route_node_lookup (table->table, &route->prefix);
424 assert (node);
425
426 /* find the route to remove, making sure that the route pointer
427 is from the route table. */
428 current = node->info;
429 while (current && ospf6_route_is_same (current, route))
430 {
431 if (current == route)
432 break;
433 current = current->next;
434 }
435 assert (current == route);
436
437 /* adjust doubly linked list */
438 if (route->prev)
439 route->prev->next = route->next;
440 if (route->next)
441 route->next->prev = route->prev;
442
443 if (node->info == route)
444 {
445 if (route->next && ospf6_route_is_same (route->next, route))
446 {
447 node->info = route->next;
448 SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
449 }
450 else
451 node->info = NULL; /* should unlock route_node here ? */
452 }
453
454 if (table->hook_remove)
455 (*table->hook_remove) (route);
456
457 ospf6_route_unlock (route);
458 table->count--;
459
460 ospf6_route_count_assert (table);
461 }
462
463 struct ospf6_route *
464 ospf6_route_head (struct ospf6_route_table *table)
465 {
466 struct route_node *node;
467 struct ospf6_route *route;
468
469 node = route_top (table->table);
470 if (node == NULL)
471 return NULL;
472
473 /* skip to the real existing entry */
474 while (node && node->info == NULL)
475 node = route_next (node);
476 if (node == NULL)
477 return NULL;
478
479 route_unlock_node (node);
480 assert (node->info);
481
482 route = (struct ospf6_route *) node->info;
483 assert (route->prev == NULL);
484 ospf6_route_lock (route);
485 return route;
486 }
487
488 struct ospf6_route *
489 ospf6_route_next (struct ospf6_route *route)
490 {
491 struct ospf6_route *next = route->next;
492
493 ospf6_route_unlock (route);
494 if (next)
495 ospf6_route_lock (next);
496
497 return next;
498 }
499
500 struct ospf6_route *
501 ospf6_route_best_next (struct ospf6_route *route)
502 {
503 struct route_node *rnode;
504 struct ospf6_route *next;
505
506 rnode = route->rnode;
507 route_lock_node (rnode);
508 rnode = route_next (rnode);
509 while (rnode && rnode->info == NULL)
510 rnode = route_next (rnode);
511 if (rnode == NULL)
512 return NULL;
513 route_unlock_node (rnode);
514
515 assert (rnode->info);
516 next = (struct ospf6_route *) rnode->info;
517 ospf6_route_unlock (route);
518 ospf6_route_lock (next);
519 return next;
520 }
521
522 /* Macro version of check_bit (). */
523 #define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
524
525 struct ospf6_route *
526 ospf6_route_match_head (struct prefix *prefix,
527 struct ospf6_route_table *table)
528 {
529 struct route_node *node;
530 struct ospf6_route *route;
531
532 /* Walk down tree. */
533 node = table->table->top;
534 while (node && node->p.prefixlen < prefix->prefixlen &&
535 prefix_match (&node->p, prefix))
536 node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
537
538 if (node)
539 route_lock_node (node);
540 while (node && node->info == NULL)
541 node = route_next (node);
542 if (node == NULL)
543 return NULL;
544 route_unlock_node (node);
545
546 if (! prefix_match (prefix, &node->p))
547 return NULL;
548
549 route = node->info;
550 ospf6_route_lock (route);
551 return route;
552 }
553
554 struct ospf6_route *
555 ospf6_route_match_next (struct prefix *prefix,
556 struct ospf6_route *route)
557 {
558 struct ospf6_route *next;
559
560 next = ospf6_route_next (route);
561 if (next && ! prefix_match (prefix, &next->prefix))
562 {
563 ospf6_route_unlock (next);
564 next = NULL;
565 }
566
567 return next;
568 }
569
570 void
571 ospf6_route_remove_all (struct ospf6_route_table *table)
572 {
573 struct ospf6_route *route;
574 for (route = ospf6_route_head (table); route;
575 route = ospf6_route_next (route))
576 ospf6_route_remove (route, table);
577 }
578
579 struct ospf6_route_table *
580 ospf6_route_table_create ()
581 {
582 struct ospf6_route_table *new;
583 new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
584 new->table = route_table_init ();
585 return new;
586 }
587
588 void
589 ospf6_route_table_delete (struct ospf6_route_table *table)
590 {
591 ospf6_route_remove_all (table);
592 route_table_finish (table->table);
593 XFREE (MTYPE_OSPF6_ROUTE, table);
594 }
595
596
597 \f
598 /* VTY commands */
599 void
600 ospf6_route_show (struct vty *vty, struct ospf6_route *route)
601 {
602 int i;
603 char destination[64], nexthop[64];
604 char duration[16], ifname[IFNAMSIZ];
605 struct timeval now, res;
606
607 gettimeofday (&now, (struct timezone *) NULL);
608 timersub (&now, &route->changed, &res);
609 timerstring (&res, duration, sizeof (duration));
610
611 /* destination */
612 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
613 ospf6_linkstate_prefix2str (&route->prefix, destination,
614 sizeof (destination));
615 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
616 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
617 destination, sizeof (destination));
618 else
619 prefix2str (&route->prefix, destination, sizeof (destination));
620
621 /* nexthop */
622 inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
623 sizeof (nexthop));
624 if (! if_indextoname (route->nexthop[0].ifindex, ifname))
625 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
626
627 vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
628 (ospf6_route_is_best (route) ? '*' : ' '),
629 OSPF6_DEST_TYPE_SUBSTR (route->type),
630 OSPF6_PATH_TYPE_SUBSTR (route->path.type),
631 destination, nexthop, ifname, duration, VNL);
632
633 for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
634 i < OSPF6_MULTI_PATH_LIMIT; i++)
635 {
636 /* nexthop */
637 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
638 sizeof (nexthop));
639 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
640 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
641
642 vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
643 ' ', "", "", "", nexthop, ifname, "", VNL);
644 }
645 }
646
647 void
648 ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
649 {
650 char destination[64], nexthop[64], ifname[IFNAMSIZ];
651 char area_id[16], id[16], adv_router[16], capa[16], options[16];
652 struct timeval now, res;
653 char duration[16];
654 int i;
655
656 gettimeofday (&now, (struct timezone *) NULL);
657
658 /* destination */
659 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
660 ospf6_linkstate_prefix2str (&route->prefix, destination,
661 sizeof (destination));
662 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
663 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
664 destination, sizeof (destination));
665 else
666 prefix2str (&route->prefix, destination, sizeof (destination));
667 vty_out (vty, "Destination: %s%s", destination, VNL);
668
669 /* destination type */
670 vty_out (vty, "Destination type: %s%s",
671 OSPF6_DEST_TYPE_NAME (route->type),
672 VNL);
673
674 /* Time */
675 timersub (&now, &route->installed, &res);
676 timerstring (&res, duration, sizeof (duration));
677 vty_out (vty, "Installed Time: %s ago%s", duration, VNL);
678
679 timersub (&now, &route->changed, &res);
680 timerstring (&res, duration, sizeof (duration));
681 vty_out (vty, " Changed Time: %s ago%s", duration, VNL);
682
683 /* Debugging info */
684 vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
685 (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
686 (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
687 (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
688 (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
689 VNL);
690 vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
691 route->prev, route, route->next, VNL);
692
693 /* Path section */
694
695 /* Area-ID */
696 inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
697 vty_out (vty, "Associated Area: %s%s", area_id, VNL);
698
699 /* Path type */
700 vty_out (vty, "Path Type: %s%s",
701 OSPF6_PATH_TYPE_NAME (route->path.type), VNL);
702
703 /* LS Origin */
704 inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
705 inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
706 sizeof (adv_router));
707 vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
708 OSPF6_LSTYPE_NAME (route->path.origin.type),
709 id, adv_router, VNL);
710
711 /* Options */
712 ospf6_options_printbuf (route->path.options, options, sizeof (options));
713 vty_out (vty, "Options: %s%s", options, VNL);
714
715 /* Router Bits */
716 ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
717 vty_out (vty, "Router Bits: %s%s", capa, VNL);
718
719 /* Prefix Options */
720 vty_out (vty, "Prefix Options: xxx%s", VNL);
721
722 /* Metrics */
723 vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
724 VNL);
725 vty_out (vty, "Metric: %d (%d)%s",
726 route->path.cost, route->path.cost_e2, VNL);
727
728 /* Nexthops */
729 vty_out (vty, "Nexthop:%s", VNL);
730 for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
731 i < OSPF6_MULTI_PATH_LIMIT; i++)
732 {
733 /* nexthop */
734 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
735 sizeof (nexthop));
736 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
737 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
738 vty_out (vty, " %s %s%s", nexthop, ifname, VNL);
739 }
740 vty_out (vty, "%s", VNL);
741 }
742
743 void
744 ospf6_route_show_table_summary (struct vty *vty,
745 struct ospf6_route_table *table)
746 {
747 struct ospf6_route *route, *prev = NULL;
748 int i, pathtype[OSPF6_PATH_TYPE_MAX];
749 int number = 0;
750 int nhinval = 0, ecmp = 0;
751 int multipath = 0, destination = 0;
752 int desttype = 0, desttype_mismatch = 0;
753
754 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
755 pathtype[i] = 0;
756
757 for (route = ospf6_route_head (table); route;
758 route = ospf6_route_next (route))
759 {
760 if (desttype == 0)
761 desttype = route->type;
762 else if (desttype != route->type)
763 desttype_mismatch++;
764
765 if (prev == NULL || ! ospf6_route_is_same (prev, route))
766 destination++;
767 else
768 multipath++;
769
770 if (! ospf6_nexthop_is_set (&route->nexthop[0]))
771 nhinval++;
772 else if (ospf6_nexthop_is_set (&route->nexthop[1]))
773 ecmp++;
774
775 if (prev == NULL || ! ospf6_route_is_same (prev, route))
776 pathtype[route->path.type]++;
777
778 number++;
779 prev = route;
780 }
781
782 assert (number == table->count);
783 vty_out (vty, "Number of Destination: %d (%d routes)%s",
784 destination, number, VNL);
785 if (multipath)
786 vty_out (vty, " Number of Multi-path: %d%s", multipath, VNL);
787 if (desttype_mismatch)
788 vty_out (vty, " Number of Different Dest-type: %d%s",
789 desttype_mismatch, VNL);
790 if (ecmp)
791 vty_out (vty, " Number of Equal Cost Multi Path: %d%s",
792 ecmp, VNL);
793 if (ecmp)
794 vty_out (vty, " Number of Invalid Nexthop: %d%s",
795 nhinval, VNL);
796
797 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
798 {
799 if (pathtype[i])
800 vty_out (vty, " Number of %s routes: %d%s",
801 OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL);
802 }
803 }
804
805 int
806 ospf6_route_table_show (struct vty *vty, int argc, char **argv,
807 struct ospf6_route_table *table)
808 {
809 unsigned char flag = 0;
810 #define MATCH 0x01
811 #define DETAIL 0x02
812 #define PREFIX 0x04
813 #define SUMMARY 0x08
814 int i, ret;
815 struct prefix prefix, *p;
816 struct ospf6_route *route;
817
818 memset (&prefix, 0, sizeof (struct prefix));
819
820 for (i = 0; i < argc; i++)
821 {
822 /* set "detail" */
823 if (! strcmp (argv[i], "summary"))
824 {
825 SET_FLAG (flag, SUMMARY);
826 continue;
827 }
828
829 /* set "detail" */
830 if (! strcmp (argv[i], "detail"))
831 {
832 SET_FLAG (flag, DETAIL);
833 continue;
834 }
835
836 /* set "match" */
837 if (! strcmp (argv[i], "match"))
838 {
839 SET_FLAG (flag, MATCH);
840 continue;
841 }
842
843 if (prefix.family)
844 {
845 vty_out (vty, "Invalid argument: %s%s", argv[i], VNL);
846 return CMD_SUCCESS;
847 }
848
849 ret = str2prefix (argv[i], &prefix);
850 if (ret != 1 || prefix.family != AF_INET6)
851 {
852 vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
853 return CMD_SUCCESS;
854 }
855
856 if (strchr (argv[i], '/'))
857 SET_FLAG (flag, PREFIX);
858 }
859
860 /* Give summary of this route table */
861 if (CHECK_FLAG (flag, SUMMARY))
862 {
863 ospf6_route_show_table_summary (vty, table);
864 return CMD_SUCCESS;
865 }
866
867 /* Give exact prefix-match route */
868 if (prefix.family && ! CHECK_FLAG (flag, MATCH))
869 {
870 /* If exact address, give best matching route */
871 if (! CHECK_FLAG (flag, PREFIX))
872 route = ospf6_route_lookup_bestmatch (&prefix, table);
873 else
874 route = ospf6_route_lookup (&prefix, table);
875
876 if (route)
877 {
878 ospf6_route_lock (route);
879 p = &route->prefix;
880 }
881
882 while (route && ospf6_route_is_prefix (p, route))
883 {
884 /* Seaching an entry will always display details */
885 if (route)
886 ospf6_route_show_detail (vty, route);
887
888 route = ospf6_route_next (route);
889 }
890
891 return CMD_SUCCESS;
892 }
893
894 if (prefix.family == 0)
895 route = ospf6_route_head (table);
896 else
897 route = ospf6_route_match_head (&prefix, table);
898
899 while (route)
900 {
901 if (CHECK_FLAG (flag, DETAIL))
902 ospf6_route_show_detail (vty, route);
903 else
904 ospf6_route_show (vty, route);
905
906 if (prefix.family == 0)
907 route = ospf6_route_next (route);
908 else
909 route = ospf6_route_match_next (&prefix, route);
910 }
911
912 return CMD_SUCCESS;
913 }
914
915
916 int
917 ospf6_lsentry_table_show (struct vty *vty, int argc, char **argv,
918 struct ospf6_route_table *table)
919 {
920 unsigned char flag = 0;
921 #define MATCH 0x01
922 #define DETAIL 0x02
923 int i, ret;
924 struct prefix adv_router, id, prefix;
925 struct ospf6_route *route;
926
927 memset (&adv_router, 0, sizeof (struct prefix));
928 memset (&id, 0, sizeof (struct prefix));
929
930 for (i = 0; i < argc; i++)
931 {
932 /* set "detail" */
933 if (! strcmp (argv[i], "detail"))
934 {
935 SET_FLAG (flag, DETAIL);
936 continue;
937 }
938
939 /* set "match" */
940 if (! strcmp (argv[i], "match"))
941 {
942 SET_FLAG (flag, MATCH);
943 continue;
944 }
945
946 if (adv_router.family && id.family)
947 {
948 vty_out (vty, "Invalid argument: %s%s", argv[i], VNL);
949 return CMD_SUCCESS;
950 }
951
952 if (adv_router.family == 0)
953 {
954 ret = str2prefix (argv[i], &adv_router);
955 if (ret != 1)
956 {
957 if (! strcmp (argv[i], "*"))
958 {
959 adv_router.family = AF_INET;
960 adv_router.prefixlen = 0;
961 ret = 1;
962 }
963 }
964 if (ret != 1)
965 {
966 vty_out (vty, "Invalid Router-ID: %s%s", argv[i], VNL);
967 return CMD_SUCCESS;
968 }
969 }
970 else if (id.family == 0)
971 {
972 unsigned long val;
973 char *endptr;
974
975 ret = str2prefix (argv[i], &id);
976 if (ret != 1)
977 {
978 val = strtoul (argv[i], &endptr, 0);
979 if (val != ULONG_MAX && *endptr == '\0')
980 {
981 id.u.prefix4.s_addr = val;
982 ret = 1;
983 }
984 }
985
986 if (ret != 1)
987 {
988 vty_out (vty, "Invalid Link state ID: %s%s", argv[i],
989 VNL);
990 return CMD_WARNING;
991 }
992 }
993 }
994
995 /* Encode to linkstate prefix */
996 if (adv_router.family)
997 {
998 if (adv_router.prefixlen == 0 &&
999 id.family && id.prefixlen != IPV4_MAX_BITLEN)
1000 {
1001 vty_out (vty, "Specifying Link State ID by prefix is not allowed%s"
1002 "when specifying Router-ID as wildcard%s",
1003 VNL, VNL);
1004 return CMD_SUCCESS;
1005 }
1006 else if (adv_router.prefixlen != 0 &&
1007 adv_router.prefixlen != IPV4_MAX_BITLEN && id.family)
1008 {
1009 vty_out (vty, "Specifying Link State ID is not allowed%s"
1010 "when specifying Router-ID by prefix%s",
1011 VNL, VNL);
1012 return CMD_SUCCESS;
1013 }
1014
1015 if (adv_router.prefixlen == 0)
1016 ospf6_linkstate_prefix (0, id.u.prefix4.s_addr, &prefix);
1017 else if (adv_router.prefixlen != IPV4_MAX_BITLEN)
1018 {
1019 ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr, 0, &prefix);
1020 prefix.prefixlen = adv_router.prefixlen;
1021 SET_FLAG (flag, MATCH);
1022 }
1023 else
1024 {
1025 ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr,
1026 id.u.prefix4.s_addr, &prefix);
1027 prefix.prefixlen = adv_router.prefixlen + id.prefixlen;
1028 if (prefix.prefixlen != 64)
1029 SET_FLAG (flag, MATCH);
1030 }
1031 }
1032
1033 /* give exact match entry */
1034 if (adv_router.family && adv_router.prefixlen == IPV4_MAX_BITLEN &&
1035 id.family && id.prefixlen == IPV4_MAX_BITLEN)
1036 {
1037 route = ospf6_route_lookup (&prefix, table);
1038 if (route)
1039 ospf6_route_show_detail (vty, route);
1040 return CMD_SUCCESS;
1041 }
1042
1043 if (CHECK_FLAG (flag, MATCH))
1044 route = ospf6_route_match_head (&prefix, table);
1045 else
1046 route = ospf6_route_head (table);
1047
1048 while (route)
1049 {
1050 if (! adv_router.family ||
1051 (CHECK_FLAG (flag, MATCH) &&
1052 prefix_match (&prefix, &route->prefix)) ||
1053 (adv_router.prefixlen == 0 && id.family &&
1054 ospf6_linkstate_prefix_id (&prefix) ==
1055 ospf6_linkstate_prefix_id (&route->prefix)))
1056 {
1057 if (CHECK_FLAG (flag, DETAIL))
1058 ospf6_route_show_detail (vty, route);
1059 else
1060 ospf6_route_show (vty, route);
1061 }
1062
1063 if (CHECK_FLAG (flag, MATCH))
1064 route = ospf6_route_match_next (&prefix, route);
1065 else
1066 route = ospf6_route_next (route);
1067 }
1068
1069 return CMD_SUCCESS;
1070 }
1071
1072 DEFUN (debug_ospf6_route,
1073 debug_ospf6_route_cmd,
1074 "debug ospf6 route (table|intra-area|inter-area)",
1075 DEBUG_STR
1076 OSPF6_STR
1077 "Debug route table calculation\n"
1078 "Debug detail\n"
1079 "Debug intra-area route calculation\n"
1080 "Debug inter-area route calculation\n"
1081 )
1082 {
1083 unsigned char level = 0;
1084
1085 if (! strncmp (argv[0], "table", 5))
1086 level = OSPF6_DEBUG_ROUTE_TABLE;
1087 else if (! strncmp (argv[0], "intra", 5))
1088 level = OSPF6_DEBUG_ROUTE_INTRA;
1089 else if (! strncmp (argv[0], "inter", 5))
1090 level = OSPF6_DEBUG_ROUTE_INTER;
1091 OSPF6_DEBUG_ROUTE_ON (level);
1092 return CMD_SUCCESS;
1093 }
1094
1095 DEFUN (no_debug_ospf6_route,
1096 no_debug_ospf6_route_cmd,
1097 "no debug ospf6 route (table|intra-area|inter-area)",
1098 NO_STR
1099 DEBUG_STR
1100 OSPF6_STR
1101 "Debug route table calculation\n"
1102 "Debug intra-area route calculation\n")
1103 {
1104 unsigned char level = 0;
1105
1106 if (! strncmp (argv[0], "table", 5))
1107 level = OSPF6_DEBUG_ROUTE_TABLE;
1108 else if (! strncmp (argv[0], "intra", 5))
1109 level = OSPF6_DEBUG_ROUTE_INTRA;
1110 else if (! strncmp (argv[0], "inter", 5))
1111 level = OSPF6_DEBUG_ROUTE_INTER;
1112 OSPF6_DEBUG_ROUTE_OFF (level);
1113 return CMD_SUCCESS;
1114 }
1115
1116 int
1117 config_write_ospf6_debug_route (struct vty *vty)
1118 {
1119 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
1120 vty_out (vty, "debug ospf6 route table%s", VNL);
1121 if (IS_OSPF6_DEBUG_ROUTE (INTRA))
1122 vty_out (vty, "debug ospf6 route intra-area%s", VNL);
1123 if (IS_OSPF6_DEBUG_ROUTE (INTER))
1124 vty_out (vty, "debug ospf6 route inter-area%s", VNL);
1125 return 0;
1126 }
1127
1128 void
1129 install_element_ospf6_debug_route ()
1130 {
1131 install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
1132 install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
1133 install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
1134 install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
1135 }
1136
1137
1138