1/*
2 * Copyright (C) 2003 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
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 <zebra.h>
23
24#include "log.h"
25#include "memory.h"
26#include "linklist.h"
27#include "thread.h"
28#include "vty.h"
29#include "command.h"
30#include "if.h"
31#include "prefix.h"
32#include "table.h"
33#include "plist.h"
34#include "filter.h"
35
36#include "ospf6_proto.h"
37#include "ospf6_lsa.h"
38#include "ospf6_lsdb.h"
39#include "ospf6_route.h"
40#include "ospf6_spf.h"
41#include "ospf6_top.h"
42#include "ospf6_area.h"
43#include "ospf6_interface.h"
44#include "ospf6_intra.h"
45#include "ospf6_abr.h"
46#include "ospf6d.h"
47
48int
49ospf6_area_cmp (void *va, void *vb)
50{
51  struct ospf6_area *oa = (struct ospf6_area *) va;
52  struct ospf6_area *ob = (struct ospf6_area *) vb;
53  return (ntohl (oa->area_id) < ntohl (ob->area_id) ? -1 : 1);
54}
55
56/* schedule routing table recalculation */
57static void
58ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa)
59{
60  switch (ntohs (lsa->header->type))
61    {
62    case OSPF6_LSTYPE_ROUTER:
63    case OSPF6_LSTYPE_NETWORK:
64      if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
65        {
66          zlog_debug ("Examin %s", lsa->name);
67          zlog_debug ("Schedule SPF Calculation for %s",
68		      OSPF6_AREA (lsa->lsdb->data)->name);
69        }
70      ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6),
71			  ospf6_lsadd_to_spf_reason(lsa));
72      break;
73
74    case OSPF6_LSTYPE_INTRA_PREFIX:
75      ospf6_intra_prefix_lsa_add (lsa);
76      break;
77
78    case OSPF6_LSTYPE_INTER_PREFIX:
79    case OSPF6_LSTYPE_INTER_ROUTER:
80      ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data);
81      break;
82
83    default:
84      break;
85    }
86}
87
88static void
89ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa)
90{
91  switch (ntohs (lsa->header->type))
92    {
93    case OSPF6_LSTYPE_ROUTER:
94    case OSPF6_LSTYPE_NETWORK:
95      if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
96        {
97          zlog_debug ("LSA disappearing: %s", lsa->name);
98          zlog_debug ("Schedule SPF Calculation for %s",
99                     OSPF6_AREA (lsa->lsdb->data)->name);
100        }
101      ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6),
102			  ospf6_lsremove_to_spf_reason(lsa));
103      break;
104
105    case OSPF6_LSTYPE_INTRA_PREFIX:
106      ospf6_intra_prefix_lsa_remove (lsa);
107      break;
108
109    case OSPF6_LSTYPE_INTER_PREFIX:
110    case OSPF6_LSTYPE_INTER_ROUTER:
111      ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data);
112      break;
113
114    default:
115      break;
116    }
117}
118
119static void
120ospf6_area_route_hook_add (struct ospf6_route *route)
121{
122  struct ospf6_route *copy = ospf6_route_copy (route);
123  ospf6_route_add (copy, ospf6->route_table);
124}
125
126static void
127ospf6_area_route_hook_remove (struct ospf6_route *route)
128{
129  struct ospf6_route *copy;
130
131  copy = ospf6_route_lookup_identical (route, ospf6->route_table);
132  if (copy)
133    ospf6_route_remove (copy, ospf6->route_table);
134}
135
136/* Make new area structure */
137struct ospf6_area *
138ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
139{
140  struct ospf6_area *oa;
141  struct ospf6_route *route;
142
143  oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
144
145  inet_ntop (AF_INET, &area_id, oa->name, sizeof (oa->name));
146  oa->area_id = area_id;
147  oa->if_list = list_new ();
148
149  oa->lsdb = ospf6_lsdb_create (oa);
150  oa->lsdb->hook_add = ospf6_area_lsdb_hook_add;
151  oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
152  oa->lsdb_self = ospf6_lsdb_create (oa);
153
154  oa->spf_table = OSPF6_ROUTE_TABLE_CREATE (AREA, SPF_RESULTS);
155  oa->spf_table->scope = oa;
156  oa->route_table = OSPF6_ROUTE_TABLE_CREATE (AREA, ROUTES);
157  oa->route_table->scope = oa;
158  oa->route_table->hook_add = ospf6_area_route_hook_add;
159  oa->route_table->hook_remove = ospf6_area_route_hook_remove;
160
161  oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES);
162  oa->range_table->scope = oa;
163  oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES);
164  oa->summary_prefix->scope = oa;
165  oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS);
166  oa->summary_router->scope = oa;
167
168  /* set default options */
169  if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER))
170    {
171      OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6);
172      OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R);
173    }
174  else
175    {
176      OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6);
177      OSPF6_OPT_SET (oa->options, OSPF6_OPT_R);
178    }
179
180  OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
181
182  oa->ospf6 = o;
183  listnode_add_sort (o->area_list, oa);
184
185  /* import athoer area's routes as inter-area routes */
186  for (route = ospf6_route_head (o->route_table); route;
187       route = ospf6_route_next (route))
188    ospf6_abr_originate_summary_to_area (route, oa);
189
190  return oa;
191}
192
193void
194ospf6_area_delete (struct ospf6_area *oa)
195{
196  struct listnode *n;
197  struct ospf6_interface *oi;
198
199  ospf6_route_table_delete (oa->range_table);
200  ospf6_route_table_delete (oa->summary_prefix);
201  ospf6_route_table_delete (oa->summary_router);
202
203  /* The ospf6_interface structs store configuration
204   * information which should not be lost/reset when
205   * deleting an area.
206   * So just detach the interface from the area and
207   * keep it around. */
208  for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi))
209    oi->area = NULL;
210
211  list_delete (oa->if_list);
212
213  ospf6_lsdb_delete (oa->lsdb);
214  ospf6_lsdb_delete (oa->lsdb_self);
215
216  ospf6_spf_table_finish (oa->spf_table);
217  ospf6_route_table_delete (oa->spf_table);
218  ospf6_route_table_delete (oa->route_table);
219
220  THREAD_OFF (oa->thread_spf_calculation);
221  THREAD_OFF (oa->thread_route_calculation);
222
223  listnode_delete (oa->ospf6->area_list, oa);
224  oa->ospf6 = NULL;
225
226  /* free area */
227  XFREE (MTYPE_OSPF6_AREA, oa);
228}
229
230struct ospf6_area *
231ospf6_area_lookup (u_int32_t area_id, struct ospf6 *ospf6)
232{
233  struct ospf6_area *oa;
234  struct listnode *n;
235
236  for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, n, oa))
237    if (oa->area_id == area_id)
238      return oa;
239
240  return (struct ospf6_area *) NULL;
241}
242
243static struct ospf6_area *
244ospf6_area_get (u_int32_t area_id, struct ospf6 *o)
245{
246  struct ospf6_area *oa;
247  oa = ospf6_area_lookup (area_id, o);
248  if (oa == NULL)
249    oa = ospf6_area_create (area_id, o);
250  return oa;
251}
252
253void
254ospf6_area_enable (struct ospf6_area *oa)
255{
256  struct listnode *node, *nnode;
257  struct ospf6_interface *oi;
258
259  SET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
260
261  for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
262    ospf6_interface_enable (oi);
263  ospf6_abr_enable_area (oa);
264}
265
266void
267ospf6_area_disable (struct ospf6_area *oa)
268{
269  struct listnode *node, *nnode;
270  struct ospf6_interface *oi;
271
272  UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
273
274  for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
275    ospf6_interface_disable (oi);
276
277  ospf6_abr_disable_area (oa);
278  ospf6_lsdb_remove_all (oa->lsdb);
279  ospf6_lsdb_remove_all (oa->lsdb_self);
280
281  ospf6_spf_table_finish(oa->spf_table);
282  ospf6_route_remove_all(oa->route_table);
283
284  THREAD_OFF (oa->thread_spf_calculation);
285  THREAD_OFF (oa->thread_route_calculation);
286
287  THREAD_OFF (oa->thread_router_lsa);
288  THREAD_OFF (oa->thread_intra_prefix_lsa);
289}
290
291
292void
293ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
294{
295  struct listnode *i;
296  struct ospf6_interface *oi;
297
298  vty_out (vty, " Area %s%s", oa->name, VNL);
299  vty_out (vty, "     Number of Area scoped LSAs is %u%s",
300           oa->lsdb->count, VNL);
301
302  vty_out (vty, "     Interface attached to this area:");
303  for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
304    vty_out (vty, " %s", oi->interface->name);
305
306  vty_out (vty, "%s", VNL);
307}
308
309
310#define OSPF6_CMD_AREA_LOOKUP(str, oa)                     \
311{                                                          \
312  u_int32_t area_id = 0;                                   \
313  if (inet_pton (AF_INET, str, &area_id) != 1)             \
314    {                                                      \
315      vty_out (vty, "Malformed Area-ID: %s%s", str, VNL);  \
316      return CMD_SUCCESS;                                  \
317    }                                                      \
318  oa = ospf6_area_lookup (area_id, ospf6);                 \
319  if (oa == NULL)                                          \
320    {                                                      \
321      vty_out (vty, "No such Area: %s%s", str, VNL);       \
322      return CMD_SUCCESS;                                  \
323    }                                                      \
324}
325
326#define OSPF6_CMD_AREA_GET(str, oa)                        \
327{                                                          \
328  u_int32_t area_id = 0;                                   \
329  if (inet_pton (AF_INET, str, &area_id) != 1)             \
330    {                                                      \
331      vty_out (vty, "Malformed Area-ID: %s%s", str, VNL);  \
332      return CMD_SUCCESS;                                  \
333    }                                                      \
334  oa = ospf6_area_get (area_id, ospf6);                    \
335}
336
337DEFUN (area_range,
338       area_range_cmd,
339       "area A.B.C.D range X:X::X:X/M",
340       "OSPF area parameters\n"
341       OSPF6_AREA_ID_STR
342       "Configured address range\n"
343       "Specify IPv6 prefix\n"
344       )
345{
346  int ret;
347  struct ospf6_area *oa;
348  struct prefix prefix;
349  struct ospf6_route *range;
350
351  OSPF6_CMD_AREA_GET (argv[0], oa);
352  argc--;
353  argv++;
354
355  ret = str2prefix (argv[0], &prefix);
356  if (ret != 1 || prefix.family != AF_INET6)
357    {
358      vty_out (vty, "Malformed argument: %s%s", argv[0], VNL);
359      return CMD_SUCCESS;
360    }
361  argc--;
362  argv++;
363
364  range = ospf6_route_lookup (&prefix, oa->range_table);
365  if (range == NULL)
366    {
367      range = ospf6_route_create ();
368      range->type = OSPF6_DEST_TYPE_RANGE;
369      range->prefix = prefix;
370    }
371
372  if (argc)
373    {
374      if (! strcmp (argv[0], "not-advertise"))
375        SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
376      else if (! strcmp (argv[0], "advertise"))
377        UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
378    }
379
380  if (range->rnode)
381    {
382      vty_out (vty, "Range already defined: %s%s", argv[-1], VNL);
383      return CMD_WARNING;
384    }
385
386  ospf6_route_add (range, oa->range_table);
387  return CMD_SUCCESS;
388}
389
390ALIAS (area_range,
391       area_range_advertise_cmd,
392       "area A.B.C.D range X:X::X:X/M (advertise|not-advertise)",
393       "OSPF area parameters\n"
394       OSPF6_AREA_ID_STR
395       "Configured address range\n"
396       "Specify IPv6 prefix\n"
397       )
398
399DEFUN (no_area_range,
400       no_area_range_cmd,
401       "no area A.B.C.D range X:X::X:X/M",
402       "OSPF area parameters\n"
403       OSPF6_AREA_ID_STR
404       "Configured address range\n"
405       "Specify IPv6 prefix\n"
406       )
407{
408  int ret;
409  struct ospf6_area *oa;
410  struct prefix prefix;
411  struct ospf6_route *range;
412
413  OSPF6_CMD_AREA_GET (argv[0], oa);
414  argc--;
415  argv++;
416
417  ret = str2prefix (argv[0], &prefix);
418  if (ret != 1 || prefix.family != AF_INET6)
419    {
420      vty_out (vty, "Malformed argument: %s%s", argv[0], VNL);
421      return CMD_SUCCESS;
422    }
423
424  range = ospf6_route_lookup (&prefix, oa->range_table);
425  if (range == NULL)
426    {
427      vty_out (vty, "Range %s does not exists.%s", argv[0], VNL);
428      return CMD_SUCCESS;
429    }
430
431  ospf6_route_remove (range, oa->range_table);
432
433  return CMD_SUCCESS;
434}
435
436void
437ospf6_area_config_write (struct vty *vty)
438{
439  struct listnode *node;
440  struct ospf6_area *oa;
441  struct ospf6_route *range;
442  char buf[128];
443
444  for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
445    {
446      for (range = ospf6_route_head (oa->range_table); range;
447           range = ospf6_route_next (range))
448        {
449          prefix2str (&range->prefix, buf, sizeof (buf));
450          vty_out (vty, " area %s range %s%s", oa->name, buf, VNL);
451        }
452      if (PREFIX_NAME_IN (oa))
453        vty_out (vty, " area %s filter-list prefix %s in%s",
454                 oa->name, PREFIX_NAME_IN (oa), VNL);
455      if (PREFIX_NAME_OUT (oa))
456        vty_out (vty, " area %s filter-list prefix %s out%s",
457                 oa->name, PREFIX_NAME_OUT (oa), VNL);
458      if (IMPORT_NAME (oa))
459        vty_out (vty, " area %s import-list %s%s",
460                 oa->name, IMPORT_NAME (oa), VNL);
461      if (EXPORT_NAME (oa))
462        vty_out (vty, " area %s export-list %s%s",
463                 oa->name, EXPORT_NAME (oa), VNL);
464    }
465}
466
467DEFUN (area_filter_list,
468       area_filter_list_cmd,
469       "area A.B.C.D filter-list prefix WORD (in|out)",
470       "OSPFv6 area parameters\n"
471       "OSPFv6 area ID in IP address format\n"
472       "Filter networks between OSPFv6 areas\n"
473       "Filter prefixes between OSPFv6 areas\n"
474       "Name of an IPv6 prefix-list\n"
475       "Filter networks sent to this area\n"
476       "Filter networks sent from this area\n")
477{
478  struct ospf6_area *area;
479  struct prefix_list *plist;
480
481  OSPF6_CMD_AREA_GET (argv[0], area);
482  argc--;
483  argv++;
484
485  plist = prefix_list_lookup (AFI_IP6, argv[0]);
486  if (strncmp (argv[1], "in", 2) == 0)
487    {
488      PREFIX_LIST_IN (area) = plist;
489      if (PREFIX_NAME_IN (area))
490	free (PREFIX_NAME_IN (area));
491
492      PREFIX_NAME_IN (area) = strdup (argv[0]);
493      ospf6_abr_reimport (area);
494    }
495  else
496    {
497      PREFIX_LIST_OUT (area) = plist;
498      if (PREFIX_NAME_OUT (area))
499	free (PREFIX_NAME_OUT (area));
500
501      PREFIX_NAME_OUT (area) = strdup (argv[0]);
502      ospf6_abr_enable_area (area);
503    }
504
505  return CMD_SUCCESS;
506}
507
508DEFUN (no_area_filter_list,
509       no_area_filter_list_cmd,
510       "no area A.B.C.D filter-list prefix WORD (in|out)",
511       NO_STR
512       "OSPFv6 area parameters\n"
513       "OSPFv6 area ID in IP address format\n"
514       "Filter networks between OSPFv6 areas\n"
515       "Filter prefixes between OSPFv6 areas\n"
516       "Name of an IPv6 prefix-list\n"
517       "Filter networks sent to this area\n"
518       "Filter networks sent from this area\n")
519{
520  struct ospf6_area *area;
521
522  OSPF6_CMD_AREA_GET (argv[0], area);
523  argc--;
524  argv++;
525
526  if (strncmp (argv[1], "in", 2) == 0)
527    {
528      if (PREFIX_NAME_IN (area))
529	if (strcmp (PREFIX_NAME_IN (area), argv[0]) != 0)
530	  return CMD_SUCCESS;
531
532      PREFIX_LIST_IN (area) = NULL;
533      if (PREFIX_NAME_IN (area))
534	free (PREFIX_NAME_IN (area));
535
536      PREFIX_NAME_IN (area) = NULL;
537      ospf6_abr_reimport (area);
538    }
539  else
540    {
541      if (PREFIX_NAME_OUT (area))
542	if (strcmp (PREFIX_NAME_OUT (area), argv[0]) != 0)
543	  return CMD_SUCCESS;
544
545      PREFIX_LIST_OUT (area) = NULL;
546      if (PREFIX_NAME_OUT (area))
547	free (PREFIX_NAME_OUT (area));
548
549      PREFIX_NAME_OUT (area) = NULL;
550      ospf6_abr_enable_area (area);
551    }
552
553  return CMD_SUCCESS;
554}
555
556DEFUN (area_import_list,
557       area_import_list_cmd,
558       "area A.B.C.D import-list NAME",
559       "OSPFv6 area parameters\n"
560       "OSPFv6 area ID in IP address format\n"
561       "Set the filter for networks from other areas announced to the specified one\n"
562       "Name of the acess-list\n")
563{
564  struct ospf6_area *area;
565  struct access_list *list;
566
567  OSPF6_CMD_AREA_GET(argv[0], area);
568
569  list = access_list_lookup (AFI_IP6, argv[1]);
570
571  IMPORT_LIST (area) = list;
572
573  if (IMPORT_NAME (area))
574    free (IMPORT_NAME (area));
575
576  IMPORT_NAME (area) = strdup (argv[1]);
577  ospf6_abr_reimport (area);
578
579  return CMD_SUCCESS;
580}
581
582DEFUN (no_area_import_list,
583       no_area_import_list_cmd,
584       "no area A.B.C.D import-list NAME",
585       "OSPFv6 area parameters\n"
586       "OSPFv6 area ID in IP address format\n"
587       "Unset the filter for networks announced to other areas\n"
588       "NAme of the access-list\n")
589{
590  struct ospf6_area *area;
591
592  OSPF6_CMD_AREA_GET(argv[0], area);
593
594  IMPORT_LIST (area) = 0;
595
596  if (IMPORT_NAME (area))
597    free (IMPORT_NAME (area));
598
599  IMPORT_NAME (area) = NULL;
600  ospf6_abr_reimport (area);
601
602  return CMD_SUCCESS;
603}
604
605DEFUN (area_export_list,
606       area_export_list_cmd,
607       "area A.B.C.D export-list NAME",
608       "OSPFv6 area parameters\n"
609       "OSPFv6 area ID in IP address format\n"
610       "Set the filter for networks announced to other areas\n"
611       "Name of the acess-list\n")
612{
613  struct ospf6_area *area;
614  struct access_list *list;
615
616  OSPF6_CMD_AREA_GET(argv[0], area);
617
618  list = access_list_lookup (AFI_IP6, argv[1]);
619
620  EXPORT_LIST (area) = list;
621
622  if (EXPORT_NAME (area))
623    free (EXPORT_NAME (area));
624
625  EXPORT_NAME (area) = strdup (argv[1]);
626  ospf6_abr_enable_area (area);
627
628  return CMD_SUCCESS;
629}
630
631DEFUN (no_area_export_list,
632       no_area_export_list_cmd,
633       "no area A.B.C.D export-list NAME",
634       "OSPFv6 area parameters\n"
635       "OSPFv6 area ID in IP address format\n"
636       "Unset the filter for networks announced to other areas\n"
637       "Name of the access-list\n")
638{
639  struct ospf6_area *area;
640
641  OSPF6_CMD_AREA_GET(argv[0], area);
642
643  EXPORT_LIST (area) = 0;
644
645  if (EXPORT_NAME (area))
646    free (EXPORT_NAME (area));
647
648  EXPORT_NAME (area) = NULL;
649  ospf6_abr_enable_area (area);
650
651  return CMD_SUCCESS;
652}
653
654DEFUN (show_ipv6_ospf6_spf_tree,
655       show_ipv6_ospf6_spf_tree_cmd,
656       "show ipv6 ospf6 spf tree",
657       SHOW_STR
658       IP6_STR
659       OSPF6_STR
660       "Shortest Path First caculation\n"
661       "Show SPF tree\n")
662{
663  struct listnode *node;
664  struct ospf6_area *oa;
665  struct ospf6_vertex *root;
666  struct ospf6_route *route;
667  struct prefix prefix;
668
669  ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
670
671  for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
672    {
673      route = ospf6_route_lookup (&prefix, oa->spf_table);
674      if (route == NULL)
675        {
676          vty_out (vty, "LS entry for root not found in area %s%s",
677                   oa->name, VNL);
678          continue;
679        }
680      root = (struct ospf6_vertex *) route->route_option;
681      ospf6_spf_display_subtree (vty, "", 0, root);
682    }
683
684  return CMD_SUCCESS;
685}
686
687DEFUN (show_ipv6_ospf6_area_spf_tree,
688       show_ipv6_ospf6_area_spf_tree_cmd,
689       "show ipv6 ospf6 area A.B.C.D spf tree",
690       SHOW_STR
691       IP6_STR
692       OSPF6_STR
693       OSPF6_AREA_STR
694       OSPF6_AREA_ID_STR
695       "Shortest Path First caculation\n"
696       "Show SPF tree\n")
697{
698  u_int32_t area_id;
699  struct ospf6_area *oa;
700  struct ospf6_vertex *root;
701  struct ospf6_route *route;
702  struct prefix prefix;
703
704  ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
705
706  if (inet_pton (AF_INET, argv[0], &area_id) != 1)
707    {
708      vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VNL);
709      return CMD_SUCCESS;
710    }
711  oa = ospf6_area_lookup (area_id, ospf6);
712  if (oa == NULL)
713    {
714      vty_out (vty, "No such Area: %s%s", argv[0], VNL);
715      return CMD_SUCCESS;
716    }
717
718  route = ospf6_route_lookup (&prefix, oa->spf_table);
719  if (route == NULL)
720    {
721      vty_out (vty, "LS entry for root not found in area %s%s",
722               oa->name, VNL);
723      return CMD_SUCCESS;
724    }
725  root = (struct ospf6_vertex *) route->route_option;
726  ospf6_spf_display_subtree (vty, "", 0, root);
727
728  return CMD_SUCCESS;
729}
730
731DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
732       show_ipv6_ospf6_simulate_spf_tree_root_cmd,
733       "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D",
734       SHOW_STR
735       IP6_STR
736       OSPF6_STR
737       "Shortest Path First caculation\n"
738       "Show SPF tree\n"
739       "Specify root's router-id to calculate another router's SPF tree\n")
740{
741  u_int32_t area_id;
742  struct ospf6_area *oa;
743  struct ospf6_vertex *root;
744  struct ospf6_route *route;
745  struct prefix prefix;
746  u_int32_t router_id;
747  struct ospf6_route_table *spf_table;
748  unsigned char tmp_debug_ospf6_spf = 0;
749
750  inet_pton (AF_INET, argv[0], &router_id);
751  ospf6_linkstate_prefix (router_id, htonl (0), &prefix);
752
753  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
754    {
755      vty_out (vty, "Malformed Area-ID: %s%s", argv[1], VNL);
756      return CMD_SUCCESS;
757    }
758  oa = ospf6_area_lookup (area_id, ospf6);
759  if (oa == NULL)
760    {
761      vty_out (vty, "No such Area: %s%s", argv[1], VNL);
762      return CMD_SUCCESS;
763    }
764
765  tmp_debug_ospf6_spf = conf_debug_ospf6_spf;
766  conf_debug_ospf6_spf = 0;
767
768  spf_table = OSPF6_ROUTE_TABLE_CREATE (NONE, SPF_RESULTS);
769  ospf6_spf_calculation (router_id, spf_table, oa);
770
771  conf_debug_ospf6_spf = tmp_debug_ospf6_spf;
772
773  route = ospf6_route_lookup (&prefix, spf_table);
774  if (route == NULL)
775    {
776      ospf6_spf_table_finish (spf_table);
777      ospf6_route_table_delete (spf_table);
778      return CMD_SUCCESS;
779    }
780  root = (struct ospf6_vertex *) route->route_option;
781  ospf6_spf_display_subtree (vty, "", 0, root);
782
783  ospf6_spf_table_finish (spf_table);
784  ospf6_route_table_delete (spf_table);
785
786  return CMD_SUCCESS;
787}
788
789void
790ospf6_area_init (void)
791{
792  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
793  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
794  install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd);
795
796  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd);
797  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
798  install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd);
799
800  install_element (OSPF6_NODE, &area_range_cmd);
801  install_element (OSPF6_NODE, &area_range_advertise_cmd);
802  install_element (OSPF6_NODE, &no_area_range_cmd);
803
804  install_element (OSPF6_NODE, &area_import_list_cmd);
805  install_element (OSPF6_NODE, &no_area_import_list_cmd);
806  install_element (OSPF6_NODE, &area_export_list_cmd);
807  install_element (OSPF6_NODE, &no_area_export_list_cmd);
808
809  install_element (OSPF6_NODE, &area_filter_list_cmd);
810  install_element (OSPF6_NODE, &no_area_filter_list_cmd);
811
812}
813
814
815