blob: 73bdac2d25c4a8cd32508ac384984b3a1237b8e8 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
hasso508e53e2004-05-18 18:57:06 +00002 * Copyright (C) 2003 Yasuhiro Ohara
paul718e3742002-12-13 20:15:29 +00003 *
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
hasso508e53e2004-05-18 18:57:06 +000022#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
paul718e3742002-12-13 20:15:29 +000031#include "ospf6d.h"
hasso508e53e2004-05-18 18:57:06 +000032#include "ospf6_proto.h"
33#include "ospf6_lsa.h"
34#include "ospf6_route.h"
paul718e3742002-12-13 20:15:29 +000035
hasso508e53e2004-05-18 18:57:06 +000036unsigned char conf_debug_ospf6_route = 0;
37
38void
39ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
40 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +000041{
hasso508e53e2004-05-18 18:57:06 +000042 memset (prefix, 0, sizeof (struct prefix));
43 prefix->family = AF_INET6;
44 prefix->prefixlen = 64;
45 memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
46 memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
paul718e3742002-12-13 20:15:29 +000047}
48
hasso508e53e2004-05-18 18:57:06 +000049void
50ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
paul718e3742002-12-13 20:15:29 +000051{
hasso508e53e2004-05-18 18:57:06 +000052 u_int32_t adv_router, id;
53 char adv_router_str[16];
54 memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
55 memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
56 inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
57 snprintf (buf, size, "%s(%lu)", adv_router_str, (u_long) ntohl (id));
paul718e3742002-12-13 20:15:29 +000058}
59
hasso508e53e2004-05-18 18:57:06 +000060/* Global strings for logging */
61char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
62{ "Unknown", "Router", "Network", "Discard", "Linkstate", };
63
64char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
65{ "?", "R", "N", "D", "L", };
66
67char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
68{ "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
69
70char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
71{ "??", "Ia", "Ie", "E1", "E2", };
72
73
74struct ospf6_route *
75ospf6_route_create ()
paul718e3742002-12-13 20:15:29 +000076{
hasso508e53e2004-05-18 18:57:06 +000077 struct ospf6_route *route;
78 route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
79 return route;
paul718e3742002-12-13 20:15:29 +000080}
81
hasso508e53e2004-05-18 18:57:06 +000082void
83ospf6_route_delete (struct ospf6_route *route)
paul718e3742002-12-13 20:15:29 +000084{
hasso508e53e2004-05-18 18:57:06 +000085 XFREE (MTYPE_OSPF6_ROUTE, route);
paul718e3742002-12-13 20:15:29 +000086}
87
hasso508e53e2004-05-18 18:57:06 +000088struct ospf6_route *
89ospf6_route_copy (struct ospf6_route *route)
90{
91 struct ospf6_route *new;
92
93 new = ospf6_route_create ();
94 memcpy (new, route, sizeof (struct ospf6_route));
95 new->rnode = NULL;
96 new->prev = NULL;
97 new->next = NULL;
98 new->lock = 0;
99 return new;
100}
101
102void
103ospf6_route_lock (struct ospf6_route *route)
104{
105 route->lock++;
106}
107
108void
109ospf6_route_unlock (struct ospf6_route *route)
110{
111 assert (route->lock > 0);
112 route->lock--;
113 if (route->lock == 0)
114 ospf6_route_delete (route);
115}
116
117/* Route compare function. If ra is more preferred, it returns
118 less than 0. If rb is more preferred returns greater than 0.
119 Otherwise (neither one is preferred), returns 0 */
120static int
121ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
122{
123 assert (ospf6_route_is_same (ra, rb));
124 assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
125 ra->path.type < OSPF6_PATH_TYPE_MAX);
126 assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
127 rb->path.type < OSPF6_PATH_TYPE_MAX);
128
129 if (ra->type != rb->type)
130 return (ra->type - rb->type);
131
132 if (ra->path.area_id != rb->path.area_id)
133 return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
134
135 if (ra->path.type != rb->path.type)
136 return (ra->path.type - rb->path.type);
137
138 if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
139 {
140 if (ra->path.cost_e2 != rb->path.cost_e2)
141 return (ra->path.cost_e2 - rb->path.cost_e2);
142 }
143 else
144 {
145 if (ra->path.cost != rb->path.cost)
146 return (ra->path.cost - rb->path.cost);
147 }
148
149 return 0;
150}
151
152struct ospf6_route *
153ospf6_route_lookup (struct prefix *prefix,
paul718e3742002-12-13 20:15:29 +0000154 struct ospf6_route_table *table)
155{
156 struct route_node *node;
hasso508e53e2004-05-18 18:57:06 +0000157 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000158
159 node = route_node_lookup (table->table, prefix);
hasso508e53e2004-05-18 18:57:06 +0000160 if (node == NULL)
161 return NULL;
paul718e3742002-12-13 20:15:29 +0000162
hasso508e53e2004-05-18 18:57:06 +0000163 route = (struct ospf6_route *) node->info;
164 return route;
paul718e3742002-12-13 20:15:29 +0000165}
166
hasso508e53e2004-05-18 18:57:06 +0000167struct ospf6_route *
168ospf6_route_lookup_identical (struct ospf6_route *route,
169 struct ospf6_route_table *table)
170{
171 struct ospf6_route *target;
172
173 for (target = ospf6_route_lookup (&route->prefix, table);
174 target; target = target->next)
175 {
176 if (ospf6_route_is_identical (target, route))
177 return target;
178 }
179 return NULL;
180}
181
182struct ospf6_route *
183ospf6_route_lookup_bestmatch (struct prefix *prefix,
184 struct ospf6_route_table *table)
paul718e3742002-12-13 20:15:29 +0000185{
186 struct route_node *node;
hasso508e53e2004-05-18 18:57:06 +0000187 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000188
hasso508e53e2004-05-18 18:57:06 +0000189 node = route_node_match (table->table, prefix);
190 if (node == NULL)
191 return NULL;
192 route_unlock_node (node);
paul718e3742002-12-13 20:15:29 +0000193
hasso508e53e2004-05-18 18:57:06 +0000194 route = (struct ospf6_route *) node->info;
195 return route;
paul718e3742002-12-13 20:15:29 +0000196}
197
hasso508e53e2004-05-18 18:57:06 +0000198#ifndef NDEBUG
199static void
200_route_count_assert (struct ospf6_route_table *table)
paul718e3742002-12-13 20:15:29 +0000201{
hasso508e53e2004-05-18 18:57:06 +0000202 struct ospf6_route *debug;
203 int num = 0;
204 for (debug = ospf6_route_head (table); debug;
205 debug = ospf6_route_next (debug))
206 num++;
207 assert (num == table->count);
paul718e3742002-12-13 20:15:29 +0000208}
hasso508e53e2004-05-18 18:57:06 +0000209#define ospf6_route_count_assert(t) (_route_count_assert (t))
210#else
211#define ospf6_route_count_assert(t) ((void) 0)
212#endif /*NDEBUG*/
paul718e3742002-12-13 20:15:29 +0000213
hasso508e53e2004-05-18 18:57:06 +0000214struct ospf6_route *
215ospf6_route_add (struct ospf6_route *route,
paul718e3742002-12-13 20:15:29 +0000216 struct ospf6_route_table *table)
217{
hasso508e53e2004-05-18 18:57:06 +0000218 struct route_node *node, *nextnode, *prevnode;
219 struct ospf6_route *current = NULL;
220 struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
221 char buf[64];
222 struct timeval now;
paul718e3742002-12-13 20:15:29 +0000223
hasso508e53e2004-05-18 18:57:06 +0000224 assert (route->rnode == NULL);
225 assert (route->lock == 0);
226 assert (route->next == NULL);
227 assert (route->prev == NULL);
paul718e3742002-12-13 20:15:29 +0000228
hasso508e53e2004-05-18 18:57:06 +0000229 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
230 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
231 else
232 prefix2str (&route->prefix, buf, sizeof (buf));
paul718e3742002-12-13 20:15:29 +0000233
hasso508e53e2004-05-18 18:57:06 +0000234 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
235 zlog_info ("route add %s", buf);
paul718e3742002-12-13 20:15:29 +0000236
hasso508e53e2004-05-18 18:57:06 +0000237 gettimeofday (&now, NULL);
238
239 node = route_node_get (table->table, &route->prefix);
240 route->rnode = node;
241
242 /* find place to insert */
243 for (current = node->info; current; current = current->next)
paul718e3742002-12-13 20:15:29 +0000244 {
hasso508e53e2004-05-18 18:57:06 +0000245 if (! ospf6_route_is_same (current, route))
246 next = current;
247 else if (current->type != route->type)
248 prev = current;
249 else if (ospf6_route_is_same_origin (current, route))
250 old = current;
251 else if (ospf6_route_cmp (current, route) > 0)
252 next = current;
253 else
254 prev = current;
255
256 if (old || next)
257 break;
paul718e3742002-12-13 20:15:29 +0000258 }
hasso508e53e2004-05-18 18:57:06 +0000259
260 if (old)
261 {
262 /* if route does not actually change, return unchanged */
263 if (ospf6_route_is_identical (old, route))
264 {
265 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
266 zlog_info (" identical route found, ignore");
267
268 ospf6_route_delete (route);
269 SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
270 ospf6_route_count_assert (table);
271 return old;
272 }
273
274 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
275 zlog_info (" old route found, replace");
276
277 /* replace old one if exists */
278 if (node->info == old)
279 {
280 node->info = route;
281 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
282 }
283
284 if (old->prev)
285 old->prev->next = route;
286 route->prev = old->prev;
287 if (old->next)
288 old->next->prev = route;
289 route->next = old->next;
290
291 route->installed = old->installed;
292 route->changed = now;
293
294 ospf6_route_unlock (old); /* will be deleted later */
295 ospf6_route_lock (route);
296
297 SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
298 if (table->hook_add)
299 (*table->hook_add) (route);
300
301 ospf6_route_count_assert (table);
302 return route;
303 }
304
305 /* insert if previous or next node found */
306 if (prev || next)
307 {
308 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
309 zlog_info (" another path found, insert");
310
311 if (prev == NULL)
312 prev = next->prev;
313 if (next == NULL)
314 next = prev->next;
315
316 if (prev)
317 prev->next = route;
318 route->prev = prev;
319 if (next)
320 next->prev = route;
321 route->next = next;
322
323 if (node->info == next)
324 {
325 assert (next->rnode == node);
326 node->info = route;
327 UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
328 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
329 }
330
331 route->installed = now;
332 route->changed = now;
333
334 ospf6_route_lock (route);
335 table->count++;
336
337 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
338 if (table->hook_add)
339 (*table->hook_add) (route);
340
341 ospf6_route_count_assert (table);
342 return route;
343 }
344
345 /* Else, this is the brand new route regarding to the prefix */
346 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
347 zlog_info (" brand new route, add");
348
349 assert (node->info == NULL);
350 node->info = route;
351 SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
352 ospf6_route_lock (route);
353 route->installed = now;
354 route->changed = now;
355
356 /* lookup real existing next route */
357 nextnode = node;
358 route_lock_node (nextnode);
359 do {
360 nextnode = route_next (nextnode);
361 } while (nextnode && nextnode->info == NULL);
362
363 /* set next link */
364 if (nextnode == NULL)
365 route->next = NULL;
paul718e3742002-12-13 20:15:29 +0000366 else
367 {
hasso508e53e2004-05-18 18:57:06 +0000368 route_unlock_node (nextnode);
369
370 next = nextnode->info;
371 route->next = next;
372 next->prev = route;
paul718e3742002-12-13 20:15:29 +0000373 }
374
hasso508e53e2004-05-18 18:57:06 +0000375 /* lookup real existing prev route */
376 prevnode = node;
377 route_lock_node (prevnode);
378 do {
379 prevnode = route_prev (prevnode);
380 } while (prevnode && prevnode->info == NULL);
paul718e3742002-12-13 20:15:29 +0000381
hasso508e53e2004-05-18 18:57:06 +0000382 /* set prev link */
383 if (prevnode == NULL)
384 route->prev = NULL;
paul718e3742002-12-13 20:15:29 +0000385 else
386 {
hasso508e53e2004-05-18 18:57:06 +0000387 route_unlock_node (prevnode);
388
389 prev = prevnode->info;
390 while (prev->next && ospf6_route_is_same (prev, prev->next))
391 prev = prev->next;
392 route->prev = prev;
393 prev->next = route;
paul718e3742002-12-13 20:15:29 +0000394 }
395
hasso508e53e2004-05-18 18:57:06 +0000396 table->count++;
paul718e3742002-12-13 20:15:29 +0000397
hasso508e53e2004-05-18 18:57:06 +0000398 SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
399 if (table->hook_add)
400 (*table->hook_add) (route);
paul718e3742002-12-13 20:15:29 +0000401
hasso508e53e2004-05-18 18:57:06 +0000402 ospf6_route_count_assert (table);
403 return route;
paul718e3742002-12-13 20:15:29 +0000404}
405
406void
hasso508e53e2004-05-18 18:57:06 +0000407ospf6_route_remove (struct ospf6_route *route,
paul718e3742002-12-13 20:15:29 +0000408 struct ospf6_route_table *table)
409{
hasso508e53e2004-05-18 18:57:06 +0000410 struct route_node *node;
411 struct ospf6_route *current;
412 char buf[64];
paul718e3742002-12-13 20:15:29 +0000413
hasso508e53e2004-05-18 18:57:06 +0000414 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
415 ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
416 else
417 prefix2str (&route->prefix, buf, sizeof (buf));
paul718e3742002-12-13 20:15:29 +0000418
hasso508e53e2004-05-18 18:57:06 +0000419 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
420 zlog_info ("route remove: %s", buf);
421
422 node = route_node_lookup (table->table, &route->prefix);
423 assert (node);
424
425 /* find the route to remove, making sure that the route pointer
426 is from the route table. */
427 current = node->info;
428 while (current && ospf6_route_is_same (current, route))
paul718e3742002-12-13 20:15:29 +0000429 {
hasso508e53e2004-05-18 18:57:06 +0000430 if (current == route)
431 break;
432 current = current->next;
433 }
434 assert (current == route);
435
436 /* adjust doubly linked list */
437 if (route->prev)
438 route->prev->next = route->next;
439 if (route->next)
440 route->next->prev = route->prev;
441
442 if (node->info == route)
443 {
444 if (route->next && ospf6_route_is_same (route->next, route))
paul718e3742002-12-13 20:15:29 +0000445 {
hasso508e53e2004-05-18 18:57:06 +0000446 node->info = route->next;
447 SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
paul718e3742002-12-13 20:15:29 +0000448 }
hasso508e53e2004-05-18 18:57:06 +0000449 else
450 node->info = NULL; /* should unlock route_node here ? */
paul718e3742002-12-13 20:15:29 +0000451 }
452
paul718e3742002-12-13 20:15:29 +0000453 if (table->hook_remove)
hasso508e53e2004-05-18 18:57:06 +0000454 (*table->hook_remove) (route);
paul718e3742002-12-13 20:15:29 +0000455
hasso508e53e2004-05-18 18:57:06 +0000456 ospf6_route_unlock (route);
457 table->count--;
paul718e3742002-12-13 20:15:29 +0000458
hasso508e53e2004-05-18 18:57:06 +0000459 ospf6_route_count_assert (table);
460}
paul718e3742002-12-13 20:15:29 +0000461
hasso508e53e2004-05-18 18:57:06 +0000462struct ospf6_route *
463ospf6_route_head (struct ospf6_route_table *table)
464{
465 struct route_node *node;
466 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000467
hasso508e53e2004-05-18 18:57:06 +0000468 node = route_top (table->table);
469 if (node == NULL)
470 return NULL;
471
472 /* skip to the real existing entry */
473 while (node && node->info == NULL)
474 node = route_next (node);
475 if (node == NULL)
476 return NULL;
477
478 route_unlock_node (node);
479 assert (node->info);
480
481 route = (struct ospf6_route *) node->info;
482 assert (route->prev == NULL);
483 ospf6_route_lock (route);
484 return route;
485}
486
487struct ospf6_route *
488ospf6_route_next (struct ospf6_route *route)
489{
490 struct ospf6_route *next = route->next;
491
492 ospf6_route_unlock (route);
493 if (next)
494 ospf6_route_lock (next);
495
496 return next;
497}
498
499struct ospf6_route *
500ospf6_route_best_next (struct ospf6_route *route)
501{
502 struct route_node *rnode;
503 struct ospf6_route *next;
504
505 rnode = route->rnode;
506 route_lock_node (rnode);
507 rnode = route_next (rnode);
508 while (rnode && rnode->info == NULL)
509 rnode = route_next (rnode);
510 if (rnode == NULL)
511 return NULL;
512 route_unlock_node (rnode);
513
514 assert (rnode->info);
515 next = (struct ospf6_route *) rnode->info;
516 ospf6_route_unlock (route);
517 ospf6_route_lock (next);
518 return next;
519}
520
521/* Macro version of check_bit (). */
522#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
523
524struct ospf6_route *
525ospf6_route_match_head (struct prefix *prefix,
526 struct ospf6_route_table *table)
527{
528 struct route_node *node;
529 struct ospf6_route *route;
530
531 /* Walk down tree. */
532 node = table->table->top;
533 while (node && node->p.prefixlen < prefix->prefixlen &&
534 prefix_match (&node->p, prefix))
535 node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
536
537 if (node)
538 route_lock_node (node);
539 while (node && node->info == NULL)
540 node = route_next (node);
541 if (node == NULL)
542 return NULL;
543 route_unlock_node (node);
544
545 if (! prefix_match (prefix, &node->p))
546 return NULL;
547
548 route = node->info;
549 ospf6_route_lock (route);
550 return route;
551}
552
553struct ospf6_route *
554ospf6_route_match_next (struct prefix *prefix,
555 struct ospf6_route *route)
556{
557 struct ospf6_route *next;
558
559 next = ospf6_route_next (route);
560 if (next && ! prefix_match (prefix, &next->prefix))
561 {
562 ospf6_route_unlock (next);
563 next = NULL;
564 }
565
566 return next;
paul718e3742002-12-13 20:15:29 +0000567}
568
569void
570ospf6_route_remove_all (struct ospf6_route_table *table)
571{
hasso508e53e2004-05-18 18:57:06 +0000572 struct ospf6_route *route;
573 for (route = ospf6_route_head (table); route;
574 route = ospf6_route_next (route))
575 ospf6_route_remove (route, table);
paul718e3742002-12-13 20:15:29 +0000576}
577
paul718e3742002-12-13 20:15:29 +0000578struct ospf6_route_table *
hasso508e53e2004-05-18 18:57:06 +0000579ospf6_route_table_create ()
paul718e3742002-12-13 20:15:29 +0000580{
paul718e3742002-12-13 20:15:29 +0000581 struct ospf6_route_table *new;
paul718e3742002-12-13 20:15:29 +0000582 new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
paul718e3742002-12-13 20:15:29 +0000583 new->table = route_table_init ();
paul718e3742002-12-13 20:15:29 +0000584 return new;
585}
586
587void
588ospf6_route_table_delete (struct ospf6_route_table *table)
589{
paul718e3742002-12-13 20:15:29 +0000590 ospf6_route_remove_all (table);
591 route_table_finish (table->table);
paul718e3742002-12-13 20:15:29 +0000592 XFREE (MTYPE_OSPF6_ROUTE, table);
593}
594
paul718e3742002-12-13 20:15:29 +0000595
596
597/* VTY commands */
hasso508e53e2004-05-18 18:57:06 +0000598void
599ospf6_route_show (struct vty *vty, struct ospf6_route *route)
600{
601 int i;
602 char destination[64], nexthop[64];
603 char duration[16], ifname[IFNAMSIZ];
604 struct timeval now, res;
605
606 gettimeofday (&now, (struct timezone *) NULL);
607 timersub (&now, &route->changed, &res);
608 timerstring (&res, duration, sizeof (duration));
609
610 /* destination */
611 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
612 ospf6_linkstate_prefix2str (&route->prefix, destination,
613 sizeof (destination));
614 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
615 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
616 destination, sizeof (destination));
617 else
618 prefix2str (&route->prefix, destination, sizeof (destination));
619
620 /* nexthop */
621 inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
622 sizeof (nexthop));
623 if (! if_indextoname (route->nexthop[0].ifindex, ifname))
624 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
625
626 vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
627 (ospf6_route_is_best (route) ? '*' : ' '),
628 OSPF6_DEST_TYPE_SUBSTR (route->type),
629 OSPF6_PATH_TYPE_SUBSTR (route->path.type),
630 destination, nexthop, ifname, duration, VTY_NEWLINE);
631
632 for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
633 i < OSPF6_MULTI_PATH_LIMIT; i++)
634 {
635 /* nexthop */
636 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
637 sizeof (nexthop));
638 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
639 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
640
641 vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
642 ' ', "", "", "", nexthop, ifname, "", VTY_NEWLINE);
643 }
644}
paul718e3742002-12-13 20:15:29 +0000645
646void
hasso508e53e2004-05-18 18:57:06 +0000647ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
paul718e3742002-12-13 20:15:29 +0000648{
hasso508e53e2004-05-18 18:57:06 +0000649 char destination[64], nexthop[64], ifname[IFNAMSIZ];
650 char area_id[16], id[16], adv_router[16], capa[16], options[16];
paul718e3742002-12-13 20:15:29 +0000651 struct timeval now, res;
652 char duration[16];
hasso508e53e2004-05-18 18:57:06 +0000653 int i;
paul718e3742002-12-13 20:15:29 +0000654
655 gettimeofday (&now, (struct timezone *) NULL);
656
657 /* destination */
hasso508e53e2004-05-18 18:57:06 +0000658 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
659 ospf6_linkstate_prefix2str (&route->prefix, destination,
660 sizeof (destination));
661 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
662 inet_ntop (route->prefix.family, &route->prefix.u.prefix,
663 destination, sizeof (destination));
paul718e3742002-12-13 20:15:29 +0000664 else
hasso508e53e2004-05-18 18:57:06 +0000665 prefix2str (&route->prefix, destination, sizeof (destination));
666 vty_out (vty, "Destination: %s%s", destination, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000667
hasso508e53e2004-05-18 18:57:06 +0000668 /* destination type */
669 vty_out (vty, "Destination type: %s%s",
670 OSPF6_DEST_TYPE_NAME (route->type),
671 VTY_NEWLINE);
672
673 /* Time */
674 timersub (&now, &route->installed, &res);
675 timerstring (&res, duration, sizeof (duration));
676 vty_out (vty, "Installed Time: %s ago%s", duration, VTY_NEWLINE);
677
678 timersub (&now, &route->changed, &res);
679 timerstring (&res, duration, sizeof (duration));
680 vty_out (vty, " Changed Time: %s ago%s", duration, VTY_NEWLINE);
681
682 /* Debugging info */
683 vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
684 (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
685 (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
686 (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
687 (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
688 VTY_NEWLINE);
689 vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
690 route->prev, route, route->next, VTY_NEWLINE);
691
692 /* Path section */
693
694 /* Area-ID */
695 inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
696 vty_out (vty, "Associated Area: %s%s", area_id, VTY_NEWLINE);
697
698 /* Path type */
699 vty_out (vty, "Path Type: %s%s",
700 OSPF6_PATH_TYPE_NAME (route->path.type), VTY_NEWLINE);
701
702 /* LS Origin */
703 inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
704 inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
705 sizeof (adv_router));
706 vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
707 OSPF6_LSTYPE_NAME (route->path.origin.type),
708 id, adv_router, VTY_NEWLINE);
709
710 /* Options */
711 ospf6_options_printbuf (route->path.options, options, sizeof (options));
712 vty_out (vty, "Options: %s%s", options, VTY_NEWLINE);
713
714 /* Router Bits */
715 ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
716 vty_out (vty, "Router Bits: %s%s", capa, VTY_NEWLINE);
717
718 /* Prefix Options */
719 vty_out (vty, "Prefix Options: xxx%s", VTY_NEWLINE);
720
721 /* Metrics */
722 vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
723 VTY_NEWLINE);
724 vty_out (vty, "Metric: %d (%d)%s",
725 route->path.cost, route->path.cost_e2, VTY_NEWLINE);
726
727 /* Nexthops */
728 vty_out (vty, "Nexthop:%s", VTY_NEWLINE);
729 for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
730 i < OSPF6_MULTI_PATH_LIMIT; i++)
paul718e3742002-12-13 20:15:29 +0000731 {
hasso508e53e2004-05-18 18:57:06 +0000732 /* nexthop */
733 inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
734 sizeof (nexthop));
735 if (! if_indextoname (route->nexthop[i].ifindex, ifname))
736 snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
737 vty_out (vty, " %s %s%s", nexthop, ifname, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000738 }
hasso508e53e2004-05-18 18:57:06 +0000739 vty_out (vty, "%s", VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000740}
741
742void
hasso508e53e2004-05-18 18:57:06 +0000743ospf6_route_show_table_summary (struct vty *vty,
744 struct ospf6_route_table *table)
paul718e3742002-12-13 20:15:29 +0000745{
hasso508e53e2004-05-18 18:57:06 +0000746 struct ospf6_route *route, *prev = NULL;
747 int i, pathtype[OSPF6_PATH_TYPE_MAX];
748 int number = 0;
749 int nhinval = 0, ecmp = 0;
750 int multipath = 0, destination = 0;
751 int desttype = 0, desttype_mismatch = 0;
paul718e3742002-12-13 20:15:29 +0000752
hasso508e53e2004-05-18 18:57:06 +0000753 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
754 pathtype[i] = 0;
paul718e3742002-12-13 20:15:29 +0000755
hasso508e53e2004-05-18 18:57:06 +0000756 for (route = ospf6_route_head (table); route;
757 route = ospf6_route_next (route))
paul718e3742002-12-13 20:15:29 +0000758 {
hasso508e53e2004-05-18 18:57:06 +0000759 if (desttype == 0)
760 desttype = route->type;
761 else if (desttype != route->type)
762 desttype_mismatch++;
paul718e3742002-12-13 20:15:29 +0000763
hasso508e53e2004-05-18 18:57:06 +0000764 if (prev == NULL || ! ospf6_route_is_same (prev, route))
765 destination++;
766 else
767 multipath++;
paul718e3742002-12-13 20:15:29 +0000768
hasso508e53e2004-05-18 18:57:06 +0000769 if (! ospf6_nexthop_is_set (&route->nexthop[0]))
770 nhinval++;
771 else if (ospf6_nexthop_is_set (&route->nexthop[1]))
772 ecmp++;
paul718e3742002-12-13 20:15:29 +0000773
hasso508e53e2004-05-18 18:57:06 +0000774 if (prev == NULL || ! ospf6_route_is_same (prev, route))
775 pathtype[route->path.type]++;
paul718e3742002-12-13 20:15:29 +0000776
hasso508e53e2004-05-18 18:57:06 +0000777 number++;
778 prev = route;
paul718e3742002-12-13 20:15:29 +0000779 }
hasso508e53e2004-05-18 18:57:06 +0000780
781 assert (number == table->count);
782 vty_out (vty, "Number of Destination: %d (%d routes)%s",
783 destination, number, VTY_NEWLINE);
784 if (multipath)
785 vty_out (vty, " Number of Multi-path: %d%s", multipath, VTY_NEWLINE);
786 if (desttype_mismatch)
787 vty_out (vty, " Number of Different Dest-type: %d%s",
788 desttype_mismatch, VTY_NEWLINE);
789 if (ecmp)
790 vty_out (vty, " Number of Equal Cost Multi Path: %d%s",
791 ecmp, VTY_NEWLINE);
792 if (ecmp)
793 vty_out (vty, " Number of Invalid Nexthop: %d%s",
794 nhinval, VTY_NEWLINE);
795
796 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
797 {
798 if (pathtype[i])
799 vty_out (vty, " Number of %s routes: %d%s",
800 OSPF6_PATH_TYPE_NAME (i), pathtype[i], VTY_NEWLINE);
801 }
paul718e3742002-12-13 20:15:29 +0000802}
803
804int
805ospf6_route_table_show (struct vty *vty, int argc, char **argv,
806 struct ospf6_route_table *table)
807{
hasso508e53e2004-05-18 18:57:06 +0000808 unsigned char flag = 0;
809#define MATCH 0x01
810#define DETAIL 0x02
811#define PREFIX 0x04
812#define SUMMARY 0x08
paul718e3742002-12-13 20:15:29 +0000813 int i, ret;
hasso508e53e2004-05-18 18:57:06 +0000814 struct prefix prefix, *p;
815 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000816
817 memset (&prefix, 0, sizeof (struct prefix));
818
819 for (i = 0; i < argc; i++)
820 {
hasso508e53e2004-05-18 18:57:06 +0000821 /* set "detail" */
822 if (! strcmp (argv[i], "summary"))
823 {
824 SET_FLAG (flag, SUMMARY);
825 continue;
826 }
827
828 /* set "detail" */
paul718e3742002-12-13 20:15:29 +0000829 if (! strcmp (argv[i], "detail"))
830 {
hasso508e53e2004-05-18 18:57:06 +0000831 SET_FLAG (flag, DETAIL);
832 continue;
paul718e3742002-12-13 20:15:29 +0000833 }
834
hasso508e53e2004-05-18 18:57:06 +0000835 /* set "match" */
836 if (! strcmp (argv[i], "match"))
paul718e3742002-12-13 20:15:29 +0000837 {
hasso508e53e2004-05-18 18:57:06 +0000838 SET_FLAG (flag, MATCH);
839 continue;
paul718e3742002-12-13 20:15:29 +0000840 }
841
hasso508e53e2004-05-18 18:57:06 +0000842 if (prefix.family)
paul718e3742002-12-13 20:15:29 +0000843 {
hasso508e53e2004-05-18 18:57:06 +0000844 vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
845 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +0000846 }
hasso508e53e2004-05-18 18:57:06 +0000847
848 ret = str2prefix (argv[i], &prefix);
849 if (ret != 1 || prefix.family != AF_INET6)
850 {
851 vty_out (vty, "Malformed argument: %s%s", argv[i], VTY_NEWLINE);
852 return CMD_SUCCESS;
853 }
854
855 if (strchr (argv[i], '/'))
856 SET_FLAG (flag, PREFIX);
paul718e3742002-12-13 20:15:29 +0000857 }
858
hasso508e53e2004-05-18 18:57:06 +0000859 /* Give summary of this route table */
860 if (CHECK_FLAG (flag, SUMMARY))
paul718e3742002-12-13 20:15:29 +0000861 {
hasso508e53e2004-05-18 18:57:06 +0000862 ospf6_route_show_table_summary (vty, table);
paul718e3742002-12-13 20:15:29 +0000863 return CMD_SUCCESS;
864 }
865
hasso508e53e2004-05-18 18:57:06 +0000866 /* Give exact prefix-match route */
867 if (prefix.family && ! CHECK_FLAG (flag, MATCH))
paul718e3742002-12-13 20:15:29 +0000868 {
hasso508e53e2004-05-18 18:57:06 +0000869 /* If exact address, give best matching route */
870 if (! CHECK_FLAG (flag, PREFIX))
871 route = ospf6_route_lookup_bestmatch (&prefix, table);
872 else
873 route = ospf6_route_lookup (&prefix, table);
874
875 if (route)
876 {
877 ospf6_route_lock (route);
878 p = &route->prefix;
879 }
880
881 while (route && ospf6_route_is_prefix (p, route))
882 {
883 /* Seaching an entry will always display details */
884 if (route)
885 ospf6_route_show_detail (vty, route);
886
887 route = ospf6_route_next (route);
888 }
889
890 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +0000891 }
892
hasso508e53e2004-05-18 18:57:06 +0000893 if (prefix.family == 0)
894 route = ospf6_route_head (table);
895 else
896 route = ospf6_route_match_head (&prefix, table);
897
898 while (route)
paul718e3742002-12-13 20:15:29 +0000899 {
hasso508e53e2004-05-18 18:57:06 +0000900 if (CHECK_FLAG (flag, DETAIL))
paul718e3742002-12-13 20:15:29 +0000901 ospf6_route_show_detail (vty, route);
902 else
903 ospf6_route_show (vty, route);
904
hasso508e53e2004-05-18 18:57:06 +0000905 if (prefix.family == 0)
906 route = ospf6_route_next (route);
907 else
908 route = ospf6_route_match_next (&prefix, route);
paul718e3742002-12-13 20:15:29 +0000909 }
910
paul718e3742002-12-13 20:15:29 +0000911 return CMD_SUCCESS;
912}
913
hasso508e53e2004-05-18 18:57:06 +0000914
915int
916ospf6_lsentry_table_show (struct vty *vty, int argc, char **argv,
917 struct ospf6_route_table *table)
918{
919 unsigned char flag = 0;
920#define MATCH 0x01
921#define DETAIL 0x02
922 int i, ret;
923 struct prefix adv_router, id, prefix;
924 struct ospf6_route *route;
925
926 memset (&adv_router, 0, sizeof (struct prefix));
927 memset (&id, 0, sizeof (struct prefix));
928
929 for (i = 0; i < argc; i++)
930 {
931 /* set "detail" */
932 if (! strcmp (argv[i], "detail"))
933 {
934 SET_FLAG (flag, DETAIL);
935 continue;
936 }
937
938 /* set "match" */
939 if (! strcmp (argv[i], "match"))
940 {
941 SET_FLAG (flag, MATCH);
942 continue;
943 }
944
945 if (adv_router.family && id.family)
946 {
947 vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
948 return CMD_SUCCESS;
949 }
950
951 if (adv_router.family == 0)
952 {
953 ret = str2prefix (argv[i], &adv_router);
954 if (ret != 1)
955 {
956 if (! strcmp (argv[i], "*"))
957 {
958 adv_router.family = AF_INET;
959 adv_router.prefixlen = 0;
960 ret = 1;
961 }
962 }
963 if (ret != 1)
964 {
965 vty_out (vty, "Invalid Router-ID: %s%s", argv[i], VTY_NEWLINE);
966 return CMD_SUCCESS;
967 }
968 }
969 else if (id.family == 0)
970 {
971 unsigned long val;
972 char *endptr;
973
974 ret = str2prefix (argv[i], &id);
975 if (ret != 1)
976 {
977 val = strtoul (argv[i], &endptr, 0);
978 if (val != ULONG_MAX && *endptr == '\0')
979 {
980 id.u.prefix4.s_addr = val;
981 ret = 1;
982 }
983 }
984
985 if (ret != 1)
986 {
987 vty_out (vty, "Invalid Link state ID: %s%s", argv[i],
988 VTY_NEWLINE);
989 return CMD_WARNING;
990 }
991 }
992 }
993
994 /* Encode to linkstate prefix */
995 if (adv_router.family)
996 {
997 if (adv_router.prefixlen == 0 &&
998 id.family && id.prefixlen != IPV4_MAX_BITLEN)
999 {
1000 vty_out (vty, "Specifying Link State ID by prefix is not allowed%s"
1001 "when specifying Router-ID as wildcard%s",
1002 VTY_NEWLINE, VTY_NEWLINE);
1003 return CMD_SUCCESS;
1004 }
1005 else if (adv_router.prefixlen != 0 &&
1006 adv_router.prefixlen != IPV4_MAX_BITLEN && id.family)
1007 {
1008 vty_out (vty, "Specifying Link State ID is not allowed%s"
1009 "when specifying Router-ID by prefix%s",
1010 VTY_NEWLINE, VTY_NEWLINE);
1011 return CMD_SUCCESS;
1012 }
1013
1014 if (adv_router.prefixlen == 0)
1015 ospf6_linkstate_prefix (0, id.u.prefix4.s_addr, &prefix);
1016 else if (adv_router.prefixlen != IPV4_MAX_BITLEN)
1017 {
1018 ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr, 0, &prefix);
1019 prefix.prefixlen = adv_router.prefixlen;
1020 SET_FLAG (flag, MATCH);
1021 }
1022 else
1023 {
1024 ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr,
1025 id.u.prefix4.s_addr, &prefix);
1026 prefix.prefixlen = adv_router.prefixlen + id.prefixlen;
1027 if (prefix.prefixlen != 64)
1028 SET_FLAG (flag, MATCH);
1029 }
1030 }
1031
1032 /* give exact match entry */
1033 if (adv_router.family && adv_router.prefixlen == IPV4_MAX_BITLEN &&
1034 id.family && id.prefixlen == IPV4_MAX_BITLEN)
1035 {
1036 route = ospf6_route_lookup (&prefix, table);
1037 if (route)
1038 ospf6_route_show_detail (vty, route);
1039 return CMD_SUCCESS;
1040 }
1041
1042 if (CHECK_FLAG (flag, MATCH))
1043 route = ospf6_route_match_head (&prefix, table);
1044 else
1045 route = ospf6_route_head (table);
1046
1047 while (route)
1048 {
1049 if (! adv_router.family ||
1050 (CHECK_FLAG (flag, MATCH) &&
1051 prefix_match (&prefix, &route->prefix)) ||
1052 (adv_router.prefixlen == 0 && id.family &&
1053 ospf6_linkstate_prefix_id (&prefix) ==
1054 ospf6_linkstate_prefix_id (&route->prefix)))
1055 {
1056 if (CHECK_FLAG (flag, DETAIL))
1057 ospf6_route_show_detail (vty, route);
1058 else
1059 ospf6_route_show (vty, route);
1060 }
1061
1062 if (CHECK_FLAG (flag, MATCH))
1063 route = ospf6_route_match_next (&prefix, route);
1064 else
1065 route = ospf6_route_next (route);
1066 }
1067
1068 return CMD_SUCCESS;
1069}
1070
1071DEFUN (debug_ospf6_route,
1072 debug_ospf6_route_cmd,
1073 "debug ospf6 route (table|intra-area|inter-area)",
1074 DEBUG_STR
1075 OSPF6_STR
1076 "Debug route table calculation\n"
1077 "Debug detail\n"
1078 "Debug intra-area route calculation\n"
1079 "Debug inter-area route calculation\n"
1080 )
1081{
1082 unsigned char level = 0;
1083
1084 if (! strncmp (argv[0], "table", 5))
1085 level = OSPF6_DEBUG_ROUTE_TABLE;
1086 else if (! strncmp (argv[0], "intra", 5))
1087 level = OSPF6_DEBUG_ROUTE_INTRA;
1088 else if (! strncmp (argv[0], "inter", 5))
1089 level = OSPF6_DEBUG_ROUTE_INTER;
1090 OSPF6_DEBUG_ROUTE_ON (level);
1091 return CMD_SUCCESS;
1092}
1093
1094DEFUN (no_debug_ospf6_route,
1095 no_debug_ospf6_route_cmd,
1096 "no debug ospf6 route (table|intra-area|inter-area)",
1097 NO_STR
1098 DEBUG_STR
1099 OSPF6_STR
1100 "Debug route table calculation\n"
1101 "Debug intra-area route calculation\n")
1102{
1103 unsigned char level = 0;
1104
1105 if (! strncmp (argv[0], "table", 5))
1106 level = OSPF6_DEBUG_ROUTE_TABLE;
1107 else if (! strncmp (argv[0], "intra", 5))
1108 level = OSPF6_DEBUG_ROUTE_INTRA;
1109 else if (! strncmp (argv[0], "inter", 5))
1110 level = OSPF6_DEBUG_ROUTE_INTER;
1111 OSPF6_DEBUG_ROUTE_OFF (level);
1112 return CMD_SUCCESS;
1113}
1114
1115int
1116config_write_ospf6_debug_route (struct vty *vty)
1117{
1118 if (IS_OSPF6_DEBUG_ROUTE (TABLE))
1119 vty_out (vty, "debug ospf6 route table%s", VTY_NEWLINE);
1120 if (IS_OSPF6_DEBUG_ROUTE (INTRA))
1121 vty_out (vty, "debug ospf6 route intra-area%s", VTY_NEWLINE);
1122 if (IS_OSPF6_DEBUG_ROUTE (INTER))
1123 vty_out (vty, "debug ospf6 route inter-area%s", VTY_NEWLINE);
1124 return 0;
1125}
1126
1127void
1128install_element_ospf6_debug_route ()
1129{
1130 install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
1131 install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
1132 install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
1133 install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
1134}
1135
1136
1137