Annotation of embedaddon/quagga/ospf6d/ospf6_route.c, revision 1.1.1.2
1.1 misho 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: #include "linklist.h"
31:
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"
40:
41: unsigned char conf_debug_ospf6_route = 0;
42:
43: static char *
44: ospf6_route_table_name (struct ospf6_route_table *table)
45: {
46: static char name[32];
47: switch (table->scope_type)
48: {
49: case OSPF6_SCOPE_TYPE_GLOBAL:
50: {
51: switch (table->table_type)
52: {
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;
65: }
66: }
67: break;
68:
69: case OSPF6_SCOPE_TYPE_AREA:
70: {
71: struct ospf6_area *oa = (struct ospf6_area *) table->scope;
72: switch (table->table_type)
73: {
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;
98: }
99: }
100: break;
101:
102: case OSPF6_SCOPE_TYPE_INTERFACE:
103: {
104: struct ospf6_interface *oi = (struct ospf6_interface *) table->scope;
105: switch (table->table_type)
106: {
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;
115: }
116: }
117: break;
118:
119: default:
120: {
121: switch (table->table_type)
122: {
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;
129: }
130: }
131: break;
132: }
133: return name;
134: }
135:
136: void
137: ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
138: struct prefix *prefix)
139: {
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);
145: }
146:
147: void
148: ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
149: {
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);
160: }
161:
162: /* Global strings for logging */
163: const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
164: { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", };
165:
166: const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
167: { "?", "R", "N", "D", "L", "A", };
168:
169: const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
170: { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
171:
172: const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
173: { "??", "IA", "IE", "E1", "E2", };
174:
175:
176: struct ospf6_route *
177: ospf6_route_create (void)
178: {
179: struct ospf6_route *route;
180: route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
181: return route;
182: }
183:
184: void
185: ospf6_route_delete (struct ospf6_route *route)
186: {
187: XFREE (MTYPE_OSPF6_ROUTE, route);
188: }
189:
190: struct ospf6_route *
191: ospf6_route_copy (struct ospf6_route *route)
192: {
193: struct ospf6_route *new;
194:
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;
203: }
204:
205: void
206: ospf6_route_lock (struct ospf6_route *route)
207: {
208: route->lock++;
209: }
210:
211: void
212: ospf6_route_unlock (struct ospf6_route *route)
213: {
214: assert (route->lock > 0);
215: route->lock--;
216: if (route->lock == 0)
217: {
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);
223: }
224: }
225:
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)
231: {
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);
237:
238: if (ra->type != rb->type)
239: return (ra->type - rb->type);
240:
241: if (ra->path.area_id != rb->path.area_id)
242: return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
243:
244: if (ra->path.type != rb->path.type)
245: return (ra->path.type - rb->path.type);
246:
247: if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
248: {
249: if (ra->path.cost_e2 != rb->path.cost_e2)
250: return (ra->path.cost_e2 - rb->path.cost_e2);
251: }
252: else
253: {
254: if (ra->path.cost != rb->path.cost)
255: return (ra->path.cost - rb->path.cost);
256: }
257:
258: return 0;
259: }
260:
261: struct ospf6_route *
262: ospf6_route_lookup (struct prefix *prefix,
263: struct ospf6_route_table *table)
264: {
265: struct route_node *node;
266: struct ospf6_route *route;
267:
268: node = route_node_lookup (table->table, prefix);
269: if (node == NULL)
270: return NULL;
271:
272: route = (struct ospf6_route *) node->info;
273: return route;
274: }
275:
276: struct ospf6_route *
277: ospf6_route_lookup_identical (struct ospf6_route *route,
278: struct ospf6_route_table *table)
279: {
280: struct ospf6_route *target;
281:
282: for (target = ospf6_route_lookup (&route->prefix, table);
283: target; target = target->next)
284: {
285: if (ospf6_route_is_identical (target, route))
286: return target;
287: }
288: return NULL;
289: }
290:
291: struct ospf6_route *
292: ospf6_route_lookup_bestmatch (struct prefix *prefix,
293: struct ospf6_route_table *table)
294: {
295: struct route_node *node;
296: struct ospf6_route *route;
297:
298: node = route_node_match (table->table, prefix);
299: if (node == NULL)
300: return NULL;
301: route_unlock_node (node);
302:
303: route = (struct ospf6_route *) node->info;
304: return route;
305: }
306:
1.1.1.2 ! misho 307: #ifdef DEBUG
1.1 misho 308: static void
309: route_table_assert (struct ospf6_route_table *table)
310: {
311: struct ospf6_route *prev, *r, *next;
312: char buf[64];
313: unsigned int link_error = 0, num = 0;
314:
315: r = ospf6_route_head (table);
316: prev = NULL;
317: while (r)
318: {
319: if (r->prev != prev)
320: link_error++;
321:
322: next = ospf6_route_next (r);
323:
324: if (r->next != next)
325: link_error++;
326:
327: prev = r;
328: r = next;
329: }
330:
331: for (r = ospf6_route_head (table); r; r = ospf6_route_next (r))
332: num++;
333:
334: if (link_error == 0 && num == table->count)
335: return;
336:
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))
342: {
343: prefix2str (&r->prefix, buf, sizeof (buf));
344: zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf);
345: }
346: zlog_debug ("DUMP END");
347:
348: assert (link_error == 0 && num == table->count);
349: }
350: #define ospf6_route_table_assert(t) (route_table_assert (t))
351: #else
352: #define ospf6_route_table_assert(t) ((void) 0)
1.1.1.2 ! misho 353: #endif /*DEBUG*/
1.1 misho 354:
355: struct ospf6_route *
356: ospf6_route_add (struct ospf6_route *route,
357: struct ospf6_route_table *table)
358: {
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;
364:
365: assert (route->rnode == NULL);
366: assert (route->lock == 0);
367: assert (route->next == NULL);
368: assert (route->prev == NULL);
369:
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));
374:
375: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
376: zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table),
1.1.1.2 ! misho 377: (void *)table, (void *)route, buf);
1.1 misho 378: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
379: zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
380:
381: quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
382:
383: node = route_node_get (table->table, &route->prefix);
384: route->rnode = node;
385:
386: /* find place to insert */
387: for (current = node->info; current; current = current->next)
388: {
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;
399:
400: if (old || next)
401: break;
402: }
403:
404: if (old)
405: {
406: /* if route does not actually change, return unchanged */
407: if (ospf6_route_is_identical (old, route))
408: {
409: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
410: zlog_debug ("%s %p: route add %p: needless update of %p",
1.1.1.2 ! misho 411: ospf6_route_table_name (table),
! 412: (void *)table, (void *)route, (void *)old);
1.1 misho 413: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
414: zlog_debug ("%s: route add: needless update",
415: ospf6_route_table_name (table));
416:
417: ospf6_route_delete (route);
418: SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
419: ospf6_route_table_assert (table);
420:
421: return old;
422: }
423:
424: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
425: zlog_debug ("%s %p: route add %p: update of %p",
1.1.1.2 ! misho 426: ospf6_route_table_name (table),
! 427: (void *)table, (void *)route, (void *)old);
1.1 misho 428: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
429: zlog_debug ("%s: route add: update",
430: ospf6_route_table_name (table));
431:
432: /* replace old one if exists */
433: if (node->info == old)
434: {
435: node->info = route;
436: SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
437: }
438:
439: if (old->prev)
440: old->prev->next = route;
441: route->prev = old->prev;
442: if (old->next)
443: old->next->prev = route;
444: route->next = old->next;
445:
446: route->installed = old->installed;
447: route->changed = now;
448: assert (route->table == NULL);
449: route->table = table;
450:
451: ospf6_route_unlock (old); /* will be deleted later */
452: ospf6_route_lock (route);
453:
454: SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
455: ospf6_route_table_assert (table);
456:
457: if (table->hook_add)
458: (*table->hook_add) (route);
459:
460: return route;
461: }
462:
463: /* insert if previous or next node found */
464: if (prev || next)
465: {
466: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
467: zlog_debug ("%s %p: route add %p: another path: prev %p, next %p",
1.1.1.2 ! misho 468: ospf6_route_table_name (table),
! 469: (void *)table, (void *)route, (void *)prev, (void *)next);
1.1 misho 470: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
471: zlog_debug ("%s: route add: another path found",
472: ospf6_route_table_name (table));
473:
474: if (prev == NULL)
475: prev = next->prev;
476: if (next == NULL)
477: next = prev->next;
478:
479: if (prev)
480: prev->next = route;
481: route->prev = prev;
482: if (next)
483: next->prev = route;
484: route->next = next;
485:
486: if (node->info == next)
487: {
488: assert (next->rnode == node);
489: node->info = route;
490: UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
491: SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
492: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
493: zlog_info ("%s %p: route add %p: replacing previous best: %p",
1.1.1.2 ! misho 494: ospf6_route_table_name (table),
! 495: (void *)table, (void *)route, (void *)next);
1.1 misho 496: }
497:
498: route->installed = now;
499: route->changed = now;
500: assert (route->table == NULL);
501: route->table = table;
502:
503: ospf6_route_lock (route);
504: table->count++;
505: ospf6_route_table_assert (table);
506:
507: SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
508: if (table->hook_add)
509: (*table->hook_add) (route);
510:
511: return route;
512: }
513:
514: /* Else, this is the brand new route regarding to the prefix */
515: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
516: zlog_debug ("%s %p: route add %p: brand new route",
1.1.1.2 ! misho 517: ospf6_route_table_name (table), (void *)table, (void *)route);
1.1 misho 518: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
519: zlog_debug ("%s: route add: brand new route",
520: ospf6_route_table_name (table));
521:
522: assert (node->info == NULL);
523: node->info = route;
524: SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
525: ospf6_route_lock (route);
526: route->installed = now;
527: route->changed = now;
528: assert (route->table == NULL);
529: route->table = table;
530:
531: /* lookup real existing next route */
532: nextnode = node;
533: route_lock_node (nextnode);
534: do {
535: nextnode = route_next (nextnode);
536: } while (nextnode && nextnode->info == NULL);
537:
538: /* set next link */
539: if (nextnode == NULL)
540: route->next = NULL;
541: else
542: {
543: route_unlock_node (nextnode);
544:
545: next = nextnode->info;
546: route->next = next;
547: next->prev = route;
548: }
549:
550: /* lookup real existing prev route */
551: prevnode = node;
552: route_lock_node (prevnode);
553: do {
554: prevnode = route_prev (prevnode);
555: } while (prevnode && prevnode->info == NULL);
556:
557: /* set prev link */
558: if (prevnode == NULL)
559: route->prev = NULL;
560: else
561: {
562: route_unlock_node (prevnode);
563:
564: prev = prevnode->info;
565: while (prev->next && ospf6_route_is_same (prev, prev->next))
566: prev = prev->next;
567: route->prev = prev;
568: prev->next = route;
569: }
570:
571: table->count++;
572: ospf6_route_table_assert (table);
573:
574: SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
575: if (table->hook_add)
576: (*table->hook_add) (route);
577:
578: return route;
579: }
580:
581: void
582: ospf6_route_remove (struct ospf6_route *route,
583: struct ospf6_route_table *table)
584: {
585: struct route_node *node;
586: struct ospf6_route *current;
587: char buf[64];
588:
589: if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
590: ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
591: else
592: prefix2str (&route->prefix, buf, sizeof (buf));
593:
594: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
595: zlog_debug ("%s %p: route remove %p: %s",
1.1.1.2 ! misho 596: ospf6_route_table_name (table),
! 597: (void *)table, (void *)route, buf);
1.1 misho 598: else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
599: zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf);
600:
601: node = route_node_lookup (table->table, &route->prefix);
602: assert (node);
603:
604: /* find the route to remove, making sure that the route pointer
605: is from the route table. */
606: current = node->info;
607: while (current && ospf6_route_is_same (current, route))
608: {
609: if (current == route)
610: break;
611: current = current->next;
612: }
613: assert (current == route);
614:
615: /* adjust doubly linked list */
616: if (route->prev)
617: route->prev->next = route->next;
618: if (route->next)
619: route->next->prev = route->prev;
620:
621: if (node->info == route)
622: {
623: if (route->next && ospf6_route_is_same (route->next, route))
624: {
625: node->info = route->next;
626: SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
627: }
628: else
629: node->info = NULL; /* should unlock route_node here ? */
630: }
631:
632: table->count--;
633: ospf6_route_table_assert (table);
634:
635: SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED);
636:
637: if (table->hook_remove)
638: (*table->hook_remove) (route);
639:
640: ospf6_route_unlock (route);
641: }
642:
643: struct ospf6_route *
644: ospf6_route_head (struct ospf6_route_table *table)
645: {
646: struct route_node *node;
647: struct ospf6_route *route;
648:
649: node = route_top (table->table);
650: if (node == NULL)
651: return NULL;
652:
653: /* skip to the real existing entry */
654: while (node && node->info == NULL)
655: node = route_next (node);
656: if (node == NULL)
657: return NULL;
658:
659: route_unlock_node (node);
660: assert (node->info);
661:
662: route = (struct ospf6_route *) node->info;
663: assert (route->prev == NULL);
664: assert (route->table == table);
665: ospf6_route_lock (route);
666:
667: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
668: zlog_info ("%s %p: route head: %p<-[%p]->%p",
1.1.1.2 ! misho 669: ospf6_route_table_name (table), (void *)table,
! 670: (void *)route->prev, (void *)route, (void *)route->next);
1.1 misho 671:
672: return route;
673: }
674:
675: struct ospf6_route *
676: ospf6_route_next (struct ospf6_route *route)
677: {
678: struct ospf6_route *next = route->next;
679:
680: if (IS_OSPF6_DEBUG_ROUTE (MEMORY))
681: zlog_info ("%s %p: route next: %p<-[%p]->%p",
1.1.1.2 ! misho 682: ospf6_route_table_name (route->table), (void *)route->table,
! 683: (void *)route->prev, (void *)route, (void *)route->next);
1.1 misho 684:
685: ospf6_route_unlock (route);
686: if (next)
687: ospf6_route_lock (next);
688:
689: return next;
690: }
691:
692: struct ospf6_route *
693: ospf6_route_best_next (struct ospf6_route *route)
694: {
695: struct route_node *rnode;
696: struct ospf6_route *next;
697:
698: ospf6_route_unlock (route);
699:
700: rnode = route->rnode;
701: route_lock_node (rnode);
702: rnode = route_next (rnode);
703: while (rnode && rnode->info == NULL)
704: rnode = route_next (rnode);
705: if (rnode == NULL)
706: return NULL;
707: route_unlock_node (rnode);
708:
709: assert (rnode->info);
710: next = (struct ospf6_route *) rnode->info;
711: ospf6_route_lock (next);
712: return next;
713: }
714:
715: struct ospf6_route *
716: ospf6_route_match_head (struct prefix *prefix,
717: struct ospf6_route_table *table)
718: {
719: struct route_node *node;
720: struct ospf6_route *route;
721:
722: /* Walk down tree. */
723: node = table->table->top;
724: while (node && node->p.prefixlen < prefix->prefixlen &&
725: prefix_match (&node->p, prefix))
726: node = node->link[prefix_bit(&prefix->u.prefix, node->p.prefixlen)];
727:
728: if (node)
729: route_lock_node (node);
730: while (node && node->info == NULL)
731: node = route_next (node);
732: if (node == NULL)
733: return NULL;
734: route_unlock_node (node);
735:
736: if (! prefix_match (prefix, &node->p))
737: return NULL;
738:
739: route = node->info;
740: ospf6_route_lock (route);
741: return route;
742: }
743:
744: struct ospf6_route *
745: ospf6_route_match_next (struct prefix *prefix,
746: struct ospf6_route *route)
747: {
748: struct ospf6_route *next;
749:
750: next = ospf6_route_next (route);
751: if (next && ! prefix_match (prefix, &next->prefix))
752: {
753: ospf6_route_unlock (next);
754: next = NULL;
755: }
756:
757: return next;
758: }
759:
760: void
761: ospf6_route_remove_all (struct ospf6_route_table *table)
762: {
763: struct ospf6_route *route;
764: for (route = ospf6_route_head (table); route;
765: route = ospf6_route_next (route))
766: ospf6_route_remove (route, table);
767: }
768:
769: struct ospf6_route_table *
770: ospf6_route_table_create (int s, int t)
771: {
772: struct ospf6_route_table *new;
773: new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
774: new->table = route_table_init ();
775: new->scope_type = s;
776: new->table_type = t;
777: return new;
778: }
779:
780: void
781: ospf6_route_table_delete (struct ospf6_route_table *table)
782: {
783: ospf6_route_remove_all (table);
784: route_table_finish (table->table);
785: XFREE (MTYPE_OSPF6_ROUTE, table);
786: }
787:
1.1.1.2 ! misho 788:
1.1 misho 789: /* VTY commands */
790: void
791: ospf6_route_show (struct vty *vty, struct ospf6_route *route)
792: {
793: int i;
794: char destination[64], nexthop[64];
1.1.1.2 ! misho 795: char duration[16];
! 796: const char *ifname;
1.1 misho 797: struct timeval now, res;
798:
799: quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
800: timersub (&now, &route->changed, &res);
801: timerstring (&res, duration, sizeof (duration));
802:
803: /* destination */
804: if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
805: ospf6_linkstate_prefix2str (&route->prefix, destination,
806: sizeof (destination));
807: else if (route->type == OSPF6_DEST_TYPE_ROUTER)
808: inet_ntop (route->prefix.family, &route->prefix.u.prefix,
809: destination, sizeof (destination));
810: else
811: prefix2str (&route->prefix, destination, sizeof (destination));
812:
813: /* nexthop */
814: inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
815: sizeof (nexthop));
1.1.1.2 ! misho 816: ifname = ifindex2ifname (route->nexthop[0].ifindex);
1.1 misho 817:
818: vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
819: (ospf6_route_is_best (route) ? '*' : ' '),
820: OSPF6_DEST_TYPE_SUBSTR (route->type),
821: OSPF6_PATH_TYPE_SUBSTR (route->path.type),
822: destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
823:
824: for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
825: i < OSPF6_MULTI_PATH_LIMIT; i++)
826: {
827: /* nexthop */
828: inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
829: sizeof (nexthop));
1.1.1.2 ! misho 830: ifname = ifindex2ifname (route->nexthop[i].ifindex);
1.1 misho 831:
832: vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
833: ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
834: }
835: }
836:
837: void
838: ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
839: {
1.1.1.2 ! misho 840: const char *ifname;
! 841: char destination[64], nexthop[64];
1.1 misho 842: char area_id[16], id[16], adv_router[16], capa[16], options[16];
843: struct timeval now, res;
844: char duration[16];
845: int i;
846:
847: quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
848:
849: /* destination */
850: if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
851: ospf6_linkstate_prefix2str (&route->prefix, destination,
852: sizeof (destination));
853: else if (route->type == OSPF6_DEST_TYPE_ROUTER)
854: inet_ntop (route->prefix.family, &route->prefix.u.prefix,
855: destination, sizeof (destination));
856: else
857: prefix2str (&route->prefix, destination, sizeof (destination));
858: vty_out (vty, "Destination: %s%s", destination, VNL);
859:
860: /* destination type */
861: vty_out (vty, "Destination type: %s%s",
862: OSPF6_DEST_TYPE_NAME (route->type),
863: VNL);
864:
865: /* Time */
866: timersub (&now, &route->installed, &res);
867: timerstring (&res, duration, sizeof (duration));
868: vty_out (vty, "Installed Time: %s ago%s", duration, VNL);
869:
870: timersub (&now, &route->changed, &res);
871: timerstring (&res, duration, sizeof (duration));
872: vty_out (vty, " Changed Time: %s ago%s", duration, VNL);
873:
874: /* Debugging info */
875: vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
876: (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
877: (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
878: (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
879: (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
880: VNL);
881: vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
1.1.1.2 ! misho 882: (void *)route->prev, (void *)route, (void *)route->next, VNL);
1.1 misho 883:
884: /* Path section */
885:
886: /* Area-ID */
887: inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
888: vty_out (vty, "Associated Area: %s%s", area_id, VNL);
889:
890: /* Path type */
891: vty_out (vty, "Path Type: %s%s",
892: OSPF6_PATH_TYPE_NAME (route->path.type), VNL);
893:
894: /* LS Origin */
895: inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
896: inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
897: sizeof (adv_router));
898: vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
899: ospf6_lstype_name (route->path.origin.type),
900: id, adv_router, VNL);
901:
902: /* Options */
903: ospf6_options_printbuf (route->path.options, options, sizeof (options));
904: vty_out (vty, "Options: %s%s", options, VNL);
905:
906: /* Router Bits */
907: ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
908: vty_out (vty, "Router Bits: %s%s", capa, VNL);
909:
910: /* Prefix Options */
911: vty_out (vty, "Prefix Options: xxx%s", VNL);
912:
913: /* Metrics */
914: vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
915: VNL);
916: vty_out (vty, "Metric: %d (%d)%s",
917: route->path.cost, route->path.cost_e2, VNL);
918:
919: /* Nexthops */
920: vty_out (vty, "Nexthop:%s", VNL);
921: for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
922: i < OSPF6_MULTI_PATH_LIMIT; i++)
923: {
924: /* nexthop */
925: inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
926: sizeof (nexthop));
1.1.1.2 ! misho 927: ifname = ifindex2ifname (route->nexthop[i].ifindex);
1.1 misho 928: vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
929: }
930: vty_out (vty, "%s", VNL);
931: }
932:
933: static void
934: ospf6_route_show_table_summary (struct vty *vty,
935: struct ospf6_route_table *table)
936: {
937: struct ospf6_route *route, *prev = NULL;
938: int i, pathtype[OSPF6_PATH_TYPE_MAX];
939: unsigned int number = 0;
940: int nhinval = 0, ecmp = 0;
941: int alternative = 0, destination = 0;
942:
943: for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
944: pathtype[i] = 0;
945:
946: for (route = ospf6_route_head (table); route;
947: route = ospf6_route_next (route))
948: {
949: if (prev == NULL || ! ospf6_route_is_same (prev, route))
950: destination++;
951: else
952: alternative++;
953: if (! ospf6_nexthop_is_set (&route->nexthop[0]))
954: nhinval++;
955: else if (ospf6_nexthop_is_set (&route->nexthop[1]))
956: ecmp++;
957: pathtype[route->path.type]++;
958: number++;
959:
960: prev = route;
961: }
962:
963: assert (number == table->count);
964:
965: vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL);
966: vty_out (vty, "Number of Destination: %d%s", destination, VNL);
967: vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL);
968: vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL);
969: for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++)
970: {
971: vty_out (vty, "Number of %s routes: %d%s",
972: OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL);
973: }
974: }
975:
976: static void
977: ospf6_route_show_table_prefix (struct vty *vty,
978: struct prefix *prefix,
979: struct ospf6_route_table *table)
980: {
981: struct ospf6_route *route;
982:
983: route = ospf6_route_lookup (prefix, table);
984: if (route == NULL)
985: return;
986:
987: ospf6_route_lock (route);
988: while (route && ospf6_route_is_prefix (prefix, route))
989: {
990: /* Specifying a prefix will always display details */
991: ospf6_route_show_detail (vty, route);
992: route = ospf6_route_next (route);
993: }
994: if (route)
995: ospf6_route_unlock (route);
996: }
997:
998: static void
999: ospf6_route_show_table_address (struct vty *vty,
1000: struct prefix *prefix,
1001: struct ospf6_route_table *table)
1002: {
1003: struct ospf6_route *route;
1004:
1005: route = ospf6_route_lookup_bestmatch (prefix, table);
1006: if (route == NULL)
1007: return;
1008:
1009: prefix = &route->prefix;
1010: ospf6_route_lock (route);
1011: while (route && ospf6_route_is_prefix (prefix, route))
1012: {
1013: /* Specifying a prefix will always display details */
1014: ospf6_route_show_detail (vty, route);
1015: route = ospf6_route_next (route);
1016: }
1017: if (route)
1018: ospf6_route_unlock (route);
1019: }
1020:
1021: static void
1022: ospf6_route_show_table_match (struct vty *vty, int detail,
1023: struct prefix *prefix,
1024: struct ospf6_route_table *table)
1025: {
1026: struct ospf6_route *route;
1027: assert (prefix->family);
1028:
1029: route = ospf6_route_match_head (prefix, table);
1030: while (route)
1031: {
1032: if (detail)
1033: ospf6_route_show_detail (vty, route);
1034: else
1035: ospf6_route_show (vty, route);
1036: route = ospf6_route_match_next (prefix, route);
1037: }
1038: }
1039:
1040: static void
1041: ospf6_route_show_table_type (struct vty *vty, int detail, u_char type,
1042: struct ospf6_route_table *table)
1043: {
1044: struct ospf6_route *route;
1045:
1046: route = ospf6_route_head (table);
1047: while (route)
1048: {
1049: if (route->path.type == type)
1050: {
1051: if (detail)
1052: ospf6_route_show_detail (vty, route);
1053: else
1054: ospf6_route_show (vty, route);
1055: }
1056: route = ospf6_route_next (route);
1057: }
1058: }
1059:
1060: static void
1061: ospf6_route_show_table (struct vty *vty, int detail,
1062: struct ospf6_route_table *table)
1063: {
1064: struct ospf6_route *route;
1065:
1066: route = ospf6_route_head (table);
1067: while (route)
1068: {
1069: if (detail)
1070: ospf6_route_show_detail (vty, route);
1071: else
1072: ospf6_route_show (vty, route);
1073: route = ospf6_route_next (route);
1074: }
1075: }
1076:
1077: int
1078: ospf6_route_table_show (struct vty *vty, int argc, const char *argv[],
1079: struct ospf6_route_table *table)
1080: {
1081: int summary = 0;
1082: int match = 0;
1083: int detail = 0;
1084: int slash = 0;
1085: int isprefix = 0;
1086: int i, ret;
1087: struct prefix prefix;
1088: u_char type = 0;
1089:
1090: memset (&prefix, 0, sizeof (struct prefix));
1091:
1092: for (i = 0; i < argc; i++)
1093: {
1094: if (! strcmp (argv[i], "summary"))
1095: {
1096: summary++;
1097: continue;
1098: }
1099:
1100: if (! strcmp (argv[i], "intra-area"))
1101: {
1102: type = OSPF6_PATH_TYPE_INTRA;
1103: continue;
1104: }
1105:
1106: if (! strcmp (argv[i], "inter-area"))
1107: {
1108: type = OSPF6_PATH_TYPE_INTER;
1109: continue;
1110: }
1111:
1112: if (! strcmp (argv[i], "external-1"))
1113: {
1114: type = OSPF6_PATH_TYPE_EXTERNAL1;
1115: continue;
1116: }
1117:
1118: if (! strcmp (argv[i], "external-2"))
1119: {
1120: type = OSPF6_PATH_TYPE_EXTERNAL2;
1121: continue;
1122: }
1123:
1124: if (! strcmp (argv[i], "detail"))
1125: {
1126: detail++;
1127: continue;
1128: }
1129:
1130: if (! strcmp (argv[i], "match"))
1131: {
1132: match++;
1133: continue;
1134: }
1135:
1136: ret = str2prefix (argv[i], &prefix);
1137: if (ret == 1 && prefix.family == AF_INET6)
1138: {
1139: isprefix++;
1140: if (strchr (argv[i], '/'))
1141: slash++;
1142: continue;
1143: }
1144:
1145: vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1146: return CMD_SUCCESS;
1147: }
1148:
1149: /* Give summary of this route table */
1150: if (summary)
1151: {
1152: ospf6_route_show_table_summary (vty, table);
1153: return CMD_SUCCESS;
1154: }
1155:
1156: /* Give exact prefix-match route */
1157: if (isprefix && ! match)
1158: {
1159: /* If exact address, give best matching route */
1160: if (! slash)
1161: ospf6_route_show_table_address (vty, &prefix, table);
1162: else
1163: ospf6_route_show_table_prefix (vty, &prefix, table);
1164:
1165: return CMD_SUCCESS;
1166: }
1167:
1168: if (match)
1169: ospf6_route_show_table_match (vty, detail, &prefix, table);
1170: else if (type)
1171: ospf6_route_show_table_type (vty, detail, type, table);
1172: else
1173: ospf6_route_show_table (vty, detail, table);
1174:
1175: return CMD_SUCCESS;
1176: }
1177:
1178: static void
1179: ospf6_linkstate_show_header (struct vty *vty)
1180: {
1181: vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s",
1182: "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL);
1183: }
1184:
1185: static void
1186: ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route)
1187: {
1188: u_int32_t router, id;
1189: char routername[16], idname[16], rbits[16], options[16];
1190:
1191: router = ospf6_linkstate_prefix_adv_router (&route->prefix);
1192: inet_ntop (AF_INET, &router, routername, sizeof (routername));
1193: id = ospf6_linkstate_prefix_id (&route->prefix);
1194: inet_ntop (AF_INET, &id, idname, sizeof (idname));
1195:
1196: ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
1197: ospf6_options_printbuf (route->path.options, options, sizeof (options));
1198:
1199: if (ntohl (id))
1200: vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
1201: "Network", routername, idname, rbits, options,
1202: (unsigned long) route->path.cost, VNL);
1203: else
1204: vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s",
1205: "Router", routername, idname, rbits, options,
1206: (unsigned long) route->path.cost, VNL);
1207: }
1208:
1209:
1210: static void
1211: ospf6_linkstate_show_table_exact (struct vty *vty,
1212: struct prefix *prefix,
1213: struct ospf6_route_table *table)
1214: {
1215: struct ospf6_route *route;
1216:
1217: route = ospf6_route_lookup (prefix, table);
1218: if (route == NULL)
1219: return;
1220:
1221: ospf6_route_lock (route);
1222: while (route && ospf6_route_is_prefix (prefix, route))
1223: {
1224: /* Specifying a prefix will always display details */
1225: ospf6_route_show_detail (vty, route);
1226: route = ospf6_route_next (route);
1227: }
1228: if (route)
1229: ospf6_route_unlock (route);
1230: }
1231:
1232: static void
1233: ospf6_linkstate_show_table (struct vty *vty, int detail,
1234: struct ospf6_route_table *table)
1235: {
1236: struct ospf6_route *route;
1237:
1238: if (! detail)
1239: ospf6_linkstate_show_header (vty);
1240:
1241: route = ospf6_route_head (table);
1242: while (route)
1243: {
1244: if (detail)
1245: ospf6_route_show_detail (vty, route);
1246: else
1247: ospf6_linkstate_show (vty, route);
1248: route = ospf6_route_next (route);
1249: }
1250: }
1251:
1252: int
1253: ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[],
1254: struct ospf6_route_table *table)
1255: {
1256: int detail = 0;
1257: int is_id = 0;
1258: int is_router = 0;
1259: int i, ret;
1260: struct prefix router, id, prefix;
1261:
1262: memset (&router, 0, sizeof (struct prefix));
1263: memset (&id, 0, sizeof (struct prefix));
1264: memset (&prefix, 0, sizeof (struct prefix));
1265:
1266: for (i = 0; i < argc; i++)
1267: {
1268: if (! strcmp (argv[i], "detail"))
1269: {
1270: detail++;
1271: continue;
1272: }
1273:
1274: if (! is_router)
1275: {
1276: ret = str2prefix (argv[i], &router);
1277: if (ret == 1 && router.family == AF_INET)
1278: {
1279: is_router++;
1280: continue;
1281: }
1282: vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1283: return CMD_SUCCESS;
1284: }
1285:
1286: if (! is_id)
1287: {
1288: ret = str2prefix (argv[i], &id);
1289: if (ret == 1 && id.family == AF_INET)
1290: {
1291: is_id++;
1292: continue;
1293: }
1294: vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1295: return CMD_SUCCESS;
1296: }
1297:
1298: vty_out (vty, "Malformed argument: %s%s", argv[i], VNL);
1299: return CMD_SUCCESS;
1300: }
1301:
1302: if (is_router)
1303: ospf6_linkstate_prefix (router.u.prefix4.s_addr,
1304: id.u.prefix4.s_addr, &prefix);
1305:
1306: if (prefix.family)
1307: ospf6_linkstate_show_table_exact (vty, &prefix, table);
1308: else
1309: ospf6_linkstate_show_table (vty, detail, table);
1310:
1311: return CMD_SUCCESS;
1312: }
1313:
1314:
1315: void
1316: ospf6_brouter_show_header (struct vty *vty)
1317: {
1318: vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1319: "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL);
1320: }
1321:
1322: void
1323: ospf6_brouter_show (struct vty *vty, struct ospf6_route *route)
1324: {
1325: u_int32_t adv_router;
1326: char adv[16], rbits[16], options[16], area[16];
1327:
1328: adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix);
1329: inet_ntop (AF_INET, &adv_router, adv, sizeof (adv));
1330: ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits));
1331: ospf6_options_printbuf (route->path.options, options, sizeof (options));
1332: inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area));
1333:
1334: /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1335: "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */
1336: vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s",
1337: adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type),
1338: area, VNL);
1339: }
1340:
1341: DEFUN (debug_ospf6_route,
1342: debug_ospf6_route_cmd,
1343: "debug ospf6 route (table|intra-area|inter-area|memory)",
1344: DEBUG_STR
1345: OSPF6_STR
1346: "Debug route table calculation\n"
1347: "Debug detail\n"
1348: "Debug intra-area route calculation\n"
1349: "Debug inter-area route calculation\n"
1350: "Debug route memory use\n"
1351: )
1352: {
1353: unsigned char level = 0;
1354:
1355: if (! strncmp (argv[0], "table", 5))
1356: level = OSPF6_DEBUG_ROUTE_TABLE;
1357: else if (! strncmp (argv[0], "intra", 5))
1358: level = OSPF6_DEBUG_ROUTE_INTRA;
1359: else if (! strncmp (argv[0], "inter", 5))
1360: level = OSPF6_DEBUG_ROUTE_INTER;
1361: else if (! strncmp (argv[0], "memor", 5))
1362: level = OSPF6_DEBUG_ROUTE_MEMORY;
1363: OSPF6_DEBUG_ROUTE_ON (level);
1364: return CMD_SUCCESS;
1365: }
1366:
1367: DEFUN (no_debug_ospf6_route,
1368: no_debug_ospf6_route_cmd,
1369: "no debug ospf6 route (table|intra-area|inter-area|memory)",
1370: NO_STR
1371: DEBUG_STR
1372: OSPF6_STR
1373: "Debug route table calculation\n"
1374: "Debug intra-area route calculation\n"
1375: "Debug route memory use\n")
1376: {
1377: unsigned char level = 0;
1378:
1379: if (! strncmp (argv[0], "table", 5))
1380: level = OSPF6_DEBUG_ROUTE_TABLE;
1381: else if (! strncmp (argv[0], "intra", 5))
1382: level = OSPF6_DEBUG_ROUTE_INTRA;
1383: else if (! strncmp (argv[0], "inter", 5))
1384: level = OSPF6_DEBUG_ROUTE_INTER;
1385: else if (! strncmp (argv[0], "memor", 5))
1386: level = OSPF6_DEBUG_ROUTE_MEMORY;
1387: OSPF6_DEBUG_ROUTE_OFF (level);
1388: return CMD_SUCCESS;
1389: }
1390:
1391: int
1392: config_write_ospf6_debug_route (struct vty *vty)
1393: {
1394: if (IS_OSPF6_DEBUG_ROUTE (TABLE))
1395: vty_out (vty, "debug ospf6 route table%s", VNL);
1396: if (IS_OSPF6_DEBUG_ROUTE (INTRA))
1397: vty_out (vty, "debug ospf6 route intra-area%s", VNL);
1398: if (IS_OSPF6_DEBUG_ROUTE (INTER))
1399: vty_out (vty, "debug ospf6 route inter-area%s", VNL);
1400: return 0;
1401: }
1402:
1403: void
1404: install_element_ospf6_debug_route (void)
1405: {
1406: install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
1407: install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
1408: install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
1409: install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
1410: }
1411:
1412:
1413:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>