]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_route.c
b3abedc3c52cc95f33d471b0cb64f3d081c230b6
[mirror_frr.git] / ospf6d / ospf6_route.c
1 /*
2 * Copyright (C) 1999 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
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
22 #include "ospf6d.h"
23
24 char *
25 dtype_name[OSPF6_DEST_TYPE_MAX] =
26 {
27 "Unknown", "Router", "Network", "Discard"
28 };
29 #define DTYPE_NAME(x) \
30 (0 < (x) && (x) < sizeof (dtype_name) ? \
31 dtype_name[(x)] : dtype_name[0])
32
33 char *
34 dtype_abname[OSPF6_DEST_TYPE_MAX] =
35 {
36 "?", "R", "N", "D"
37 };
38 #define DTYPE_ABNAME(x) \
39 (0 < (x) && (x) < sizeof (dtype_abname) ? \
40 dtype_abname[(x)] : dtype_abname[0])
41
42 char *
43 ptype_name[OSPF6_PATH_TYPE_MAX] =
44 {
45 "Unknown", "Intra", "Inter", "External-1", "External-2",
46 "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
47 "OSPF", "OSPF6", "BGP"
48 };
49 #define PTYPE_NAME(x) \
50 (0 < (x) && (x) < sizeof (ptype_name) ? \
51 ptype_name[(x)] : ptype_name[0])
52
53 char *
54 ptype_abname[OSPF6_PATH_TYPE_MAX] =
55 {
56 "??", "Ia", "Ie", "E1", "E2",
57 "-X", "-K", "-C", "-S", "-R", "-R",
58 "-O", "-O", "-B"
59 };
60 #define PTYPE_ABNAME(x) \
61 (0 < (x) && (x) < sizeof (ptype_abname) ? \
62 ptype_abname[(x)] : ptype_abname[0])
63
64 \f
65
66 int
67 ospf6_path_cmp (void *arg1, void *arg2)
68 {
69 struct ospf6_path_node *pn1 = arg1;
70 struct ospf6_path_node *pn2 = arg2;
71 struct ospf6_path *p1 = &pn1->path;
72 struct ospf6_path *p2 = &pn2->path;
73
74 if (p1->type < p2->type)
75 return -1;
76 else if (p1->type > p2->type)
77 return 1;
78
79 if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
80 {
81 if (p1->cost_e2 < p2->cost_e2)
82 return -1;
83 else if (p1->cost_e2 > p2->cost_e2)
84 return 1;
85 }
86
87 if (p1->cost < p2->cost)
88 return -1;
89 else if (p1->cost > p2->cost)
90 return 1;
91
92 /* if from the same source, recognize as identical
93 (and treat this as update) */
94 if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
95 p1->area_id == p2->area_id)
96 return 0;
97
98 /* else, always prefer left */
99 return -1;
100 }
101
102 int
103 ospf6_nexthop_cmp (void *arg1, void *arg2)
104 {
105 int i, ret = 0;
106 struct ospf6_nexthop_node *nn1 = arg1;
107 struct ospf6_nexthop_node *nn2 = arg2;
108 struct ospf6_nexthop *n1 = &nn1->nexthop;
109 struct ospf6_nexthop *n2 = &nn2->nexthop;
110
111 if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
112 return 0;
113
114 for (i = 0; i < sizeof (struct in6_addr); i++)
115 {
116 if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
117 {
118 ret = nn1->nexthop.address.s6_addr[i] -
119 nn2->nexthop.address.s6_addr[i];
120 break;
121 }
122 }
123
124 if (ret == 0)
125 ret = -1;
126
127 return ret;
128 }
129
130 static void
131 ospf6_route_request (struct ospf6_route_req *request,
132 struct ospf6_route_node *rn,
133 struct ospf6_path_node *pn,
134 struct ospf6_nexthop_node *nn)
135 {
136 assert (request);
137 assert (rn && pn && nn);
138
139 request->route_node = rn->route_node;
140
141 linklist_head (rn->path_list, &request->path_lnode);
142 while (request->path_lnode.data != pn)
143 {
144 //assert (! linklist_end (&request->path_lnode));
145 if (linklist_end (&request->path_lnode))
146 {
147 struct linklist_node node;
148
149 zlog_info ("rn: %p, pn: %p", rn, pn);
150 zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
151 pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
152 (int)pn->path.capability[1], (int)pn->path.capability[2],
153 (int)pn->path.prefix_options, pn->path.area_id,
154 pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
155
156 for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
157 linklist_next (&node))
158 {
159 struct ospf6_path_node *pn2 = node.data;
160
161 zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
162 (memcmp (&pn->path, &pn2->path,
163 sizeof (struct ospf6_path)) ?
164 "different" : "same"));
165
166 zlog_info (" origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
167 pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
168 (int)pn2->path.capability[1], (int)pn2->path.capability[2],
169 (int)pn2->path.prefix_options, pn2->path.area_id,
170 pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
171
172 if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
173 {
174 pn = pn2;
175 request->nexthop_lnode.data = pn2;
176 }
177 }
178 break;
179 }
180 linklist_next (&request->path_lnode);
181 }
182 assert (request->path_lnode.data == pn);
183
184 linklist_head (pn->nexthop_list, &request->nexthop_lnode);
185 while (request->nexthop_lnode.data != nn)
186 {
187 assert (! linklist_end (&request->nexthop_lnode));
188 linklist_next (&request->nexthop_lnode);
189 }
190 assert (request->nexthop_lnode.data == nn);
191
192 request->table = rn->table;
193 request->count = rn->count;
194 request->route_id = rn->route_id;
195 memcpy (&request->route, &rn->route, sizeof (struct ospf6_route));
196 memcpy (&request->path, &pn->path, sizeof (struct ospf6_path));
197 memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
198 }
199
200 int
201 ospf6_route_count (struct ospf6_route_req *request)
202 {
203 return request->count;
204 }
205
206 int
207 ospf6_route_lookup (struct ospf6_route_req *request,
208 struct prefix *prefix,
209 struct ospf6_route_table *table)
210 {
211 struct route_node *node;
212 struct ospf6_route_node *rn = NULL;
213 struct ospf6_path_node *pn = NULL;
214 struct ospf6_nexthop_node *nn = NULL;
215 struct linklist_node lnode;
216
217 if (request)
218 memset ((void *) request, 0, sizeof (struct ospf6_route_req));
219
220 node = route_node_lookup (table->table, prefix);
221 if (! node)
222 return 0;
223
224 rn = (struct ospf6_route_node *) node->info;
225 if (! rn)
226 return 0;
227
228 if (request)
229 {
230 linklist_head (rn->path_list, &lnode);
231 pn = lnode.data;
232 linklist_head (pn->nexthop_list, &lnode);
233 nn = lnode.data;
234
235 ospf6_route_request (request, rn, pn, nn);
236 }
237
238 return 1;
239 }
240
241 void
242 ospf6_route_head (struct ospf6_route_req *request,
243 struct ospf6_route_table *table)
244 {
245 struct route_node *node;
246 struct ospf6_route_node *rn = NULL;
247 struct ospf6_path_node *pn = NULL;
248 struct ospf6_nexthop_node *nn = NULL;
249 struct linklist_node lnode;
250
251 if (request)
252 memset (request, 0, sizeof (struct ospf6_route_req));
253
254 node = route_top (table->table);
255 if (! node)
256 return;
257
258 while (node && node->info == NULL)
259 node = route_next (node);
260 if (! node)
261 return;
262
263 rn = (struct ospf6_route_node *) node->info;
264 linklist_head (rn->path_list, &lnode);
265 pn = lnode.data;
266 linklist_head (pn->nexthop_list, &lnode);
267 nn = lnode.data;
268
269 ospf6_route_request (request, rn, pn, nn);
270 }
271
272 int
273 ospf6_route_end (struct ospf6_route_req *request)
274 {
275 if (request->route_node == NULL &&
276 linklist_end (&request->path_lnode) &&
277 linklist_end (&request->nexthop_lnode) &&
278 request->nexthop.ifindex == 0 &&
279 IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
280 return 1;
281 return 0;
282 }
283
284 void
285 ospf6_route_next (struct ospf6_route_req *request)
286 {
287 struct ospf6_route_node *route_node = NULL;
288 struct ospf6_path_node *path_node = NULL;
289 struct ospf6_nexthop_node *nexthop_node = NULL;
290
291 linklist_next (&request->nexthop_lnode);
292 if (linklist_end (&request->nexthop_lnode))
293 {
294 linklist_next (&request->path_lnode);
295 if (linklist_end (&request->path_lnode))
296 {
297 request->route_node = route_next (request->route_node);
298 while (request->route_node && request->route_node->info == NULL)
299 request->route_node = route_next (request->route_node);
300 if (request->route_node)
301 {
302 route_node = request->route_node->info;
303 if (route_node)
304 linklist_head (route_node->path_list, &request->path_lnode);
305 }
306 }
307
308 path_node = request->path_lnode.data;
309 if (path_node)
310 linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
311 }
312
313 nexthop_node = request->nexthop_lnode.data;
314
315 if (nexthop_node == NULL)
316 {
317 assert (path_node == NULL);
318 assert (route_node == NULL);
319
320 memset (&request->route, 0, sizeof (struct ospf6_route));
321 memset (&request->path, 0, sizeof (struct ospf6_path));
322 memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
323 }
324 else
325 {
326 path_node = request->path_lnode.data;
327 route_node = request->route_node->info;
328
329 assert (path_node != NULL);
330 assert (route_node != NULL);
331
332 memcpy (&request->route, &route_node->route,
333 sizeof (struct ospf6_route));
334 memcpy (&request->path, &path_node->path,
335 sizeof (struct ospf6_path));
336 memcpy (&request->nexthop, &nexthop_node->nexthop,
337 sizeof (struct ospf6_nexthop));
338 }
339 }
340
341 #define ADD 0
342 #define CHANGE 1
343 #define REMOVE 2
344
345 void
346 ospf6_route_hook_call (int type,
347 struct ospf6_route_req *request,
348 struct ospf6_route_table *table)
349 {
350 struct linklist_node node;
351 void (*func) (struct ospf6_route_req *);
352
353 for (linklist_head (table->hook_list[type], &node);
354 ! linklist_end (&node);
355 linklist_next (&node))
356 {
357 func = node.data;
358 (*func) (request);
359 }
360 }
361
362 void
363 ospf6_route_hook_register (void (*add) (struct ospf6_route_req *),
364 void (*change) (struct ospf6_route_req *),
365 void (*remove) (struct ospf6_route_req *),
366 struct ospf6_route_table *table)
367 {
368 linklist_add (add, table->hook_list[ADD]);
369 linklist_add (change, table->hook_list[CHANGE]);
370 linklist_add (remove, table->hook_list[REMOVE]);
371 }
372
373 void
374 ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *),
375 void (*change) (struct ospf6_route_req *),
376 void (*remove) (struct ospf6_route_req *),
377 struct ospf6_route_table *table)
378 {
379 linklist_remove (add, table->hook_list[ADD]);
380 linklist_remove (change, table->hook_list[CHANGE]);
381 linklist_remove (remove, table->hook_list[REMOVE]);
382 }
383
384
385 int
386 prefix_ls2str (struct prefix *p, char *str, int size)
387 {
388 char id[BUFSIZ], adv_router[BUFSIZ];
389 struct prefix_ls *pl = (struct prefix_ls *) p;
390
391 inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
392 inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
393 snprintf (str, size, "%s-%s", adv_router, id);
394 return 0;
395 }
396
397 void
398 ospf6_route_log_request (char *what, char *where,
399 struct ospf6_route_req *request)
400 {
401 char prefix[64];
402 char area_id[16];
403 char type[16], id[16], adv[16];
404 char address[64], ifname[IFNAMSIZ];
405
406 if (request->route.prefix.family != AF_INET &&
407 request->route.prefix.family != AF_INET6)
408 prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
409 else
410 prefix2str (&request->route.prefix, prefix, sizeof (prefix));
411
412 inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
413
414 ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
415 inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
416 inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
417
418 inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
419
420 zlog_info ("ROUTE: %s %s %s %s %s",
421 what, DTYPE_ABNAME (request->route.type), prefix,
422 ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
423 zlog_info ("ROUTE: Area: %s type: %s cost: %lu (E2: %lu)",
424 area_id, PTYPE_NAME (request->path.type),
425 (u_long) request->path.cost, (u_long) request->path.cost_e2);
426 zlog_info ("ROUTE: Origin: Type: %s", type);
427 zlog_info ("ROUTE: Origin: Id: %s Adv: %s", id, adv);
428 zlog_info ("ROUTE: Nexthop: %s", address);
429 zlog_info ("ROUTE: Nexthop: Ifindex: %u (%s)",
430 request->nexthop.ifindex,
431 if_indextoname (request->nexthop.ifindex, ifname));
432 }
433
434 struct ospf6_path_node *
435 ospf6_route_find_path_node (struct ospf6_route_req *request,
436 struct ospf6_route_node *rn)
437 {
438 struct linklist_node node;
439
440 for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
441 linklist_next (&node))
442 {
443 struct ospf6_path_node *path_node = node.data;
444
445 if (path_node->path.area_id == request->path.area_id &&
446 path_node->path.origin.type == request->path.origin.type &&
447 path_node->path.origin.id == request->path.origin.id &&
448 path_node->path.origin.adv_router == request->path.origin.adv_router)
449 return path_node;
450 }
451
452 #if 0
453 zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
454 request->path.area_id, request->path.origin.type,
455 request->path.origin.id, request->path.origin.adv_router);
456 for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
457 linklist_next (&node))
458 {
459 struct ospf6_path_node *path_node = node.data;
460 zlog_info (" path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
461 path_node->path.area_id, path_node->path.origin.type,
462 path_node->path.origin.id, path_node->path.origin.adv_router);
463 }
464 #endif
465
466 return NULL;
467 }
468
469 struct ospf6_nexthop_node *
470 ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
471 struct ospf6_path_node *pn)
472 {
473 struct linklist_node node;
474 for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
475 linklist_next (&node))
476 {
477 struct ospf6_nexthop_node *nexthop_node = node.data;
478
479 if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
480 sizeof (struct ospf6_nexthop)))
481 return nexthop_node;
482 }
483 return NULL;
484 }
485
486 void
487 ospf6_route_add (struct ospf6_route_req *request,
488 struct ospf6_route_table *table)
489 {
490 struct ospf6_route_node *rn;
491 struct ospf6_path_node *pn;
492 struct ospf6_nexthop_node *nn;
493 struct route_node *route_node;
494
495 struct ospf6_route_req route;
496
497 int route_change = 0;
498 int path_change = 0;
499 int nexthop_change = 0;
500
501 /* find the requested route */
502 route_node = route_node_get (table->table, &request->route.prefix);
503 rn = (struct ospf6_route_node *) route_node->info;
504
505 if (rn)
506 {
507 if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
508 {
509 memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
510 route_change++;
511 }
512 }
513 else
514 {
515 rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
516 rn->table = table;
517 rn->route_node = route_node;
518 rn->route_id = table->route_id++;
519 rn->path_list = linklist_create ();
520 rn->path_list->cmp = ospf6_path_cmp;
521 memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
522 route_node->info = rn;
523 }
524
525 /* find the same path */
526 pn = ospf6_route_find_path_node (request, rn);
527
528 if (pn)
529 {
530 if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
531 {
532 memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
533 path_change++;
534 }
535 }
536 else
537 {
538 pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
539 pn->route_node = rn;
540 pn->nexthop_list = linklist_create ();
541 pn->nexthop_list->cmp = ospf6_nexthop_cmp;
542 memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
543 linklist_add (pn, rn->path_list);
544 }
545
546 /* find the same nexthop */
547 nn = ospf6_route_find_nexthop_node (request, pn);
548
549 if (nn)
550 {
551 if (memcmp (&nn->nexthop, &request->nexthop,
552 sizeof (struct ospf6_nexthop)))
553 {
554 memcpy (&nn->nexthop, &request->nexthop,
555 sizeof (struct ospf6_nexthop));
556 nexthop_change++;
557 gettimeofday (&nn->installed, (struct timezone *) NULL);
558 }
559 }
560 else
561 {
562 nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
563 nn->path_node = pn;
564 memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
565 linklist_add (nn, pn->nexthop_list);
566 rn->count++;
567 gettimeofday (&nn->installed, (struct timezone *) NULL);
568 }
569
570 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
571 if (route_change)
572 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
573 if (path_change)
574 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
575 if (nexthop_change)
576 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
577
578 if (table->freeze)
579 return;
580
581 if (IS_OSPF6_DUMP_ROUTE)
582 {
583 ospf6_route_log_request ("Add", table->name, request);
584
585 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
586 zlog_info ("ROUTE: route attribute change");
587 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
588 zlog_info ("ROUTE: path attribute change");
589 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
590 zlog_info ("ROUTE: nexthop attribute change");
591 }
592
593 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
594 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
595 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
596
597 /* Call hooks */
598 ospf6_route_request (&route, rn, pn, nn);
599 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
600 ospf6_route_hook_call (ADD, &route, table);
601 else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
602 ospf6_route_hook_call (CHANGE, &route, table);
603
604 if (table->hook_add &&
605 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
606 (*table->hook_add) (&route);
607 else if (table->hook_change &&
608 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
609 (*table->hook_change) (&route);
610
611 /* clear flag */
612 nn->flag = 0;
613 }
614
615 void
616 ospf6_route_remove (struct ospf6_route_req *request,
617 struct ospf6_route_table *table)
618 {
619 struct ospf6_route_node *rn;
620 struct ospf6_path_node *pn;
621 struct ospf6_nexthop_node *nn;
622 struct route_node *route_node;
623 struct ospf6_route_req route;
624
625 /* find the requested route */
626 route_node = route_node_get (table->table, &request->route.prefix);
627 rn = (struct ospf6_route_node *) route_node->info;
628
629 if (! rn)
630 {
631 if (IS_OSPF6_DUMP_ROUTE)
632 {
633 ospf6_route_log_request ("Remove", table->name, request);
634 zlog_info ("ROUTE: Can't remove: No such route");
635 }
636 return;
637 }
638
639 pn = ospf6_route_find_path_node (request, rn);
640 if (! pn)
641 {
642 if (IS_OSPF6_DUMP_ROUTE)
643 {
644 ospf6_route_log_request ("Remove", table->name, request);
645 zlog_info ("ROUTE: Can't remove: No such path");
646 }
647 return;
648 }
649
650 if (pn->path.area_id != request->path.area_id ||
651 pn->path.origin.type != request->path.origin.type ||
652 pn->path.origin.id != request->path.origin.id ||
653 pn->path.origin.adv_router != request->path.origin.adv_router)
654 {
655 if (IS_OSPF6_DUMP_ROUTE)
656 {
657 ospf6_route_log_request ("Remove", table->name, request);
658 zlog_info ("ROUTE: Can't remove: Path differ");
659 {
660 char *s, *e, *c;
661 char line[512], *p;
662
663 p = line;
664 s = (char *) &pn->path;
665 e = s + sizeof (struct ospf6_path);
666 for (c = s; c < e; c++)
667 {
668 if ((c - s) % 4 == 0)
669 {
670 snprintf (p, line + sizeof (line) - p, " ");
671 p++;
672 }
673 snprintf (p, line + sizeof (line) - p, "%02x", *c);
674 p += 2;
675 }
676 zlog_info ("ROUTE: path: %s", line);
677
678 p = line;
679 s = (char *) &request->path;
680 e = s + sizeof (struct ospf6_path);
681 for (c = s; c < e; c++)
682 {
683 if ((c - s) % 4 == 0)
684 {
685 snprintf (p, line + sizeof (line) - p, " ");
686 p++;
687 }
688 snprintf (p, line + sizeof (line) - p, "%02x", *c);
689 p += 2;
690 }
691 zlog_info ("ROUTE: req : %s", line);
692
693 }
694 }
695 return;
696 }
697
698 nn = ospf6_route_find_nexthop_node (request, pn);
699 if (! nn)
700 {
701 if (IS_OSPF6_DUMP_ROUTE)
702 {
703 ospf6_route_log_request ("Remove", table->name, request);
704 zlog_info ("ROUTE: Can't remove: No such nexthop");
705 }
706 return;
707 }
708
709 if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
710 {
711 if (IS_OSPF6_DUMP_ROUTE)
712 {
713 ospf6_route_log_request ("Remove", table->name, request);
714 zlog_info ("ROUTE: Can't remove: Nexthop differ");
715 }
716 return;
717 }
718
719 SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
720
721 if (table->freeze)
722 return;
723
724 if (IS_OSPF6_DUMP_ROUTE)
725 ospf6_route_log_request ("Remove", table->name, request);
726
727 ospf6_route_request (&route, rn, pn, nn);
728 ospf6_route_hook_call (REMOVE, &route, table);
729 if (table->hook_remove)
730 (*table->hook_remove) (&route);
731
732 /* clear flag */
733 nn->flag = 0;
734
735 /* remove nexthop */
736 linklist_remove (nn, pn->nexthop_list);
737 rn->count--;
738 XFREE (MTYPE_OSPF6_ROUTE, nn);
739
740 /* remove path if there's no nexthop for the path */
741 if (pn->nexthop_list->count != 0)
742 return;
743 linklist_remove (pn, rn->path_list);
744 linklist_delete (pn->nexthop_list);
745 XFREE (MTYPE_OSPF6_ROUTE, pn);
746
747 /* remove route if there's no path for the route */
748 if (rn->path_list->count != 0)
749 return;
750 route_node->info = NULL;
751 linklist_delete (rn->path_list);
752 XFREE (MTYPE_OSPF6_ROUTE, rn);
753 }
754
755 void
756 ospf6_route_remove_all (struct ospf6_route_table *table)
757 {
758 struct ospf6_route_req request;
759
760 for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
761 ospf6_route_next (&request))
762 ospf6_route_remove (&request, table);
763 }
764
765
766 struct ospf6_route_table *
767 ospf6_route_table_create (char *name)
768 {
769 int i;
770 struct ospf6_route_table *new;
771
772 new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
773 snprintf (new->name, sizeof (new->name), "%s", name);
774
775 new->table = route_table_init ();
776 for (i = 0; i < 3; i++)
777 new->hook_list[i] = linklist_create ();
778
779 return new;
780 }
781
782 void
783 ospf6_route_table_delete (struct ospf6_route_table *table)
784 {
785 int i;
786
787 ospf6_route_remove_all (table);
788 route_table_finish (table->table);
789 for (i = 0; i < 3; i++)
790 linklist_delete (table->hook_list[i]);
791 XFREE (MTYPE_OSPF6_ROUTE, table);
792 }
793
794 void
795 ospf6_route_table_freeze (struct ospf6_route_table *route_table)
796 {
797 if (IS_OSPF6_DUMP_ROUTE)
798 zlog_info ("ROUTE: Table freeze: %s", route_table->name);
799 assert (route_table->freeze == 0);
800 route_table->freeze = 1;
801 }
802
803 void
804 ospf6_route_table_thaw (struct ospf6_route_table *route_table)
805 {
806 struct route_node *node;
807 struct linklist_node pnode;
808 struct linklist_node nnode;
809
810 struct ospf6_route_node *rn;
811 struct ospf6_path_node *pn;
812 struct ospf6_nexthop_node *nn;
813
814 struct ospf6_route_req request;
815
816 if (IS_OSPF6_DUMP_ROUTE)
817 zlog_info ("ROUTE: Table thaw: %s", route_table->name);
818
819 assert (route_table->freeze == 1);
820 route_table->freeze = 0;
821
822 for (node = route_top (route_table->table); node;
823 node = route_next (node))
824 {
825 rn = node->info;
826 if (! rn)
827 continue;
828
829 for (linklist_head (rn->path_list, &pnode);
830 ! linklist_end (&pnode);
831 linklist_next (&pnode))
832 {
833 pn = pnode.data;
834
835 for (linklist_head (pn->nexthop_list, &nnode);
836 ! linklist_end (&nnode);
837 linklist_next (&nnode))
838 {
839 nn = nnode.data;
840
841 /* if the add and remove flag set without change flag,
842 do nothing with this route */
843 if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
844 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
845 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
846 {
847 nn->flag = 0;
848 continue;
849 }
850
851 memset (&request, 0, sizeof (request));
852 memcpy (&request.route, &rn->route, sizeof (rn->route));
853 memcpy (&request.path, &pn->path, sizeof (pn->path));
854 memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
855
856 if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
857 CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
858 ospf6_route_add (&request, route_table);
859 else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
860 ospf6_route_remove (&request, route_table);
861 }
862 }
863 }
864 }
865
866 \f
867 /* VTY commands */
868
869 void
870 ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
871 {
872 struct linklist_node pnode;
873 struct linklist_node nnode;
874 struct ospf6_path_node *pn;
875 struct ospf6_nexthop_node *nn;
876
877 struct timeval now, res;
878 char duration[16];
879
880 u_int pc = 0;
881 u_int nc = 0;
882 #define HEAD (pc == 0 && nc == 0)
883
884 char prefix[64], nexthop[64], ifname[IFNAMSIZ];
885
886 gettimeofday (&now, (struct timezone *) NULL);
887
888 /* destination */
889 if (rn->route.prefix.family == AF_INET ||
890 rn->route.prefix.family == AF_INET6)
891 prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
892 else
893 prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
894
895 for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
896 linklist_next (&pnode))
897 {
898 pn = pnode.data;
899
900 for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
901 linklist_next (&nnode))
902 {
903 nn = nnode.data;
904
905 inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
906 sizeof (nexthop));
907 if (! if_indextoname (nn->nexthop.ifindex, ifname))
908 snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
909
910 ospf6_timeval_sub (&now, &nn->installed, &res);
911 ospf6_timeval_string_summary (&res, duration, sizeof (duration));
912
913 vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
914 (HEAD ? '*' : ' '),
915 DTYPE_ABNAME (rn->route.type),
916 PTYPE_ABNAME (pn->path.type),
917 prefix, nexthop, ifname, duration, VTY_NEWLINE);
918
919 nc++;
920 }
921 pc++;
922 }
923 }
924
925 void
926 ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
927 {
928 struct linklist_node pnode;
929 struct linklist_node nnode;
930 struct ospf6_path_node *pn;
931 struct ospf6_nexthop_node *nn;
932
933 u_int pc = 0;
934 u_int nc = 0;
935
936 char prefix[64], nexthop[64], ifname[IFNAMSIZ];
937 char area_id[16], type[16], id[16], adv[16];
938 char capa[64];
939
940 /* destination */
941 if (rn->route.prefix.family == AF_INET ||
942 rn->route.prefix.family == AF_INET6)
943 prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
944 else
945 prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
946
947 vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
948 vty_out (vty, " Destination Type: %s%s",
949 DTYPE_NAME (rn->route.type), VTY_NEWLINE);
950
951 for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
952 linklist_next (&pnode))
953 {
954 pn = pnode.data;
955
956 inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
957 ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
958 inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
959 inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
960 ospf6_options_string (pn->path.capability, capa, sizeof (capa));
961
962 vty_out (vty, " Path:%s", VTY_NEWLINE);
963 vty_out (vty, " Associated Area: %s%s", area_id, VTY_NEWLINE);
964 vty_out (vty, " LS Origin: %s ID: %s Adv: %s%s",
965 type, id, adv, VTY_NEWLINE);
966 vty_out (vty, " Path Type: %s%s",
967 PTYPE_NAME (pn->path.type), VTY_NEWLINE);
968 vty_out (vty, " Metric Type: %d%s",
969 pn->path.metric_type, VTY_NEWLINE);
970 vty_out (vty, " Cost: Type-1: %lu Type-2: %lu%s",
971 (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
972 VTY_NEWLINE);
973 vty_out (vty, " Router Bits: %s|%s|%s|%s%s",
974 (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
975 "W" : "-"),
976 (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
977 "V" : "-"),
978 (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
979 "E" : "-"),
980 (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
981 "B" : "-"), VTY_NEWLINE);
982 vty_out (vty, " Optional Capabilities: %s%s", capa, VTY_NEWLINE);
983 vty_out (vty, " Prefix Options: %s%s", "xxx", VTY_NEWLINE);
984 vty_out (vty, " Next Hops:%s", VTY_NEWLINE);
985
986 for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
987 linklist_next (&nnode))
988 {
989 nn = nnode.data;
990
991 inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
992 sizeof (nexthop));
993 if (! if_indextoname (nn->nexthop.ifindex, ifname))
994 snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
995
996 vty_out (vty, " %c%s%%%s%s",
997 (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
998
999 nc++;
1000 }
1001 pc++;
1002 }
1003 vty_out (vty, "%s", VTY_NEWLINE);
1004 }
1005
1006 int
1007 ospf6_route_table_show (struct vty *vty, int argc, char **argv,
1008 struct ospf6_route_table *table)
1009 {
1010 int i, ret;
1011 unsigned long ret_ul;
1012 char *endptr;
1013 struct prefix prefix;
1014 int detail = 0;
1015 int arg_ipv6 = 0;
1016 int arg_ipv4 = 0;
1017 int arg_digit = 0;
1018 struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
1019 struct prefix_ls *pl = (struct prefix_ls *) &prefix;
1020 struct route_node *node;
1021
1022 u_int route_count = 0;
1023 u_int path_count = 0;
1024 u_int route_redundant = 0;
1025
1026 memset (&prefix, 0, sizeof (struct prefix));
1027
1028 for (i = 0; i < argc; i++)
1029 {
1030 if (! strcmp (argv[i], "detail"))
1031 {
1032 detail++;
1033 break;
1034 }
1035
1036 if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
1037 {
1038
1039 if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
1040 {
1041 p6->family = AF_INET6;
1042 p6->prefixlen = 128;
1043 arg_ipv6++;
1044 continue;
1045 }
1046 else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
1047 {
1048 pl->family = AF_UNSPEC;
1049 pl->prefixlen = 64; /* xxx */
1050 arg_ipv4++;
1051 continue;
1052 }
1053 else
1054 {
1055 ret_ul = strtoul (argv[i], &endptr, 10);
1056 if (*endptr == '\0')
1057 {
1058 pl->adv_router.s_addr = htonl (ret_ul);
1059 pl->family = AF_UNSPEC;
1060 pl->prefixlen = 64; /* xxx */
1061 arg_digit++;
1062 continue;
1063 }
1064 else
1065 {
1066 vty_out (vty, "Malformed argument: %s%s",
1067 argv[i], VTY_NEWLINE);
1068 return CMD_SUCCESS;
1069 }
1070 }
1071 }
1072
1073 if (arg_ipv4 || arg_digit)
1074 {
1075 if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
1076 {
1077 arg_ipv4++;
1078 }
1079 else
1080 {
1081 ret_ul = strtoul (argv[i], &endptr, 10);
1082 if (*endptr == '\0')
1083 {
1084 pl->id.s_addr = htonl (ret_ul);
1085 arg_digit++;
1086 }
1087 else
1088 {
1089 vty_out (vty, "Malformed argument: %s%s",
1090 argv[i], VTY_NEWLINE);
1091 return CMD_SUCCESS;
1092 }
1093 }
1094 }
1095 }
1096
1097 if (arg_ipv4 || arg_ipv6 || arg_digit)
1098 {
1099 node = route_node_match (table->table, &prefix);
1100 if (node && node->info)
1101 ospf6_route_show_detail (vty, node->info);
1102 return CMD_SUCCESS;
1103 }
1104
1105 if (! detail)
1106 {
1107 vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
1108 ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
1109 vty_out (vty, "---------------------------%s", VTY_NEWLINE);
1110 }
1111
1112 for (node = route_top (table->table); node; node = route_next (node))
1113 {
1114 struct ospf6_route_node *route = node->info;
1115
1116 if (! route)
1117 continue;
1118
1119 if (detail)
1120 ospf6_route_show_detail (vty, route);
1121 else
1122 ospf6_route_show (vty, route);
1123
1124 route_count++;
1125 path_count += route->path_list->count;
1126 if (route->path_list->count > 1)
1127 route_redundant++;
1128 }
1129
1130 vty_out (vty, "===========%s", VTY_NEWLINE);
1131 vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
1132 route_count, path_count, route_redundant, VTY_NEWLINE);
1133
1134 return CMD_SUCCESS;
1135 }
1136