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
24char *
25dtype_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
33char *
34dtype_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
42char *
43ptype_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
53char *
54ptype_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
65
66int
67ospf6_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
102int
103ospf6_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
130static void
131ospf6_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
200int
201ospf6_route_count (struct ospf6_route_req *request)
202{
203  return request->count;
204}
205
206int
207ospf6_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
241void
242ospf6_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
272int
273ospf6_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
284void
285ospf6_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
345void
346ospf6_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
362void
363ospf6_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
373void
374ospf6_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
385int
386prefix_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
397void
398ospf6_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
434struct ospf6_path_node *
435ospf6_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
469struct ospf6_nexthop_node *
470ospf6_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
486void
487ospf6_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
615void
616ospf6_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                  snprintf (p++, line + sizeof (line) - p, " ");
670                snprintf (p, line + sizeof (line) - p, "%02x", *c);
671                p += 2;
672              }
673            zlog_info ("ROUTE:     path: %s", line);
674
675            p = line;
676            s = (char *) &request->path;
677            e = s + sizeof (struct ospf6_path);
678            for (c = s; c < e; c++)
679              {
680                if ((c - s) % 4 == 0)
681                  snprintf (p++, line + sizeof (line) - p, " ");
682                snprintf (p, line + sizeof (line) - p, "%02x", *c);
683                p += 2;
684              }
685            zlog_info ("ROUTE:     req : %s", line);
686
687          }
688        }
689      return;
690    }
691
692  nn = ospf6_route_find_nexthop_node (request, pn);
693  if (! nn)
694    {
695      if (IS_OSPF6_DUMP_ROUTE)
696        {
697          ospf6_route_log_request ("Remove", table->name, request);
698          zlog_info ("ROUTE:   Can't remove: No such nexthop");
699        }
700      return;
701    }
702
703  if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
704    {
705      if (IS_OSPF6_DUMP_ROUTE)
706        {
707          ospf6_route_log_request ("Remove", table->name, request);
708          zlog_info ("ROUTE:   Can't remove: Nexthop differ");
709        }
710      return;
711    }
712
713  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
714
715  if (table->freeze)
716    return;
717
718  if (IS_OSPF6_DUMP_ROUTE)
719    ospf6_route_log_request ("Remove", table->name, request);
720
721  ospf6_route_request (&route, rn, pn, nn);
722  ospf6_route_hook_call (REMOVE, &route, table);
723  if (table->hook_remove)
724    (*table->hook_remove) (&route);
725
726  /* clear flag */
727  nn->flag = 0;
728
729  /* remove nexthop */
730  linklist_remove (nn, pn->nexthop_list);
731  rn->count--;
732  XFREE (MTYPE_OSPF6_ROUTE, nn);
733
734  /* remove path if there's no nexthop for the path */
735  if (pn->nexthop_list->count != 0)
736    return;
737  linklist_remove (pn, rn->path_list);
738  linklist_delete (pn->nexthop_list);
739  XFREE (MTYPE_OSPF6_ROUTE, pn);
740
741  /* remove route if there's no path for the route */
742  if (rn->path_list->count != 0)
743    return;
744  route_node->info = NULL;
745  linklist_delete (rn->path_list);
746  XFREE (MTYPE_OSPF6_ROUTE, rn);
747}
748
749void
750ospf6_route_remove_all (struct ospf6_route_table *table)
751{
752  struct ospf6_route_req request;
753
754  for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
755       ospf6_route_next (&request))
756    ospf6_route_remove (&request, table);
757}
758
759
760struct ospf6_route_table *
761ospf6_route_table_create (char *name)
762{
763  int i;
764  struct ospf6_route_table *new;
765
766  new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
767  snprintf (new->name, sizeof (new->name), "%s", name);
768
769  new->table = route_table_init ();
770  for (i = 0; i < 3; i++)
771    new->hook_list[i] = linklist_create ();
772
773  return new;
774}
775
776void
777ospf6_route_table_delete (struct ospf6_route_table *table)
778{
779  int i;
780
781  ospf6_route_remove_all (table);
782  route_table_finish (table->table);
783  for (i = 0; i < 3; i++)
784    linklist_delete (table->hook_list[i]);
785  XFREE (MTYPE_OSPF6_ROUTE, table);
786}
787
788void
789ospf6_route_table_freeze (struct ospf6_route_table *route_table)
790{
791  if (IS_OSPF6_DUMP_ROUTE)
792    zlog_info ("ROUTE: Table freeze: %s", route_table->name);
793  assert (route_table->freeze == 0);
794  route_table->freeze = 1;
795}
796
797void
798ospf6_route_table_thaw (struct ospf6_route_table *route_table)
799{
800  struct route_node *node;
801  struct linklist_node pnode;
802  struct linklist_node nnode;
803
804  struct ospf6_route_node   *rn;
805  struct ospf6_path_node    *pn;
806  struct ospf6_nexthop_node *nn;
807
808  struct ospf6_route_req request;
809
810  if (IS_OSPF6_DUMP_ROUTE)
811    zlog_info ("ROUTE: Table thaw: %s", route_table->name);
812
813  assert (route_table->freeze == 1);
814  route_table->freeze = 0;
815
816  for (node = route_top (route_table->table); node;
817       node = route_next (node))
818    {
819      rn = node->info;
820      if (! rn)
821        continue;
822
823      for (linklist_head (rn->path_list, &pnode);
824           ! linklist_end (&pnode);
825           linklist_next (&pnode))
826        {
827          pn = pnode.data;
828
829          for (linklist_head (pn->nexthop_list, &nnode);
830               ! linklist_end (&nnode);
831               linklist_next (&nnode))
832            {
833              nn = nnode.data;
834
835              /* if the add and remove flag set without change flag,
836                 do nothing with this route */
837              if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
838                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
839                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
840                {
841                  nn->flag = 0;
842                  continue;
843                }
844
845              memset (&request, 0, sizeof (request));
846              memcpy (&request.route, &rn->route, sizeof (rn->route));
847              memcpy (&request.path, &pn->path, sizeof (pn->path));
848              memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
849
850              if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
851                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
852                ospf6_route_add (&request, route_table);
853              else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
854                ospf6_route_remove (&request, route_table);
855            }
856        }
857    }
858}
859
860
861/* VTY commands */
862
863void
864ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
865{
866  struct linklist_node pnode;
867  struct linklist_node nnode;
868  struct ospf6_path_node    *pn;
869  struct ospf6_nexthop_node *nn;
870
871  struct timeval now, res;
872  char duration[16];
873
874  u_int pc = 0;
875  u_int nc = 0;
876#define HEAD (pc == 0 && nc == 0)
877
878  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
879
880  gettimeofday (&now, (struct timezone *) NULL);
881
882  /* destination */
883  if (rn->route.prefix.family == AF_INET ||
884      rn->route.prefix.family == AF_INET6)
885    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
886  else
887    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
888
889  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
890       linklist_next (&pnode))
891    {
892      pn = pnode.data;
893
894      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
895           linklist_next (&nnode))
896        {
897          nn = nnode.data;
898
899          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
900                     sizeof (nexthop));
901          if (! if_indextoname (nn->nexthop.ifindex, ifname))
902            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
903
904          ospf6_timeval_sub (&now, &nn->installed, &res);
905          ospf6_timeval_string_summary (&res, duration, sizeof (duration));
906
907          vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
908                   (HEAD ? '*' : ' '),
909                   DTYPE_ABNAME (rn->route.type),
910                   PTYPE_ABNAME (pn->path.type),
911                   prefix, nexthop, ifname, duration, VTY_NEWLINE);
912
913          nc++;
914        }
915      pc++;
916    }
917}
918
919void
920ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
921{
922  struct linklist_node pnode;
923  struct linklist_node nnode;
924  struct ospf6_path_node    *pn;
925  struct ospf6_nexthop_node *nn;
926
927  u_int pc = 0;
928  u_int nc = 0;
929
930  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
931  char area_id[16], type[16], id[16], adv[16];
932  char capa[64];
933
934  /* destination */
935  if (rn->route.prefix.family == AF_INET ||
936      rn->route.prefix.family == AF_INET6)
937    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
938  else
939    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
940
941  vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
942  vty_out (vty, "    Destination Type: %s%s",
943           DTYPE_NAME (rn->route.type), VTY_NEWLINE);
944
945  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
946       linklist_next (&pnode))
947    {
948      pn = pnode.data;
949
950      inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
951      ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
952      inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
953      inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
954      ospf6_options_string (pn->path.capability, capa, sizeof (capa));
955
956      vty_out (vty, "  Path:%s", VTY_NEWLINE);
957      vty_out (vty, "    Associated Area: %s%s", area_id, VTY_NEWLINE);
958      vty_out (vty, "    LS Origin: %s ID: %s Adv: %s%s",
959               type, id, adv, VTY_NEWLINE);
960      vty_out (vty, "    Path Type: %s%s",
961               PTYPE_NAME (pn->path.type), VTY_NEWLINE);
962      vty_out (vty, "    Metric Type: %d%s",
963               pn->path.metric_type, VTY_NEWLINE);
964      vty_out (vty, "    Cost: Type-1: %lu Type-2: %lu%s",
965               (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
966               VTY_NEWLINE);
967      vty_out (vty, "    Router Bits: %s|%s|%s|%s%s",
968               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
969                "W" : "-"),
970               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
971                "V" : "-"),
972               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
973                "E" : "-"),
974               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
975                "B" : "-"), VTY_NEWLINE);
976      vty_out (vty, "    Optional Capabilities: %s%s", capa, VTY_NEWLINE);
977      vty_out (vty, "    Prefix Options: %s%s", "xxx", VTY_NEWLINE);
978      vty_out (vty, "    Next Hops:%s", VTY_NEWLINE);
979
980      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
981           linklist_next (&nnode))
982        {
983          nn = nnode.data;
984
985          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
986                     sizeof (nexthop));
987          if (! if_indextoname (nn->nexthop.ifindex, ifname))
988            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
989
990          vty_out (vty, "       %c%s%%%s%s",
991                   (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
992
993          nc++;
994        }
995      pc++;
996    }
997  vty_out (vty, "%s", VTY_NEWLINE);
998}
999
1000int
1001ospf6_route_table_show (struct vty *vty, int argc, char **argv,
1002                        struct ospf6_route_table *table)
1003{
1004  int i, ret;
1005  unsigned long ret_ul;
1006  char *endptr;
1007  struct prefix prefix;
1008  int detail = 0;
1009  int arg_ipv6  = 0;
1010  int arg_ipv4  = 0;
1011  int arg_digit = 0;
1012  struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
1013  struct prefix_ls   *pl = (struct prefix_ls *) &prefix;
1014  struct route_node *node;
1015
1016  memset (&prefix, 0, sizeof (struct prefix));
1017
1018  for (i = 0; i < argc; i++)
1019    {
1020      if (! strcmp (argv[i], "detail"))
1021        {
1022          detail++;
1023          break;
1024        }
1025
1026      if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
1027        {
1028
1029          if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
1030            {
1031              p6->family = AF_INET6;
1032              p6->prefixlen = 128;
1033              arg_ipv6++;
1034              continue;
1035            }
1036          else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
1037            {
1038              pl->family = AF_UNSPEC;
1039              pl->prefixlen = 64; /* xxx */
1040              arg_ipv4++;
1041              continue;
1042            }
1043          else
1044            {
1045              ret_ul = strtoul (argv[i], &endptr, 10);
1046              if (*endptr == '\0')
1047                {
1048                  pl->adv_router.s_addr = htonl (ret_ul);
1049                  pl->family = AF_UNSPEC;
1050                  pl->prefixlen = 64; /* xxx */
1051                  arg_digit++;
1052                  continue;
1053                }
1054              else
1055                {
1056                  vty_out (vty, "Malformed argument: %s%s",
1057                           argv[i], VTY_NEWLINE);
1058                  return CMD_SUCCESS;
1059                }
1060            }
1061        }
1062
1063      if (arg_ipv4 || arg_digit)
1064        {
1065          if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
1066            {
1067              arg_ipv4++;
1068            }
1069          else
1070            {
1071              ret_ul = strtoul (argv[i], &endptr, 10);
1072              if (*endptr == '\0')
1073                {
1074                  pl->id.s_addr = htonl (ret_ul);
1075                  arg_digit++;
1076                }
1077              else
1078                {
1079                  vty_out (vty, "Malformed argument: %s%s",
1080                           argv[i], VTY_NEWLINE);
1081                  return CMD_SUCCESS;
1082                }
1083            }
1084        }
1085    }
1086
1087  if (arg_ipv4 || arg_ipv6 || arg_digit)
1088    {
1089      node = route_node_match (table->table, &prefix);
1090      if (node && node->info)
1091        ospf6_route_show_detail (vty, node->info);
1092      return CMD_SUCCESS;
1093    }
1094
1095  if (! detail)
1096    {
1097      vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
1098               ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
1099      vty_out (vty, "---------------------------%s", VTY_NEWLINE);
1100    }
1101
1102  for (node = route_top (table->table); node; node = route_next (node))
1103    {
1104      if (! node->info)
1105        continue;
1106
1107      if (detail)
1108        ospf6_route_show_detail (vty, node->info);
1109      else
1110        ospf6_route_show (vty, node->info);
1111    }
1112
1113  return CMD_SUCCESS;
1114}
1115
1116