]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_route.c
Merge pull request #8267 from idryzhov/bgp-cli-fixes
[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_array_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_string_add(json_route, "destination", destination);
1076 json_object_boolean_add(json_route, "isBestRoute",
1077 ospf6_route_is_best(route));
1078 json_object_string_add(json_route, "destinationType",
1079 OSPF6_DEST_TYPE_SUBSTR(route->type));
1080 json_object_string_add(
1081 json_route, "pathType",
1082 OSPF6_PATH_TYPE_SUBSTR(route->path.type));
1083 json_object_string_add(json_route, "duration", duration);
1084 }
1085
1086 /* Nexthops */
1087 if (use_json)
1088 json_array_next_hops = json_object_new_array();
1089 else
1090 i = 0;
1091 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
1092 struct interface *ifp;
1093 /* nexthop */
1094 inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
1095 ifp = if_lookup_by_index_all_vrf(nh->ifindex);
1096 if (use_json) {
1097 json_next_hop = json_object_new_object();
1098 json_object_string_add(json_next_hop, "nextHop",
1099 nexthop);
1100 json_object_string_add(json_next_hop, "interfaceName",
1101 ifp->name);
1102 json_object_array_add(json_array_next_hops,
1103 json_next_hop);
1104 } else {
1105 if (!i) {
1106 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1107 (ospf6_route_is_best(route) ? '*'
1108 : ' '),
1109 OSPF6_DEST_TYPE_SUBSTR(route->type),
1110 OSPF6_PATH_TYPE_SUBSTR(
1111 route->path.type),
1112 destination, nexthop, IFNAMSIZ,
1113 ifp->name, duration);
1114 i++;
1115 } else
1116 vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
1117 ' ', "", "", "", nexthop, IFNAMSIZ,
1118 ifp->name, "");
1119 }
1120 }
1121 if (use_json) {
1122 json_object_object_add(json_route, "nextHops",
1123 json_array_next_hops);
1124 json_object_array_add(json_array_routes, json_route);
1125 }
1126 }
1127
1128 void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
1129 json_object *json_array_routes, bool use_json)
1130 {
1131 char destination[PREFIX2STR_BUFFER], nexthop[64];
1132 char area_id[16], id[16], adv_router[16], capa[16], options[16];
1133 struct timeval now, res;
1134 char duration[64];
1135 struct listnode *node;
1136 struct ospf6_nexthop *nh;
1137 char flag[6];
1138 json_object *json_route = NULL;
1139 json_object *json_array_next_hops = NULL;
1140 json_object *json_next_hop;
1141
1142 if (om6->ospf6 == NULL) {
1143 vty_out(vty, "OSPFv3 is not running\n");
1144 return;
1145 }
1146
1147 monotime(&now);
1148
1149 /* destination */
1150 if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
1151 ospf6_linkstate_prefix2str(&route->prefix, destination,
1152 sizeof(destination));
1153 else if (route->type == OSPF6_DEST_TYPE_ROUTER)
1154 inet_ntop(route->prefix.family, &route->prefix.u.prefix,
1155 destination, sizeof(destination));
1156 else
1157 prefix2str(&route->prefix, destination, sizeof(destination));
1158
1159 if (use_json) {
1160 json_route = json_object_new_object();
1161 json_object_string_add(json_route, "destination", destination);
1162 json_object_string_add(json_route, "destinationType",
1163 OSPF6_DEST_TYPE_NAME(route->type));
1164 } else {
1165 vty_out(vty, "Destination: %s\n", destination);
1166 vty_out(vty, "Destination type: %s\n",
1167 OSPF6_DEST_TYPE_NAME(route->type));
1168 }
1169
1170 /* Time */
1171 timersub(&now, &route->installed, &res);
1172 timerstring(&res, duration, sizeof(duration));
1173 if (use_json)
1174 json_object_string_add(json_route, "installedTimeSince",
1175 duration);
1176 else
1177 vty_out(vty, "Installed Time: %s ago\n", duration);
1178
1179 timersub(&now, &route->changed, &res);
1180 timerstring(&res, duration, sizeof(duration));
1181 if (use_json)
1182 json_object_string_add(json_route, "changedTimeSince",
1183 duration);
1184 else
1185 vty_out(vty, "Changed Time: %s ago\n", duration);
1186
1187 /* Debugging info */
1188 if (use_json) {
1189 json_object_int_add(json_route, "numberOfLock", route->lock);
1190 snprintf(
1191 flag, sizeof(flag), "%s%s%s%s",
1192 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1193 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1194 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1195 : "-"),
1196 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1197 : "-"));
1198 json_object_string_add(json_route, "flags", flag);
1199 } else {
1200 vty_out(vty, "Lock: %d Flags: %s%s%s%s\n", route->lock,
1201 (CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
1202 (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
1203 (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE) ? "R"
1204 : "-"),
1205 (CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE) ? "C"
1206 : "-"));
1207 vty_out(vty, "Memory: prev: %p this: %p next: %p\n",
1208 (void *)route->prev, (void *)route,
1209 (void *)route->next);
1210 }
1211
1212 /* Path section */
1213
1214 /* Area-ID */
1215 inet_ntop(AF_INET, &route->path.area_id, area_id, sizeof(area_id));
1216 if (use_json)
1217 json_object_string_add(json_route, "associatedArea", area_id);
1218 else
1219 vty_out(vty, "Associated Area: %s\n", area_id);
1220
1221 /* Path type */
1222 if (use_json)
1223 json_object_string_add(json_route, "pathType",
1224 OSPF6_PATH_TYPE_NAME(route->path.type));
1225 else
1226 vty_out(vty, "Path Type: %s\n",
1227 OSPF6_PATH_TYPE_NAME(route->path.type));
1228
1229 /* LS Origin */
1230 inet_ntop(AF_INET, &route->path.origin.id, id, sizeof(id));
1231 inet_ntop(AF_INET, &route->path.origin.adv_router, adv_router,
1232 sizeof(adv_router));
1233 if (use_json) {
1234 json_object_string_add(
1235 json_route, "lsOriginRoutePathType",
1236 ospf6_lstype_name(route->path.origin.type));
1237 json_object_string_add(json_route, "lsId", id);
1238 json_object_string_add(json_route, "lsAdvertisingRouter",
1239 adv_router);
1240 } else {
1241 vty_out(vty, "LS Origin: %s Id: %s Adv: %s\n",
1242 ospf6_lstype_name(route->path.origin.type), id,
1243 adv_router);
1244 }
1245
1246 /* Options */
1247 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1248 if (use_json)
1249 json_object_string_add(json_route, "options", options);
1250 else
1251 vty_out(vty, "Options: %s\n", options);
1252
1253 /* Router Bits */
1254 ospf6_capability_printbuf(route->path.router_bits, capa, sizeof(capa));
1255 if (use_json)
1256 json_object_string_add(json_route, "routerBits", capa);
1257 else
1258 vty_out(vty, "Router Bits: %s\n", capa);
1259
1260 /* Prefix Options */
1261 if (use_json)
1262 json_object_string_add(json_route, "prefixOptions", "xxx");
1263 else
1264 vty_out(vty, "Prefix Options: xxx\n");
1265
1266 /* Metrics */
1267 if (use_json) {
1268 json_object_int_add(json_route, "metricType",
1269 route->path.metric_type);
1270 json_object_int_add(json_route, "metricCost", route->path.cost);
1271 json_object_int_add(json_route, "metricCostE2",
1272 route->path.u.cost_e2);
1273
1274 json_object_int_add(json_route, "pathsCount",
1275 route->paths->count);
1276 json_object_int_add(json_route, "nextHopCount",
1277 route->nh_list->count);
1278 } else {
1279 vty_out(vty, "Metric Type: %d\n", route->path.metric_type);
1280 vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
1281 route->path.u.cost_e2);
1282
1283 vty_out(vty, "Paths count: %u\n", route->paths->count);
1284 vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
1285 }
1286
1287 /* Nexthops */
1288 if (use_json)
1289 json_array_next_hops = json_object_new_array();
1290 else
1291 vty_out(vty, "Nexthop:\n");
1292
1293 for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
1294 struct interface *ifp;
1295 ifp = if_lookup_by_index_all_vrf(nh->ifindex);
1296 /* nexthop */
1297 if (use_json) {
1298 inet_ntop(AF_INET6, &nh->address, nexthop,
1299 sizeof(nexthop));
1300 json_next_hop = json_object_new_object();
1301 json_object_string_add(json_next_hop, "nextHop",
1302 nexthop);
1303 json_object_string_add(json_next_hop, "interfaceName",
1304 ifp->name);
1305 json_object_array_add(json_array_next_hops,
1306 json_next_hop);
1307 } else
1308 vty_out(vty, " %pI6 %.*s\n", &nh->address, IFNAMSIZ,
1309 ifp->name);
1310 }
1311 if (use_json) {
1312 json_object_object_add(json_route, "nextHops",
1313 json_array_next_hops);
1314 json_object_array_add(json_array_routes, json_route);
1315 } else
1316 vty_out(vty, "\n");
1317 }
1318
1319 static void ospf6_route_show_table_summary(struct vty *vty,
1320 struct ospf6_route_table *table,
1321 json_object *json, bool use_json)
1322 {
1323 struct ospf6_route *route, *prev = NULL;
1324 int i, pathtype[OSPF6_PATH_TYPE_MAX];
1325 unsigned int number = 0;
1326 int nh_count = 0, nhinval = 0, ecmp = 0;
1327 int alternative = 0, destination = 0;
1328 char path_str[30];
1329
1330 for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
1331 pathtype[i] = 0;
1332
1333 for (route = ospf6_route_head(table); route;
1334 route = ospf6_route_next(route)) {
1335 if (prev == NULL || !ospf6_route_is_same(prev, route))
1336 destination++;
1337 else
1338 alternative++;
1339 nh_count = ospf6_num_nexthops(route->nh_list);
1340 if (!nh_count)
1341 nhinval++;
1342 else if (nh_count > 1)
1343 ecmp++;
1344 pathtype[route->path.type]++;
1345 number++;
1346
1347 prev = route;
1348 }
1349
1350 assert(number == table->count);
1351 if (use_json) {
1352 json_object_int_add(json, "numberOfOspfv3Routes", number);
1353 json_object_int_add(json, "numberOfDestination", destination);
1354 json_object_int_add(json, "numberOfAlternativeRoutes",
1355 alternative);
1356 json_object_int_add(json, "numberOfEcmp", ecmp);
1357 } else {
1358 vty_out(vty, "Number of OSPFv3 routes: %d\n", number);
1359 vty_out(vty, "Number of Destination: %d\n", destination);
1360 vty_out(vty, "Number of Alternative routes: %d\n", alternative);
1361 vty_out(vty, "Number of Equal Cost Multi Path: %d\n", ecmp);
1362 }
1363 for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) {
1364 if (use_json) {
1365 snprintf(path_str, sizeof(path_str), "numberOf%sRoutes",
1366 OSPF6_PATH_TYPE_JSON(i));
1367 json_object_int_add(json, path_str, pathtype[i]);
1368 } else
1369 vty_out(vty, "Number of %s routes: %d\n",
1370 OSPF6_PATH_TYPE_NAME(i), pathtype[i]);
1371 }
1372 }
1373
1374 static void ospf6_route_show_table_prefix(struct vty *vty,
1375 struct prefix *prefix,
1376 struct ospf6_route_table *table,
1377 json_object *json, bool use_json)
1378 {
1379 struct ospf6_route *route;
1380 json_object *json_array_routes = NULL;
1381
1382 route = ospf6_route_lookup(prefix, table);
1383 if (route == NULL)
1384 return;
1385
1386 if (use_json)
1387 json_array_routes = json_object_new_array();
1388 ospf6_route_lock(route);
1389 while (route && ospf6_route_is_prefix(prefix, route)) {
1390 /* Specifying a prefix will always display details */
1391 ospf6_route_show_detail(vty, route, json_array_routes,
1392 use_json);
1393 route = ospf6_route_next(route);
1394 }
1395
1396 if (use_json)
1397 json_object_object_add(json, "routes", json_array_routes);
1398 if (route)
1399 ospf6_route_unlock(route);
1400 }
1401
1402 static void ospf6_route_show_table_address(struct vty *vty,
1403 struct prefix *prefix,
1404 struct ospf6_route_table *table,
1405 json_object *json, bool use_json)
1406 {
1407 struct ospf6_route *route;
1408 json_object *json_array_routes = NULL;
1409
1410 route = ospf6_route_lookup_bestmatch(prefix, table);
1411 if (route == NULL)
1412 return;
1413
1414 if (use_json)
1415 json_array_routes = json_object_new_array();
1416 prefix = &route->prefix;
1417 ospf6_route_lock(route);
1418 while (route && ospf6_route_is_prefix(prefix, route)) {
1419 /* Specifying a prefix will always display details */
1420 ospf6_route_show_detail(vty, route, json_array_routes,
1421 use_json);
1422 route = ospf6_route_next(route);
1423 }
1424 if (use_json)
1425 json_object_object_add(json, "routes", json_array_routes);
1426 if (route)
1427 ospf6_route_unlock(route);
1428 }
1429
1430 static void ospf6_route_show_table_match(struct vty *vty, int detail,
1431 struct prefix *prefix,
1432 struct ospf6_route_table *table,
1433 json_object *json, bool use_json)
1434 {
1435 struct ospf6_route *route;
1436 json_object *json_array_routes = NULL;
1437
1438 assert(prefix->family);
1439
1440 route = ospf6_route_match_head(prefix, table);
1441 if (use_json)
1442 json_array_routes = json_object_new_array();
1443 while (route) {
1444 if (detail)
1445 ospf6_route_show_detail(vty, route, json_array_routes,
1446 use_json);
1447 else
1448 ospf6_route_show(vty, route, json_array_routes,
1449 use_json);
1450 route = ospf6_route_match_next(prefix, route);
1451 }
1452 if (use_json)
1453 json_object_object_add(json, "routes", json_array_routes);
1454 }
1455
1456 static void ospf6_route_show_table_type(struct vty *vty, int detail,
1457 uint8_t type,
1458 struct ospf6_route_table *table,
1459 json_object *json, bool use_json)
1460 {
1461 struct ospf6_route *route;
1462 json_object *json_array_routes = NULL;
1463
1464 route = ospf6_route_head(table);
1465 if (use_json)
1466 json_array_routes = json_object_new_array();
1467 while (route) {
1468 if (route->path.type == type) {
1469 if (detail)
1470 ospf6_route_show_detail(vty, route,
1471 json_array_routes,
1472 use_json);
1473 else
1474 ospf6_route_show(vty, route, json_array_routes,
1475 use_json);
1476 }
1477 route = ospf6_route_next(route);
1478 }
1479 if (use_json)
1480 json_object_object_add(json, "routes", json_array_routes);
1481 }
1482
1483 static void ospf6_route_show_table(struct vty *vty, int detail,
1484 struct ospf6_route_table *table,
1485 json_object *json, bool use_json)
1486 {
1487 struct ospf6_route *route;
1488 json_object *json_array_routes = NULL;
1489
1490 route = ospf6_route_head(table);
1491 if (use_json)
1492 json_array_routes = json_object_new_array();
1493 while (route) {
1494 if (detail)
1495 ospf6_route_show_detail(vty, route, json_array_routes,
1496 use_json);
1497 else
1498 ospf6_route_show(vty, route, json_array_routes,
1499 use_json);
1500 route = ospf6_route_next(route);
1501 }
1502 if (use_json)
1503 json_object_object_add(json, "routes", json_array_routes);
1504 }
1505
1506 int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
1507 struct cmd_token **argv,
1508 struct ospf6_route_table *table, bool use_json)
1509 {
1510 int summary = 0;
1511 int match = 0;
1512 int detail = 0;
1513 int slash = 0;
1514 int isprefix = 0;
1515 int i, ret;
1516 struct prefix prefix;
1517 uint8_t type = 0;
1518 int arg_end = use_json ? (argc - 1) : argc;
1519 json_object *json = NULL;
1520
1521 memset(&prefix, 0, sizeof(struct prefix));
1522
1523 if (use_json)
1524 json = json_object_new_object();
1525
1526 for (i = argc_start; i < arg_end; i++) {
1527 if (strmatch(argv[i]->text, "summary")) {
1528 summary++;
1529 continue;
1530 }
1531
1532 if (strmatch(argv[i]->text, "intra-area")) {
1533 type = OSPF6_PATH_TYPE_INTRA;
1534 continue;
1535 }
1536
1537 if (strmatch(argv[i]->text, "inter-area")) {
1538 type = OSPF6_PATH_TYPE_INTER;
1539 continue;
1540 }
1541
1542 if (strmatch(argv[i]->text, "external-1")) {
1543 type = OSPF6_PATH_TYPE_EXTERNAL1;
1544 continue;
1545 }
1546
1547 if (strmatch(argv[i]->text, "external-2")) {
1548 type = OSPF6_PATH_TYPE_EXTERNAL2;
1549 continue;
1550 }
1551
1552 if (strmatch(argv[i]->text, "detail")) {
1553 detail++;
1554 continue;
1555 }
1556
1557 if (strmatch(argv[i]->text, "match")) {
1558 match++;
1559 continue;
1560 }
1561
1562 ret = str2prefix(argv[i]->arg, &prefix);
1563 if (ret == 1 && prefix.family == AF_INET6) {
1564 isprefix++;
1565 if (strchr(argv[i]->arg, '/'))
1566 slash++;
1567 continue;
1568 }
1569 if (use_json)
1570 json_object_string_add(json, "malformedArgument",
1571 argv[i]->arg);
1572 else
1573 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1574
1575 return CMD_SUCCESS;
1576 }
1577
1578 /* Give summary of this route table */
1579 if (summary) {
1580 ospf6_route_show_table_summary(vty, table, json, use_json);
1581 if (use_json) {
1582 vty_out(vty, "%s\n",
1583 json_object_to_json_string_ext(
1584 json, JSON_C_TO_STRING_PRETTY));
1585 json_object_free(json);
1586 }
1587 return CMD_SUCCESS;
1588 }
1589
1590 /* Give exact prefix-match route */
1591 if (isprefix && !match) {
1592 /* If exact address, give best matching route */
1593 if (!slash)
1594 ospf6_route_show_table_address(vty, &prefix, table,
1595 json, use_json);
1596 else
1597 ospf6_route_show_table_prefix(vty, &prefix, table, json,
1598 use_json);
1599
1600 if (use_json) {
1601 vty_out(vty, "%s\n",
1602 json_object_to_json_string_ext(
1603 json, JSON_C_TO_STRING_PRETTY));
1604 json_object_free(json);
1605 }
1606 return CMD_SUCCESS;
1607 }
1608
1609 if (match)
1610 ospf6_route_show_table_match(vty, detail, &prefix, table, json,
1611 use_json);
1612 else if (type)
1613 ospf6_route_show_table_type(vty, detail, type, table, json,
1614 use_json);
1615 else
1616 ospf6_route_show_table(vty, detail, table, json, use_json);
1617
1618 if (use_json) {
1619 vty_out(vty, "%s\n",
1620 json_object_to_json_string_ext(
1621 json, JSON_C_TO_STRING_PRETTY));
1622 json_object_free(json);
1623 }
1624 return CMD_SUCCESS;
1625 }
1626
1627 static void ospf6_linkstate_show_header(struct vty *vty)
1628 {
1629 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %s\n", "Type", "Router-ID",
1630 "Net-ID", "Rtr-Bits", "Options", "Cost");
1631 }
1632
1633 static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route)
1634 {
1635 uint32_t router, id;
1636 char routername[16], idname[16], rbits[16], options[16];
1637
1638 router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1639 inet_ntop(AF_INET, &router, routername, sizeof(routername));
1640 id = ospf6_linkstate_prefix_id(&route->prefix);
1641 inet_ntop(AF_INET, &id, idname, sizeof(idname));
1642
1643 ospf6_capability_printbuf(route->path.router_bits, rbits,
1644 sizeof(rbits));
1645 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1646
1647 if (ntohl(id))
1648 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Network",
1649 routername, idname, rbits, options,
1650 (unsigned long)route->path.cost);
1651 else
1652 vty_out(vty, "%-7s %-15s %-15s %-8s %-14s %lu\n", "Router",
1653 routername, idname, rbits, options,
1654 (unsigned long)route->path.cost);
1655 }
1656
1657
1658 static void ospf6_linkstate_show_table_exact(struct vty *vty,
1659 struct prefix *prefix,
1660 struct ospf6_route_table *table)
1661 {
1662 struct ospf6_route *route;
1663
1664 route = ospf6_route_lookup(prefix, table);
1665 if (route == NULL)
1666 return;
1667
1668 ospf6_route_lock(route);
1669 while (route && ospf6_route_is_prefix(prefix, route)) {
1670 /* Specifying a prefix will always display details */
1671 ospf6_route_show_detail(vty, route, NULL, false);
1672 route = ospf6_route_next(route);
1673 }
1674 if (route)
1675 ospf6_route_unlock(route);
1676 }
1677
1678 static void ospf6_linkstate_show_table(struct vty *vty, int detail,
1679 struct ospf6_route_table *table)
1680 {
1681 struct ospf6_route *route;
1682
1683 if (!detail)
1684 ospf6_linkstate_show_header(vty);
1685
1686 route = ospf6_route_head(table);
1687 while (route) {
1688 if (detail)
1689 ospf6_route_show_detail(vty, route, NULL, false);
1690 else
1691 ospf6_linkstate_show(vty, route);
1692 route = ospf6_route_next(route);
1693 }
1694 }
1695
1696 int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
1697 struct cmd_token **argv,
1698 struct ospf6_route_table *table)
1699 {
1700 int detail = 0;
1701 int is_id = 0;
1702 int is_router = 0;
1703 int i, ret;
1704 struct prefix router, id, prefix;
1705
1706 memset(&router, 0, sizeof(struct prefix));
1707 memset(&id, 0, sizeof(struct prefix));
1708 memset(&prefix, 0, sizeof(struct prefix));
1709
1710 for (i = idx_ipv4; i < argc; i++) {
1711 if (strmatch(argv[i]->text, "detail")) {
1712 detail++;
1713 continue;
1714 }
1715
1716 if (!is_router) {
1717 ret = str2prefix(argv[i]->arg, &router);
1718 if (ret == 1 && router.family == AF_INET) {
1719 is_router++;
1720 continue;
1721 }
1722 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1723 return CMD_SUCCESS;
1724 }
1725
1726 if (!is_id) {
1727 ret = str2prefix(argv[i]->arg, &id);
1728 if (ret == 1 && id.family == AF_INET) {
1729 is_id++;
1730 continue;
1731 }
1732 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1733 return CMD_SUCCESS;
1734 }
1735
1736 vty_out(vty, "Malformed argument: %s\n", argv[i]->arg);
1737 return CMD_SUCCESS;
1738 }
1739
1740 if (is_router)
1741 ospf6_linkstate_prefix(router.u.prefix4.s_addr,
1742 id.u.prefix4.s_addr, &prefix);
1743
1744 if (prefix.family)
1745 ospf6_linkstate_show_table_exact(vty, &prefix, table);
1746 else
1747 ospf6_linkstate_show_table(vty, detail, table);
1748
1749 return CMD_SUCCESS;
1750 }
1751
1752
1753 void ospf6_brouter_show_header(struct vty *vty)
1754 {
1755 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", "Router-ID", "Rtr-Bits",
1756 "Options", "Path-Type", "Area");
1757 }
1758
1759 void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route)
1760 {
1761 uint32_t adv_router;
1762 char adv[16], rbits[16], options[16], area[16];
1763
1764 adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix);
1765 inet_ntop(AF_INET, &adv_router, adv, sizeof(adv));
1766 ospf6_capability_printbuf(route->path.router_bits, rbits,
1767 sizeof(rbits));
1768 ospf6_options_printbuf(route->path.options, options, sizeof(options));
1769 inet_ntop(AF_INET, &route->path.area_id, area, sizeof(area));
1770
1771 /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s\n",
1772 "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area"); */
1773 vty_out(vty, "%-15s %-8s %-14s %-10s %-15s\n", adv, rbits, options,
1774 OSPF6_PATH_TYPE_NAME(route->path.type), area);
1775 }
1776
1777 DEFUN (debug_ospf6_route,
1778 debug_ospf6_route_cmd,
1779 "debug ospf6 route <table|intra-area|inter-area|memory>",
1780 DEBUG_STR
1781 OSPF6_STR
1782 "Debug routes\n"
1783 "Debug route table calculation\n"
1784 "Debug intra-area route calculation\n"
1785 "Debug inter-area route calculation\n"
1786 "Debug route memory use\n"
1787 )
1788 {
1789 int idx_type = 3;
1790 unsigned char level = 0;
1791
1792 if (!strcmp(argv[idx_type]->text, "table"))
1793 level = OSPF6_DEBUG_ROUTE_TABLE;
1794 else if (!strcmp(argv[idx_type]->text, "intra-area"))
1795 level = OSPF6_DEBUG_ROUTE_INTRA;
1796 else if (!strcmp(argv[idx_type]->text, "inter-area"))
1797 level = OSPF6_DEBUG_ROUTE_INTER;
1798 else if (!strcmp(argv[idx_type]->text, "memory"))
1799 level = OSPF6_DEBUG_ROUTE_MEMORY;
1800 OSPF6_DEBUG_ROUTE_ON(level);
1801 return CMD_SUCCESS;
1802 }
1803
1804 DEFUN (no_debug_ospf6_route,
1805 no_debug_ospf6_route_cmd,
1806 "no debug ospf6 route <table|intra-area|inter-area|memory>",
1807 NO_STR
1808 DEBUG_STR
1809 OSPF6_STR
1810 "Debug routes\n"
1811 "Debug route table calculation\n"
1812 "Debug intra-area route calculation\n"
1813 "Debug inter-area route calculation\n"
1814 "Debug route memory use\n")
1815 {
1816 int idx_type = 4;
1817 unsigned char level = 0;
1818
1819 if (!strcmp(argv[idx_type]->text, "table"))
1820 level = OSPF6_DEBUG_ROUTE_TABLE;
1821 else if (!strcmp(argv[idx_type]->text, "intra-area"))
1822 level = OSPF6_DEBUG_ROUTE_INTRA;
1823 else if (!strcmp(argv[idx_type]->text, "inter-area"))
1824 level = OSPF6_DEBUG_ROUTE_INTER;
1825 else if (!strcmp(argv[idx_type]->text, "memory"))
1826 level = OSPF6_DEBUG_ROUTE_MEMORY;
1827 OSPF6_DEBUG_ROUTE_OFF(level);
1828 return CMD_SUCCESS;
1829 }
1830
1831 int config_write_ospf6_debug_route(struct vty *vty)
1832 {
1833 if (IS_OSPF6_DEBUG_ROUTE(TABLE))
1834 vty_out(vty, "debug ospf6 route table\n");
1835 if (IS_OSPF6_DEBUG_ROUTE(INTRA))
1836 vty_out(vty, "debug ospf6 route intra-area\n");
1837 if (IS_OSPF6_DEBUG_ROUTE(INTER))
1838 vty_out(vty, "debug ospf6 route inter-area\n");
1839 if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
1840 vty_out(vty, "debug ospf6 route memory\n");
1841
1842 return 0;
1843 }
1844
1845 void install_element_ospf6_debug_route(void)
1846 {
1847 install_element(ENABLE_NODE, &debug_ospf6_route_cmd);
1848 install_element(ENABLE_NODE, &no_debug_ospf6_route_cmd);
1849 install_element(CONFIG_NODE, &debug_ospf6_route_cmd);
1850 install_element(CONFIG_NODE, &no_debug_ospf6_route_cmd);
1851 }