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