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