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