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