]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
508e53e2 | 2 | * Copyright (C) 2003 Yasuhiro Ohara |
718e3744 | 3 | * |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with GNU Zebra; see the file COPYING. If not, write to the | |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | * Boston, MA 02111-1307, USA. | |
20 | */ | |
21 | ||
508e53e2 | 22 | #include <zebra.h> |
23 | ||
24 | #include "log.h" | |
25 | #include "memory.h" | |
26 | #include "prefix.h" | |
27 | #include "table.h" | |
28 | #include "vty.h" | |
29 | #include "command.h" | |
30 | ||
508e53e2 | 31 | #include "ospf6_proto.h" |
32 | #include "ospf6_lsa.h" | |
049207c3 | 33 | #include "ospf6_lsdb.h" |
508e53e2 | 34 | #include "ospf6_route.h" |
049207c3 | 35 | #include "ospf6d.h" |
718e3744 | 36 | |
508e53e2 | 37 | unsigned char conf_debug_ospf6_route = 0; |
718e3744 | 38 | |
508e53e2 | 39 | void |
40 | ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, | |
41 | struct prefix *prefix) | |
42 | { | |
43 | memset (prefix, 0, sizeof (struct prefix)); | |
44 | prefix->family = AF_INET6; | |
45 | prefix->prefixlen = 64; | |
46 | memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4); | |
47 | memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4); | |
48 | } | |
718e3744 | 49 | |
508e53e2 | 50 | void |
51 | ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size) | |
718e3744 | 52 | { |
508e53e2 | 53 | u_int32_t adv_router, id; |
4846ef64 | 54 | char adv_router_str[16], id_str[16]; |
508e53e2 | 55 | memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4); |
56 | memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4); | |
57 | inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str)); | |
4846ef64 | 58 | inet_ntop (AF_INET, &id, id_str, sizeof (id_str)); |
59 | if (ntohl (id)) | |
60 | snprintf (buf, size, "%s Net-ID: %s", adv_router_str, id_str); | |
61 | else | |
62 | snprintf (buf, size, "%s", adv_router_str); | |
508e53e2 | 63 | } |
718e3744 | 64 | |
508e53e2 | 65 | /* Global strings for logging */ |
0c083ee9 | 66 | const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = |
4846ef64 | 67 | { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", }; |
718e3744 | 68 | |
0c083ee9 | 69 | const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = |
4846ef64 | 70 | { "?", "R", "N", "D", "L", "A", }; |
718e3744 | 71 | |
0c083ee9 | 72 | const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = |
508e53e2 | 73 | { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", }; |
718e3744 | 74 | |
0c083ee9 | 75 | const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = |
4846ef64 | 76 | { "??", "IA", "IE", "E1", "E2", }; |
718e3744 | 77 | |
718e3744 | 78 | |
508e53e2 | 79 | struct ospf6_route * |
80 | ospf6_route_create () | |
718e3744 | 81 | { |
508e53e2 | 82 | struct ospf6_route *route; |
83 | route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route)); | |
84 | return route; | |
85 | } | |
718e3744 | 86 | |
508e53e2 | 87 | void |
88 | ospf6_route_delete (struct ospf6_route *route) | |
89 | { | |
90 | XFREE (MTYPE_OSPF6_ROUTE, route); | |
718e3744 | 91 | } |
92 | ||
508e53e2 | 93 | struct ospf6_route * |
94 | ospf6_route_copy (struct ospf6_route *route) | |
718e3744 | 95 | { |
508e53e2 | 96 | struct ospf6_route *new; |
97 | ||
98 | new = ospf6_route_create (); | |
99 | memcpy (new, route, sizeof (struct ospf6_route)); | |
100 | new->rnode = NULL; | |
101 | new->prev = NULL; | |
102 | new->next = NULL; | |
103 | new->lock = 0; | |
104 | return new; | |
105 | } | |
718e3744 | 106 | |
508e53e2 | 107 | void |
108 | ospf6_route_lock (struct ospf6_route *route) | |
109 | { | |
110 | route->lock++; | |
111 | } | |
718e3744 | 112 | |
508e53e2 | 113 | void |
114 | ospf6_route_unlock (struct ospf6_route *route) | |
115 | { | |
116 | assert (route->lock > 0); | |
117 | route->lock--; | |
118 | if (route->lock == 0) | |
119 | ospf6_route_delete (route); | |
120 | } | |
718e3744 | 121 | |
508e53e2 | 122 | /* Route compare function. If ra is more preferred, it returns |
123 | less than 0. If rb is more preferred returns greater than 0. | |
124 | Otherwise (neither one is preferred), returns 0 */ | |
125 | static int | |
126 | ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) | |
127 | { | |
128 | assert (ospf6_route_is_same (ra, rb)); | |
129 | assert (OSPF6_PATH_TYPE_NONE < ra->path.type && | |
130 | ra->path.type < OSPF6_PATH_TYPE_MAX); | |
131 | assert (OSPF6_PATH_TYPE_NONE < rb->path.type && | |
132 | rb->path.type < OSPF6_PATH_TYPE_MAX); | |
718e3744 | 133 | |
508e53e2 | 134 | if (ra->type != rb->type) |
135 | return (ra->type - rb->type); | |
718e3744 | 136 | |
508e53e2 | 137 | if (ra->path.area_id != rb->path.area_id) |
138 | return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id)); | |
718e3744 | 139 | |
508e53e2 | 140 | if (ra->path.type != rb->path.type) |
141 | return (ra->path.type - rb->path.type); | |
718e3744 | 142 | |
508e53e2 | 143 | if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) |
144 | { | |
145 | if (ra->path.cost_e2 != rb->path.cost_e2) | |
146 | return (ra->path.cost_e2 - rb->path.cost_e2); | |
718e3744 | 147 | } |
508e53e2 | 148 | else |
718e3744 | 149 | { |
508e53e2 | 150 | if (ra->path.cost != rb->path.cost) |
151 | return (ra->path.cost - rb->path.cost); | |
718e3744 | 152 | } |
718e3744 | 153 | |
508e53e2 | 154 | return 0; |
718e3744 | 155 | } |
156 | ||
508e53e2 | 157 | struct ospf6_route * |
158 | ospf6_route_lookup (struct prefix *prefix, | |
718e3744 | 159 | struct ospf6_route_table *table) |
160 | { | |
161 | struct route_node *node; | |
508e53e2 | 162 | struct ospf6_route *route; |
718e3744 | 163 | |
164 | node = route_node_lookup (table->table, prefix); | |
508e53e2 | 165 | if (node == NULL) |
166 | return NULL; | |
167 | ||
168 | route = (struct ospf6_route *) node->info; | |
169 | return route; | |
170 | } | |
718e3744 | 171 | |
508e53e2 | 172 | struct ospf6_route * |
173 | ospf6_route_lookup_identical (struct ospf6_route *route, | |
174 | struct ospf6_route_table *table) | |
175 | { | |
176 | struct ospf6_route *target; | |
718e3744 | 177 | |
508e53e2 | 178 | for (target = ospf6_route_lookup (&route->prefix, table); |
179 | target; target = target->next) | |
718e3744 | 180 | { |
508e53e2 | 181 | if (ospf6_route_is_identical (target, route)) |
182 | return target; | |
718e3744 | 183 | } |
508e53e2 | 184 | return NULL; |
718e3744 | 185 | } |
186 | ||
508e53e2 | 187 | struct ospf6_route * |
188 | ospf6_route_lookup_bestmatch (struct prefix *prefix, | |
189 | struct ospf6_route_table *table) | |
718e3744 | 190 | { |
191 | struct route_node *node; | |
508e53e2 | 192 | struct ospf6_route *route; |
718e3744 | 193 | |
508e53e2 | 194 | node = route_node_match (table->table, prefix); |
195 | if (node == NULL) | |
196 | return NULL; | |
197 | route_unlock_node (node); | |
718e3744 | 198 | |
508e53e2 | 199 | route = (struct ospf6_route *) node->info; |
200 | return route; | |
718e3744 | 201 | } |
202 | ||
508e53e2 | 203 | #ifndef NDEBUG |
204 | static void | |
205 | _route_count_assert (struct ospf6_route_table *table) | |
718e3744 | 206 | { |
508e53e2 | 207 | struct ospf6_route *debug; |
ccb59b11 | 208 | char buf[64]; |
0c083ee9 | 209 | unsigned int num = 0; |
508e53e2 | 210 | for (debug = ospf6_route_head (table); debug; |
211 | debug = ospf6_route_next (debug)) | |
212 | num++; | |
ccb59b11 | 213 | |
214 | if (num == table->count) | |
215 | return; | |
216 | ||
c6487d61 | 217 | zlog_debug ("PANIC !! table[%p]->count = %d, real = %d", |
218 | table, table->count, num); | |
ccb59b11 | 219 | for (debug = ospf6_route_head (table); debug; |
220 | debug = ospf6_route_next (debug)) | |
221 | { | |
222 | prefix2str (&debug->prefix, buf, sizeof (buf)); | |
c6487d61 | 223 | zlog_debug ("%p %p %s", debug->prev, debug->next, buf); |
ccb59b11 | 224 | } |
c6487d61 | 225 | zlog_debug ("DUMP END"); |
ccb59b11 | 226 | |
508e53e2 | 227 | assert (num == table->count); |
718e3744 | 228 | } |
508e53e2 | 229 | #define ospf6_route_count_assert(t) (_route_count_assert (t)) |
230 | #else | |
231 | #define ospf6_route_count_assert(t) ((void) 0) | |
232 | #endif /*NDEBUG*/ | |
718e3744 | 233 | |
508e53e2 | 234 | struct ospf6_route * |
235 | ospf6_route_add (struct ospf6_route *route, | |
236 | struct ospf6_route_table *table) | |
718e3744 | 237 | { |
508e53e2 | 238 | struct route_node *node, *nextnode, *prevnode; |
239 | struct ospf6_route *current = NULL; | |
240 | struct ospf6_route *prev = NULL, *old = NULL, *next = NULL; | |
241 | char buf[64]; | |
242 | struct timeval now; | |
243 | ||
244 | assert (route->rnode == NULL); | |
245 | assert (route->lock == 0); | |
246 | assert (route->next == NULL); | |
247 | assert (route->prev == NULL); | |
248 | ||
249 | if (route->type == OSPF6_DEST_TYPE_LINKSTATE) | |
250 | ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); | |
251 | else | |
252 | prefix2str (&route->prefix, buf, sizeof (buf)); | |
718e3744 | 253 | |
508e53e2 | 254 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) |
c6487d61 | 255 | zlog_debug ("route add %s", buf); |
718e3744 | 256 | |
508e53e2 | 257 | gettimeofday (&now, NULL); |
718e3744 | 258 | |
508e53e2 | 259 | node = route_node_get (table->table, &route->prefix); |
260 | route->rnode = node; | |
718e3744 | 261 | |
508e53e2 | 262 | /* find place to insert */ |
263 | for (current = node->info; current; current = current->next) | |
718e3744 | 264 | { |
508e53e2 | 265 | if (! ospf6_route_is_same (current, route)) |
266 | next = current; | |
267 | else if (current->type != route->type) | |
268 | prev = current; | |
269 | else if (ospf6_route_is_same_origin (current, route)) | |
270 | old = current; | |
271 | else if (ospf6_route_cmp (current, route) > 0) | |
272 | next = current; | |
273 | else | |
274 | prev = current; | |
718e3744 | 275 | |
508e53e2 | 276 | if (old || next) |
277 | break; | |
718e3744 | 278 | } |
508e53e2 | 279 | |
280 | if (old) | |
718e3744 | 281 | { |
508e53e2 | 282 | /* if route does not actually change, return unchanged */ |
283 | if (ospf6_route_is_identical (old, route)) | |
284 | { | |
285 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) | |
c6487d61 | 286 | zlog_debug (" identical route found, ignore"); |
718e3744 | 287 | |
508e53e2 | 288 | ospf6_route_delete (route); |
289 | SET_FLAG (old->flag, OSPF6_ROUTE_ADD); | |
290 | ospf6_route_count_assert (table); | |
9428f2dc | 291 | |
508e53e2 | 292 | return old; |
293 | } | |
718e3744 | 294 | |
508e53e2 | 295 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) |
c6487d61 | 296 | zlog_debug (" old route found, replace"); |
718e3744 | 297 | |
508e53e2 | 298 | /* replace old one if exists */ |
299 | if (node->info == old) | |
300 | { | |
301 | node->info = route; | |
302 | SET_FLAG (route->flag, OSPF6_ROUTE_BEST); | |
303 | } | |
718e3744 | 304 | |
508e53e2 | 305 | if (old->prev) |
306 | old->prev->next = route; | |
307 | route->prev = old->prev; | |
308 | if (old->next) | |
309 | old->next->prev = route; | |
310 | route->next = old->next; | |
718e3744 | 311 | |
508e53e2 | 312 | route->installed = old->installed; |
313 | route->changed = now; | |
718e3744 | 314 | |
508e53e2 | 315 | ospf6_route_unlock (old); /* will be deleted later */ |
316 | ospf6_route_lock (route); | |
718e3744 | 317 | |
508e53e2 | 318 | SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE); |
9428f2dc | 319 | ospf6_route_count_assert (table); |
320 | ||
508e53e2 | 321 | if (table->hook_add) |
322 | (*table->hook_add) (route); | |
718e3744 | 323 | |
508e53e2 | 324 | return route; |
325 | } | |
718e3744 | 326 | |
508e53e2 | 327 | /* insert if previous or next node found */ |
328 | if (prev || next) | |
329 | { | |
330 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) | |
c6487d61 | 331 | zlog_debug (" another path found, insert"); |
508e53e2 | 332 | |
333 | if (prev == NULL) | |
334 | prev = next->prev; | |
335 | if (next == NULL) | |
336 | next = prev->next; | |
337 | ||
338 | if (prev) | |
339 | prev->next = route; | |
340 | route->prev = prev; | |
341 | if (next) | |
342 | next->prev = route; | |
343 | route->next = next; | |
344 | ||
345 | if (node->info == next) | |
346 | { | |
347 | assert (next->rnode == node); | |
348 | node->info = route; | |
349 | UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST); | |
350 | SET_FLAG (route->flag, OSPF6_ROUTE_BEST); | |
351 | } | |
718e3744 | 352 | |
508e53e2 | 353 | route->installed = now; |
354 | route->changed = now; | |
718e3744 | 355 | |
508e53e2 | 356 | ospf6_route_lock (route); |
357 | table->count++; | |
9428f2dc | 358 | ospf6_route_count_assert (table); |
508e53e2 | 359 | |
360 | SET_FLAG (route->flag, OSPF6_ROUTE_ADD); | |
361 | if (table->hook_add) | |
362 | (*table->hook_add) (route); | |
718e3744 | 363 | |
508e53e2 | 364 | return route; |
718e3744 | 365 | } |
366 | ||
508e53e2 | 367 | /* Else, this is the brand new route regarding to the prefix */ |
368 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) | |
c6487d61 | 369 | zlog_debug (" brand new route, add"); |
508e53e2 | 370 | |
371 | assert (node->info == NULL); | |
372 | node->info = route; | |
373 | SET_FLAG (route->flag, OSPF6_ROUTE_BEST); | |
374 | ospf6_route_lock (route); | |
375 | route->installed = now; | |
376 | route->changed = now; | |
377 | ||
378 | /* lookup real existing next route */ | |
379 | nextnode = node; | |
380 | route_lock_node (nextnode); | |
381 | do { | |
382 | nextnode = route_next (nextnode); | |
383 | } while (nextnode && nextnode->info == NULL); | |
384 | ||
385 | /* set next link */ | |
386 | if (nextnode == NULL) | |
387 | route->next = NULL; | |
388 | else | |
718e3744 | 389 | { |
508e53e2 | 390 | route_unlock_node (nextnode); |
391 | ||
392 | next = nextnode->info; | |
393 | route->next = next; | |
394 | next->prev = route; | |
718e3744 | 395 | } |
718e3744 | 396 | |
508e53e2 | 397 | /* lookup real existing prev route */ |
398 | prevnode = node; | |
399 | route_lock_node (prevnode); | |
400 | do { | |
401 | prevnode = route_prev (prevnode); | |
402 | } while (prevnode && prevnode->info == NULL); | |
718e3744 | 403 | |
508e53e2 | 404 | /* set prev link */ |
405 | if (prevnode == NULL) | |
406 | route->prev = NULL; | |
407 | else | |
718e3744 | 408 | { |
508e53e2 | 409 | route_unlock_node (prevnode); |
718e3744 | 410 | |
508e53e2 | 411 | prev = prevnode->info; |
412 | while (prev->next && ospf6_route_is_same (prev, prev->next)) | |
413 | prev = prev->next; | |
414 | route->prev = prev; | |
415 | prev->next = route; | |
718e3744 | 416 | } |
508e53e2 | 417 | |
418 | table->count++; | |
9428f2dc | 419 | ospf6_route_count_assert (table); |
508e53e2 | 420 | |
421 | SET_FLAG (route->flag, OSPF6_ROUTE_ADD); | |
422 | if (table->hook_add) | |
423 | (*table->hook_add) (route); | |
424 | ||
508e53e2 | 425 | return route; |
718e3744 | 426 | } |
427 | ||
428 | void | |
508e53e2 | 429 | ospf6_route_remove (struct ospf6_route *route, |
430 | struct ospf6_route_table *table) | |
718e3744 | 431 | { |
508e53e2 | 432 | struct route_node *node; |
433 | struct ospf6_route *current; | |
434 | char buf[64]; | |
718e3744 | 435 | |
508e53e2 | 436 | if (route->type == OSPF6_DEST_TYPE_LINKSTATE) |
437 | ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); | |
438 | else | |
439 | prefix2str (&route->prefix, buf, sizeof (buf)); | |
718e3744 | 440 | |
508e53e2 | 441 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) |
c6487d61 | 442 | zlog_debug ("route remove: %s", buf); |
718e3744 | 443 | |
508e53e2 | 444 | node = route_node_lookup (table->table, &route->prefix); |
445 | assert (node); | |
718e3744 | 446 | |
508e53e2 | 447 | /* find the route to remove, making sure that the route pointer |
448 | is from the route table. */ | |
449 | current = node->info; | |
450 | while (current && ospf6_route_is_same (current, route)) | |
718e3744 | 451 | { |
508e53e2 | 452 | if (current == route) |
453 | break; | |
454 | current = current->next; | |
718e3744 | 455 | } |
508e53e2 | 456 | assert (current == route); |
718e3744 | 457 | |
508e53e2 | 458 | /* adjust doubly linked list */ |
459 | if (route->prev) | |
460 | route->prev->next = route->next; | |
461 | if (route->next) | |
462 | route->next->prev = route->prev; | |
718e3744 | 463 | |
508e53e2 | 464 | if (node->info == route) |
718e3744 | 465 | { |
508e53e2 | 466 | if (route->next && ospf6_route_is_same (route->next, route)) |
718e3744 | 467 | { |
508e53e2 | 468 | node->info = route->next; |
469 | SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); | |
718e3744 | 470 | } |
508e53e2 | 471 | else |
472 | node->info = NULL; /* should unlock route_node here ? */ | |
718e3744 | 473 | } |
474 | ||
9428f2dc | 475 | table->count--; |
476 | ospf6_route_count_assert (table); | |
477 | ||
478 | SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED); | |
479 | ||
508e53e2 | 480 | if (table->hook_remove) |
481 | (*table->hook_remove) (route); | |
718e3744 | 482 | |
508e53e2 | 483 | ospf6_route_unlock (route); |
508e53e2 | 484 | } |
718e3744 | 485 | |
508e53e2 | 486 | struct ospf6_route * |
487 | ospf6_route_head (struct ospf6_route_table *table) | |
488 | { | |
489 | struct route_node *node; | |
490 | struct ospf6_route *route; | |
718e3744 | 491 | |
508e53e2 | 492 | node = route_top (table->table); |
493 | if (node == NULL) | |
494 | return NULL; | |
495 | ||
496 | /* skip to the real existing entry */ | |
497 | while (node && node->info == NULL) | |
498 | node = route_next (node); | |
499 | if (node == NULL) | |
500 | return NULL; | |
718e3744 | 501 | |
508e53e2 | 502 | route_unlock_node (node); |
503 | assert (node->info); | |
504 | ||
505 | route = (struct ospf6_route *) node->info; | |
506 | assert (route->prev == NULL); | |
507 | ospf6_route_lock (route); | |
508 | return route; | |
718e3744 | 509 | } |
510 | ||
508e53e2 | 511 | struct ospf6_route * |
512 | ospf6_route_next (struct ospf6_route *route) | |
718e3744 | 513 | { |
508e53e2 | 514 | struct ospf6_route *next = route->next; |
718e3744 | 515 | |
508e53e2 | 516 | ospf6_route_unlock (route); |
517 | if (next) | |
518 | ospf6_route_lock (next); | |
718e3744 | 519 | |
508e53e2 | 520 | return next; |
521 | } | |
718e3744 | 522 | |
508e53e2 | 523 | struct ospf6_route * |
524 | ospf6_route_best_next (struct ospf6_route *route) | |
525 | { | |
526 | struct route_node *rnode; | |
527 | struct ospf6_route *next; | |
528 | ||
529 | rnode = route->rnode; | |
530 | route_lock_node (rnode); | |
531 | rnode = route_next (rnode); | |
532 | while (rnode && rnode->info == NULL) | |
533 | rnode = route_next (rnode); | |
534 | if (rnode == NULL) | |
535 | return NULL; | |
536 | route_unlock_node (rnode); | |
537 | ||
538 | assert (rnode->info); | |
539 | next = (struct ospf6_route *) rnode->info; | |
540 | ospf6_route_unlock (route); | |
541 | ospf6_route_lock (next); | |
542 | return next; | |
543 | } | |
718e3744 | 544 | |
508e53e2 | 545 | /* Macro version of check_bit (). */ |
546 | #define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1) | |
718e3744 | 547 | |
508e53e2 | 548 | struct ospf6_route * |
549 | ospf6_route_match_head (struct prefix *prefix, | |
550 | struct ospf6_route_table *table) | |
551 | { | |
552 | struct route_node *node; | |
553 | struct ospf6_route *route; | |
718e3744 | 554 | |
508e53e2 | 555 | /* Walk down tree. */ |
556 | node = table->table->top; | |
557 | while (node && node->p.prefixlen < prefix->prefixlen && | |
558 | prefix_match (&node->p, prefix)) | |
559 | node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)]; | |
718e3744 | 560 | |
508e53e2 | 561 | if (node) |
562 | route_lock_node (node); | |
563 | while (node && node->info == NULL) | |
564 | node = route_next (node); | |
565 | if (node == NULL) | |
566 | return NULL; | |
567 | route_unlock_node (node); | |
718e3744 | 568 | |
508e53e2 | 569 | if (! prefix_match (prefix, &node->p)) |
570 | return NULL; | |
718e3744 | 571 | |
508e53e2 | 572 | route = node->info; |
573 | ospf6_route_lock (route); | |
574 | return route; | |
575 | } | |
718e3744 | 576 | |
508e53e2 | 577 | struct ospf6_route * |
578 | ospf6_route_match_next (struct prefix *prefix, | |
579 | struct ospf6_route *route) | |
580 | { | |
581 | struct ospf6_route *next; | |
582 | ||
583 | next = ospf6_route_next (route); | |
584 | if (next && ! prefix_match (prefix, &next->prefix)) | |
585 | { | |
586 | ospf6_route_unlock (next); | |
587 | next = NULL; | |
588 | } | |
589 | ||
590 | return next; | |
718e3744 | 591 | } |
592 | ||
593 | void | |
594 | ospf6_route_remove_all (struct ospf6_route_table *table) | |
595 | { | |
508e53e2 | 596 | struct ospf6_route *route; |
597 | for (route = ospf6_route_head (table); route; | |
598 | route = ospf6_route_next (route)) | |
599 | ospf6_route_remove (route, table); | |
718e3744 | 600 | } |
601 | ||
718e3744 | 602 | struct ospf6_route_table * |
508e53e2 | 603 | ospf6_route_table_create () |
718e3744 | 604 | { |
718e3744 | 605 | struct ospf6_route_table *new; |
718e3744 | 606 | new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table)); |
718e3744 | 607 | new->table = route_table_init (); |
718e3744 | 608 | return new; |
609 | } | |
610 | ||
611 | void | |
612 | ospf6_route_table_delete (struct ospf6_route_table *table) | |
613 | { | |
718e3744 | 614 | ospf6_route_remove_all (table); |
615 | route_table_finish (table->table); | |
718e3744 | 616 | XFREE (MTYPE_OSPF6_ROUTE, table); |
617 | } | |
618 | ||
718e3744 | 619 | |
508e53e2 | 620 | \f |
621 | /* VTY commands */ | |
718e3744 | 622 | void |
508e53e2 | 623 | ospf6_route_show (struct vty *vty, struct ospf6_route *route) |
718e3744 | 624 | { |
508e53e2 | 625 | int i; |
626 | char destination[64], nexthop[64]; | |
627 | char duration[16], ifname[IFNAMSIZ]; | |
628 | struct timeval now, res; | |
718e3744 | 629 | |
508e53e2 | 630 | gettimeofday (&now, (struct timezone *) NULL); |
631 | timersub (&now, &route->changed, &res); | |
632 | timerstring (&res, duration, sizeof (duration)); | |
718e3744 | 633 | |
508e53e2 | 634 | /* destination */ |
635 | if (route->type == OSPF6_DEST_TYPE_LINKSTATE) | |
636 | ospf6_linkstate_prefix2str (&route->prefix, destination, | |
637 | sizeof (destination)); | |
638 | else if (route->type == OSPF6_DEST_TYPE_ROUTER) | |
639 | inet_ntop (route->prefix.family, &route->prefix.u.prefix, | |
640 | destination, sizeof (destination)); | |
641 | else | |
642 | prefix2str (&route->prefix, destination, sizeof (destination)); | |
643 | ||
644 | /* nexthop */ | |
645 | inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, | |
646 | sizeof (nexthop)); | |
647 | if (! if_indextoname (route->nexthop[0].ifindex, ifname)) | |
648 | snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex); | |
649 | ||
650 | vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s", | |
651 | (ospf6_route_is_best (route) ? '*' : ' '), | |
652 | OSPF6_DEST_TYPE_SUBSTR (route->type), | |
653 | OSPF6_PATH_TYPE_SUBSTR (route->path.type), | |
049207c3 | 654 | destination, nexthop, ifname, duration, VNL); |
508e53e2 | 655 | |
656 | for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && | |
657 | i < OSPF6_MULTI_PATH_LIMIT; i++) | |
718e3744 | 658 | { |
508e53e2 | 659 | /* nexthop */ |
660 | inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, | |
661 | sizeof (nexthop)); | |
662 | if (! if_indextoname (route->nexthop[i].ifindex, ifname)) | |
663 | snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); | |
664 | ||
665 | vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s", | |
049207c3 | 666 | ' ', "", "", "", nexthop, ifname, "", VNL); |
718e3744 | 667 | } |
668 | } | |
669 | ||
718e3744 | 670 | void |
508e53e2 | 671 | ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) |
718e3744 | 672 | { |
508e53e2 | 673 | char destination[64], nexthop[64], ifname[IFNAMSIZ]; |
674 | char area_id[16], id[16], adv_router[16], capa[16], options[16]; | |
718e3744 | 675 | struct timeval now, res; |
676 | char duration[16]; | |
508e53e2 | 677 | int i; |
718e3744 | 678 | |
679 | gettimeofday (&now, (struct timezone *) NULL); | |
680 | ||
681 | /* destination */ | |
508e53e2 | 682 | if (route->type == OSPF6_DEST_TYPE_LINKSTATE) |
683 | ospf6_linkstate_prefix2str (&route->prefix, destination, | |
684 | sizeof (destination)); | |
685 | else if (route->type == OSPF6_DEST_TYPE_ROUTER) | |
686 | inet_ntop (route->prefix.family, &route->prefix.u.prefix, | |
687 | destination, sizeof (destination)); | |
718e3744 | 688 | else |
508e53e2 | 689 | prefix2str (&route->prefix, destination, sizeof (destination)); |
049207c3 | 690 | vty_out (vty, "Destination: %s%s", destination, VNL); |
508e53e2 | 691 | |
692 | /* destination type */ | |
693 | vty_out (vty, "Destination type: %s%s", | |
694 | OSPF6_DEST_TYPE_NAME (route->type), | |
049207c3 | 695 | VNL); |
508e53e2 | 696 | |
697 | /* Time */ | |
698 | timersub (&now, &route->installed, &res); | |
699 | timerstring (&res, duration, sizeof (duration)); | |
049207c3 | 700 | vty_out (vty, "Installed Time: %s ago%s", duration, VNL); |
508e53e2 | 701 | |
702 | timersub (&now, &route->changed, &res); | |
703 | timerstring (&res, duration, sizeof (duration)); | |
049207c3 | 704 | vty_out (vty, " Changed Time: %s ago%s", duration, VNL); |
508e53e2 | 705 | |
706 | /* Debugging info */ | |
707 | vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock, | |
708 | (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"), | |
709 | (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"), | |
710 | (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"), | |
711 | (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"), | |
049207c3 | 712 | VNL); |
508e53e2 | 713 | vty_out (vty, "Memory: prev: %p this: %p next: %p%s", |
049207c3 | 714 | route->prev, route, route->next, VNL); |
508e53e2 | 715 | |
716 | /* Path section */ | |
717 | ||
718 | /* Area-ID */ | |
719 | inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id)); | |
049207c3 | 720 | vty_out (vty, "Associated Area: %s%s", area_id, VNL); |
508e53e2 | 721 | |
722 | /* Path type */ | |
723 | vty_out (vty, "Path Type: %s%s", | |
049207c3 | 724 | OSPF6_PATH_TYPE_NAME (route->path.type), VNL); |
508e53e2 | 725 | |
726 | /* LS Origin */ | |
727 | inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id)); | |
728 | inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router, | |
729 | sizeof (adv_router)); | |
730 | vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s", | |
1e05838a | 731 | ospf6_lstype_name (route->path.origin.type), |
049207c3 | 732 | id, adv_router, VNL); |
508e53e2 | 733 | |
734 | /* Options */ | |
735 | ospf6_options_printbuf (route->path.options, options, sizeof (options)); | |
049207c3 | 736 | vty_out (vty, "Options: %s%s", options, VNL); |
508e53e2 | 737 | |
738 | /* Router Bits */ | |
739 | ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa)); | |
049207c3 | 740 | vty_out (vty, "Router Bits: %s%s", capa, VNL); |
508e53e2 | 741 | |
742 | /* Prefix Options */ | |
049207c3 | 743 | vty_out (vty, "Prefix Options: xxx%s", VNL); |
508e53e2 | 744 | |
745 | /* Metrics */ | |
746 | vty_out (vty, "Metric Type: %d%s", route->path.metric_type, | |
049207c3 | 747 | VNL); |
508e53e2 | 748 | vty_out (vty, "Metric: %d (%d)%s", |
049207c3 | 749 | route->path.cost, route->path.cost_e2, VNL); |
508e53e2 | 750 | |
751 | /* Nexthops */ | |
049207c3 | 752 | vty_out (vty, "Nexthop:%s", VNL); |
508e53e2 | 753 | for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && |
754 | i < OSPF6_MULTI_PATH_LIMIT; i++) | |
755 | { | |
756 | /* nexthop */ | |
757 | inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, | |
758 | sizeof (nexthop)); | |
759 | if (! if_indextoname (route->nexthop[i].ifindex, ifname)) | |
760 | snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); | |
049207c3 | 761 | vty_out (vty, " %s %s%s", nexthop, ifname, VNL); |
508e53e2 | 762 | } |
049207c3 | 763 | vty_out (vty, "%s", VNL); |
508e53e2 | 764 | } |
718e3744 | 765 | |
508e53e2 | 766 | void |
767 | ospf6_route_show_table_summary (struct vty *vty, | |
768 | struct ospf6_route_table *table) | |
769 | { | |
770 | struct ospf6_route *route, *prev = NULL; | |
771 | int i, pathtype[OSPF6_PATH_TYPE_MAX]; | |
0c083ee9 | 772 | unsigned int number = 0; |
508e53e2 | 773 | int nhinval = 0, ecmp = 0; |
4846ef64 | 774 | int alternative = 0, destination = 0; |
508e53e2 | 775 | |
776 | for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++) | |
777 | pathtype[i] = 0; | |
778 | ||
779 | for (route = ospf6_route_head (table); route; | |
780 | route = ospf6_route_next (route)) | |
718e3744 | 781 | { |
508e53e2 | 782 | if (prev == NULL || ! ospf6_route_is_same (prev, route)) |
783 | destination++; | |
784 | else | |
4846ef64 | 785 | alternative++; |
508e53e2 | 786 | if (! ospf6_nexthop_is_set (&route->nexthop[0])) |
787 | nhinval++; | |
788 | else if (ospf6_nexthop_is_set (&route->nexthop[1])) | |
789 | ecmp++; | |
4846ef64 | 790 | pathtype[route->path.type]++; |
508e53e2 | 791 | number++; |
4846ef64 | 792 | |
508e53e2 | 793 | prev = route; |
794 | } | |
718e3744 | 795 | |
508e53e2 | 796 | assert (number == table->count); |
508e53e2 | 797 | |
4846ef64 | 798 | vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL); |
799 | vty_out (vty, "Number of Destination: %d%s", destination, VNL); | |
800 | vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL); | |
801 | vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL); | |
802 | for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) | |
803 | { | |
804 | vty_out (vty, "Number of %s routes: %d%s", | |
805 | OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL); | |
806 | } | |
807 | } | |
808 | ||
809 | void | |
810 | ospf6_route_show_table_prefix (struct vty *vty, | |
811 | struct prefix *prefix, | |
812 | struct ospf6_route_table *table) | |
813 | { | |
814 | struct ospf6_route *route; | |
815 | ||
816 | route = ospf6_route_lookup (prefix, table); | |
817 | if (route == NULL) | |
818 | return; | |
819 | ||
820 | ospf6_route_lock (route); | |
821 | while (route && ospf6_route_is_prefix (prefix, route)) | |
822 | { | |
823 | /* Specifying a prefix will always display details */ | |
824 | ospf6_route_show_detail (vty, route); | |
825 | route = ospf6_route_next (route); | |
826 | } | |
827 | if (route) | |
828 | ospf6_route_unlock (route); | |
829 | } | |
830 | ||
831 | void | |
832 | ospf6_route_show_table_address (struct vty *vty, | |
833 | struct prefix *prefix, | |
834 | struct ospf6_route_table *table) | |
835 | { | |
836 | struct ospf6_route *route; | |
837 | ||
838 | route = ospf6_route_lookup_bestmatch (prefix, table); | |
839 | if (route == NULL) | |
840 | return; | |
841 | ||
842 | prefix = &route->prefix; | |
843 | ospf6_route_lock (route); | |
844 | while (route && ospf6_route_is_prefix (prefix, route)) | |
845 | { | |
846 | /* Specifying a prefix will always display details */ | |
847 | ospf6_route_show_detail (vty, route); | |
848 | route = ospf6_route_next (route); | |
849 | } | |
850 | if (route) | |
851 | ospf6_route_unlock (route); | |
852 | } | |
853 | ||
854 | void | |
855 | ospf6_route_show_table_match (struct vty *vty, int detail, | |
856 | struct prefix *prefix, | |
857 | struct ospf6_route_table *table) | |
858 | { | |
859 | struct ospf6_route *route; | |
860 | assert (prefix->family); | |
861 | ||
862 | route = ospf6_route_match_head (prefix, table); | |
863 | while (route) | |
864 | { | |
865 | if (detail) | |
866 | ospf6_route_show_detail (vty, route); | |
867 | else | |
868 | ospf6_route_show (vty, route); | |
869 | route = ospf6_route_match_next (prefix, route); | |
870 | } | |
871 | } | |
872 | ||
873 | void | |
874 | ospf6_route_show_table_type (struct vty *vty, int detail, u_char type, | |
875 | struct ospf6_route_table *table) | |
876 | { | |
877 | struct ospf6_route *route; | |
878 | ||
879 | route = ospf6_route_head (table); | |
880 | while (route) | |
881 | { | |
882 | if (route->path.type == type) | |
883 | { | |
884 | if (detail) | |
885 | ospf6_route_show_detail (vty, route); | |
886 | else | |
887 | ospf6_route_show (vty, route); | |
888 | } | |
889 | route = ospf6_route_next (route); | |
890 | } | |
891 | } | |
892 | ||
893 | void | |
894 | ospf6_route_show_table (struct vty *vty, int detail, | |
895 | struct ospf6_route_table *table) | |
896 | { | |
897 | struct ospf6_route *route; | |
898 | ||
899 | route = ospf6_route_head (table); | |
900 | while (route) | |
508e53e2 | 901 | { |
4846ef64 | 902 | if (detail) |
903 | ospf6_route_show_detail (vty, route); | |
904 | else | |
905 | ospf6_route_show (vty, route); | |
906 | route = ospf6_route_next (route); | |
718e3744 | 907 | } |
908 | } | |
909 | ||
508e53e2 | 910 | int |
0c083ee9 | 911 | ospf6_route_table_show (struct vty *vty, int argc, const char *argv[], |
508e53e2 | 912 | struct ospf6_route_table *table) |
718e3744 | 913 | { |
4846ef64 | 914 | int summary = 0; |
915 | int match = 0; | |
916 | int detail = 0; | |
917 | int slash = 0; | |
918 | int isprefix = 0; | |
508e53e2 | 919 | int i, ret; |
4846ef64 | 920 | struct prefix prefix; |
921 | u_char type = 0; | |
718e3744 | 922 | |
508e53e2 | 923 | memset (&prefix, 0, sizeof (struct prefix)); |
718e3744 | 924 | |
508e53e2 | 925 | for (i = 0; i < argc; i++) |
926 | { | |
508e53e2 | 927 | if (! strcmp (argv[i], "summary")) |
928 | { | |
4846ef64 | 929 | summary++; |
508e53e2 | 930 | continue; |
931 | } | |
718e3744 | 932 | |
4846ef64 | 933 | if (! strcmp (argv[i], "intra-area")) |
508e53e2 | 934 | { |
4846ef64 | 935 | type = OSPF6_PATH_TYPE_INTRA; |
508e53e2 | 936 | continue; |
937 | } | |
938 | ||
4846ef64 | 939 | if (! strcmp (argv[i], "inter-area")) |
508e53e2 | 940 | { |
4846ef64 | 941 | type = OSPF6_PATH_TYPE_INTER; |
508e53e2 | 942 | continue; |
943 | } | |
718e3744 | 944 | |
4846ef64 | 945 | if (! strcmp (argv[i], "external-1")) |
508e53e2 | 946 | { |
4846ef64 | 947 | type = OSPF6_PATH_TYPE_EXTERNAL1; |
948 | continue; | |
949 | } | |
950 | ||
951 | if (! strcmp (argv[i], "external-2")) | |
952 | { | |
953 | type = OSPF6_PATH_TYPE_EXTERNAL2; | |
954 | continue; | |
955 | } | |
956 | ||
957 | if (! strcmp (argv[i], "detail")) | |
958 | { | |
959 | detail++; | |
960 | continue; | |
961 | } | |
962 | ||
963 | if (! strcmp (argv[i], "match")) | |
964 | { | |
965 | match++; | |
966 | continue; | |
508e53e2 | 967 | } |
718e3744 | 968 | |
508e53e2 | 969 | ret = str2prefix (argv[i], &prefix); |
4846ef64 | 970 | if (ret == 1 && prefix.family == AF_INET6) |
718e3744 | 971 | { |
4846ef64 | 972 | isprefix++; |
973 | if (strchr (argv[i], '/')) | |
974 | slash++; | |
975 | continue; | |
508e53e2 | 976 | } |
718e3744 | 977 | |
4846ef64 | 978 | vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); |
979 | return CMD_SUCCESS; | |
508e53e2 | 980 | } |
718e3744 | 981 | |
508e53e2 | 982 | /* Give summary of this route table */ |
4846ef64 | 983 | if (summary) |
508e53e2 | 984 | { |
985 | ospf6_route_show_table_summary (vty, table); | |
986 | return CMD_SUCCESS; | |
987 | } | |
718e3744 | 988 | |
508e53e2 | 989 | /* Give exact prefix-match route */ |
4846ef64 | 990 | if (isprefix && ! match) |
508e53e2 | 991 | { |
992 | /* If exact address, give best matching route */ | |
4846ef64 | 993 | if (! slash) |
994 | ospf6_route_show_table_address (vty, &prefix, table); | |
508e53e2 | 995 | else |
4846ef64 | 996 | ospf6_route_show_table_prefix (vty, &prefix, table); |
508e53e2 | 997 | |
4846ef64 | 998 | return CMD_SUCCESS; |
999 | } | |
508e53e2 | 1000 | |
4846ef64 | 1001 | if (match) |
1002 | ospf6_route_show_table_match (vty, detail, &prefix, table); | |
1003 | else if (type) | |
1004 | ospf6_route_show_table_type (vty, detail, type, table); | |
1005 | else | |
1006 | ospf6_route_show_table (vty, detail, table); | |
508e53e2 | 1007 | |
4846ef64 | 1008 | return CMD_SUCCESS; |
1009 | } | |
508e53e2 | 1010 | |
4846ef64 | 1011 | void |
1012 | ospf6_linkstate_show_header (struct vty *vty) | |
1013 | { | |
1014 | vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s", | |
1015 | "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL); | |
1016 | } | |
1017 | ||
1018 | void | |
1019 | ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route) | |
1020 | { | |
1021 | u_int32_t router, id; | |
1022 | char routername[16], idname[16], rbits[16], options[16]; | |
1023 | ||
1024 | router = ospf6_linkstate_prefix_adv_router (&route->prefix); | |
1025 | inet_ntop (AF_INET, &router, routername, sizeof (routername)); | |
1026 | id = ospf6_linkstate_prefix_id (&route->prefix); | |
1027 | inet_ntop (AF_INET, &id, idname, sizeof (idname)); | |
1028 | ||
1029 | ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); | |
1030 | ospf6_options_printbuf (route->path.options, options, sizeof (options)); | |
508e53e2 | 1031 | |
4846ef64 | 1032 | if (ntohl (id)) |
1033 | vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", | |
1034 | "Network", routername, idname, rbits, options, | |
1035 | (unsigned long) route->path.cost, VNL); | |
508e53e2 | 1036 | else |
4846ef64 | 1037 | vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", |
1038 | "Router", routername, idname, rbits, options, | |
1039 | (unsigned long) route->path.cost, VNL); | |
1040 | } | |
1041 | ||
1042 | ||
1043 | void | |
1044 | ospf6_linkstate_show_table_exact (struct vty *vty, | |
1045 | struct prefix *prefix, | |
1046 | struct ospf6_route_table *table) | |
1047 | { | |
1048 | struct ospf6_route *route; | |
1049 | ||
1050 | route = ospf6_route_lookup (prefix, table); | |
1051 | if (route == NULL) | |
1052 | return; | |
1053 | ||
1054 | ospf6_route_lock (route); | |
1055 | while (route && ospf6_route_is_prefix (prefix, route)) | |
1056 | { | |
1057 | /* Specifying a prefix will always display details */ | |
1058 | ospf6_route_show_detail (vty, route); | |
1059 | route = ospf6_route_next (route); | |
1060 | } | |
1061 | if (route) | |
1062 | ospf6_route_unlock (route); | |
1063 | } | |
1064 | ||
1065 | void | |
1066 | ospf6_linkstate_show_table (struct vty *vty, int detail, | |
1067 | struct ospf6_route_table *table) | |
1068 | { | |
1069 | struct ospf6_route *route; | |
1070 | ||
1071 | if (! detail) | |
1072 | ospf6_linkstate_show_header (vty); | |
508e53e2 | 1073 | |
4846ef64 | 1074 | route = ospf6_route_head (table); |
508e53e2 | 1075 | while (route) |
1076 | { | |
4846ef64 | 1077 | if (detail) |
508e53e2 | 1078 | ospf6_route_show_detail (vty, route); |
1079 | else | |
4846ef64 | 1080 | ospf6_linkstate_show (vty, route); |
1081 | route = ospf6_route_next (route); | |
508e53e2 | 1082 | } |
718e3744 | 1083 | } |
1084 | ||
1085 | int | |
0c083ee9 | 1086 | ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[], |
4846ef64 | 1087 | struct ospf6_route_table *table) |
718e3744 | 1088 | { |
4846ef64 | 1089 | int detail = 0; |
1090 | int is_id = 0; | |
1091 | int is_router = 0; | |
718e3744 | 1092 | int i, ret; |
4846ef64 | 1093 | struct prefix router, id, prefix; |
718e3744 | 1094 | |
4846ef64 | 1095 | memset (&router, 0, sizeof (struct prefix)); |
508e53e2 | 1096 | memset (&id, 0, sizeof (struct prefix)); |
4846ef64 | 1097 | memset (&prefix, 0, sizeof (struct prefix)); |
718e3744 | 1098 | |
1099 | for (i = 0; i < argc; i++) | |
1100 | { | |
1101 | if (! strcmp (argv[i], "detail")) | |
1102 | { | |
4846ef64 | 1103 | detail++; |
508e53e2 | 1104 | continue; |
718e3744 | 1105 | } |
1106 | ||
4846ef64 | 1107 | if (! is_router) |
718e3744 | 1108 | { |
4846ef64 | 1109 | ret = str2prefix (argv[i], &router); |
1110 | if (ret == 1 && router.family == AF_INET) | |
718e3744 | 1111 | { |
4846ef64 | 1112 | is_router++; |
1113 | continue; | |
718e3744 | 1114 | } |
4846ef64 | 1115 | vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); |
1116 | return CMD_SUCCESS; | |
508e53e2 | 1117 | } |
508e53e2 | 1118 | |
4846ef64 | 1119 | if (! is_id) |
1120 | { | |
508e53e2 | 1121 | ret = str2prefix (argv[i], &id); |
4846ef64 | 1122 | if (ret == 1 && id.family == AF_INET) |
718e3744 | 1123 | { |
4846ef64 | 1124 | is_id++; |
1125 | continue; | |
718e3744 | 1126 | } |
4846ef64 | 1127 | vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); |
508e53e2 | 1128 | return CMD_SUCCESS; |
1129 | } | |
1130 | ||
4846ef64 | 1131 | vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); |
508e53e2 | 1132 | return CMD_SUCCESS; |
718e3744 | 1133 | } |
1134 | ||
4846ef64 | 1135 | if (is_router) |
1136 | ospf6_linkstate_prefix (router.u.prefix4.s_addr, | |
1137 | id.u.prefix4.s_addr, &prefix); | |
718e3744 | 1138 | |
4846ef64 | 1139 | if (prefix.family) |
1140 | ospf6_linkstate_show_table_exact (vty, &prefix, table); | |
1141 | else | |
1142 | ospf6_linkstate_show_table (vty, detail, table); | |
718e3744 | 1143 | |
508e53e2 | 1144 | return CMD_SUCCESS; |
1145 | } | |
718e3744 | 1146 | |
4846ef64 | 1147 | |
6452df09 | 1148 | void |
1149 | ospf6_brouter_show_header (struct vty *vty) | |
1150 | { | |
1151 | vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", | |
1152 | "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); | |
1153 | } | |
1154 | ||
1155 | void | |
1156 | ospf6_brouter_show (struct vty *vty, struct ospf6_route *route) | |
1157 | { | |
1158 | u_int32_t adv_router; | |
1159 | char adv[16], rbits[16], options[16], area[16]; | |
1160 | ||
1161 | adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix); | |
1162 | inet_ntop (AF_INET, &adv_router, adv, sizeof (adv)); | |
1163 | ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); | |
1164 | ospf6_options_printbuf (route->path.options, options, sizeof (options)); | |
1165 | inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area)); | |
1166 | ||
1167 | /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", | |
1168 | "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */ | |
1169 | vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", | |
1170 | adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type), | |
1171 | area, VNL); | |
1172 | } | |
1173 | ||
508e53e2 | 1174 | DEFUN (debug_ospf6_route, |
1175 | debug_ospf6_route_cmd, | |
1176 | "debug ospf6 route (table|intra-area|inter-area)", | |
1177 | DEBUG_STR | |
1178 | OSPF6_STR | |
1179 | "Debug route table calculation\n" | |
1180 | "Debug detail\n" | |
1181 | "Debug intra-area route calculation\n" | |
1182 | "Debug inter-area route calculation\n" | |
1183 | ) | |
1184 | { | |
1185 | unsigned char level = 0; | |
1186 | ||
1187 | if (! strncmp (argv[0], "table", 5)) | |
1188 | level = OSPF6_DEBUG_ROUTE_TABLE; | |
1189 | else if (! strncmp (argv[0], "intra", 5)) | |
1190 | level = OSPF6_DEBUG_ROUTE_INTRA; | |
1191 | else if (! strncmp (argv[0], "inter", 5)) | |
1192 | level = OSPF6_DEBUG_ROUTE_INTER; | |
1193 | OSPF6_DEBUG_ROUTE_ON (level); | |
1194 | return CMD_SUCCESS; | |
1195 | } | |
1196 | ||
1197 | DEFUN (no_debug_ospf6_route, | |
1198 | no_debug_ospf6_route_cmd, | |
1199 | "no debug ospf6 route (table|intra-area|inter-area)", | |
1200 | NO_STR | |
1201 | DEBUG_STR | |
1202 | OSPF6_STR | |
1203 | "Debug route table calculation\n" | |
1204 | "Debug intra-area route calculation\n") | |
1205 | { | |
1206 | unsigned char level = 0; | |
1207 | ||
1208 | if (! strncmp (argv[0], "table", 5)) | |
1209 | level = OSPF6_DEBUG_ROUTE_TABLE; | |
1210 | else if (! strncmp (argv[0], "intra", 5)) | |
1211 | level = OSPF6_DEBUG_ROUTE_INTRA; | |
1212 | else if (! strncmp (argv[0], "inter", 5)) | |
1213 | level = OSPF6_DEBUG_ROUTE_INTER; | |
1214 | OSPF6_DEBUG_ROUTE_OFF (level); | |
718e3744 | 1215 | return CMD_SUCCESS; |
1216 | } | |
1217 | ||
508e53e2 | 1218 | int |
1219 | config_write_ospf6_debug_route (struct vty *vty) | |
1220 | { | |
1221 | if (IS_OSPF6_DEBUG_ROUTE (TABLE)) | |
049207c3 | 1222 | vty_out (vty, "debug ospf6 route table%s", VNL); |
508e53e2 | 1223 | if (IS_OSPF6_DEBUG_ROUTE (INTRA)) |
049207c3 | 1224 | vty_out (vty, "debug ospf6 route intra-area%s", VNL); |
508e53e2 | 1225 | if (IS_OSPF6_DEBUG_ROUTE (INTER)) |
049207c3 | 1226 | vty_out (vty, "debug ospf6 route inter-area%s", VNL); |
508e53e2 | 1227 | return 0; |
1228 | } | |
1229 | ||
1230 | void | |
1231 | install_element_ospf6_debug_route () | |
1232 | { | |
1233 | install_element (ENABLE_NODE, &debug_ospf6_route_cmd); | |
1234 | install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd); | |
1235 | install_element (CONFIG_NODE, &debug_ospf6_route_cmd); | |
1236 | install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd); | |
1237 | } | |
1238 | ||
1239 | ||
1240 |