From: Dinesh Dutt <[email protected]>

Support stubby and totally stubby areas in OSPFv3

Signed-off-by: Dinesh G Dutt <[email protected]>
Reviewed-by: Pradosh Mohapatra <[email protected]>
---
 lib/libospf.h        |   5 +
 lib/thread.c         |   2 -
 lib/thread.h         |   3 +
 ospf6d/ospf6_abr.c   | 254 ++++++++++++++++++++++++++++++++++-----------------
 ospf6d/ospf6_abr.h   |   6 +-
 ospf6d/ospf6_area.c  | 221 +++++++++++++++++++++++++++++++++++++++++---
 ospf6d/ospf6_area.h  |   3 +
 ospf6d/ospf6_asbr.c  |  17 ++++
 ospf6d/ospf6_asbr.h  |   1 +
 ospf6d/ospf6_flood.c |   2 +-
 ospf6d/ospf6_flood.h |   2 +
 ospf6d/ospf6_intra.c |  57 +++++++-----
 ospf6d/ospf6_lsa.h   |   1 +
 ospf6d/ospf6_route.h |   4 +
 ospf6d/ospf6_spf.c   |  12 ++-
 ospfd/ospfd.h        |   4 -
 16 files changed, 465 insertions(+), 129 deletions(-)

diff --git a/lib/libospf.h b/lib/libospf.h
index 93e8678..a3bbc1d 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -82,6 +82,11 @@
 #define OSPF_AREA_BACKBONE              0x00000000      /* 0.0.0.0 */
 #define OSPF_AREA_RANGE_COST_UNSPEC    -1U
 
+#define OSPF_AREA_DEFAULT       0
+#define OSPF_AREA_STUB          1
+#define OSPF_AREA_NSSA          2
+#define OSPF_AREA_TYPE_MAX     3
+
 /* SPF Throttling timer values. */
 #define OSPF_SPF_DELAY_DEFAULT              0
 #define OSPF_SPF_HOLDTIME_DEFAULT           50
diff --git a/lib/thread.c b/lib/thread.c
index 688d291..f72e67e 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -57,8 +57,6 @@ static unsigned short timers_inited;
 
 static struct hash *cpu_record = NULL;
 
-/* Struct timeval's tv_usec one second value.  */
-#define TIMER_SECOND_MICRO 1000000L
 
 /* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
    And change negative values to 0. */
diff --git a/lib/thread.h b/lib/thread.h
index d8c5389..1c9f4f1 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -109,6 +109,9 @@ enum quagga_clkid {
   QUAGGA_CLK_REALTIME_STABILISED, /* like realtime, but non-decrementing */
 };
 
+/* Struct timeval's tv_usec one second value.  */
+#define TIMER_SECOND_MICRO 1000000L
+
 /* Thread types. */
 #define THREAD_READ           0
 #define THREAD_WRITE          1
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index e4e36f1..33299f4 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -91,7 +91,7 @@ ospf6_abr_delete_route (struct ospf6_route *range, struct 
ospf6_route *summary,
       ospf6_route_remove (summary, summary_table);
     }
 
-  if (old)
+  if (old && !OSPF6_LSA_IS_MAXAGE (old))
     ospf6_lsa_purge (old);
 }
 
@@ -99,35 +99,11 @@ void
 ospf6_abr_enable_area (struct ospf6_area *area)
 {
   struct ospf6_area *oa;
-  struct ospf6_route *ro;
   struct listnode *node, *nnode;
 
   for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa))
-    {
-      /* update B bit for each area */
-      OSPF6_ROUTER_LSA_SCHEDULE (oa);
-
-      /* install other area's configured address range */
-      if (oa != area)
-        {
-          for (ro = ospf6_route_head (oa->range_table); ro;
-               ro = ospf6_route_next (ro))
-            {
-              if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
-                ospf6_abr_originate_summary_to_area (ro, area);
-            }
-        }
-    }
-
-  /* install calculated routes to border routers */
-  for (ro = ospf6_route_head (area->ospf6->brouter_table); ro;
-       ro = ospf6_route_next (ro))
-    ospf6_abr_originate_summary_to_area (ro, area);
-
-  /* install calculated routes to network (may be rejected by ranges) */
-  for (ro = ospf6_route_head (area->ospf6->route_table); ro;
-       ro = ospf6_route_next (ro))
-    ospf6_abr_originate_summary_to_area (ro, area);
+    /* update B bit for each area */
+    OSPF6_ROUTER_LSA_SCHEDULE (oa);
 }
 
 void
@@ -167,6 +143,8 @@ ospf6_abr_disable_area (struct ospf6_area *area)
 }
 
 /* RFC 2328 12.4.3. Summary-LSAs */
+/* Returns 1 if a summary LSA has been generated for the area */
+/* This is used by the area/range logic to add/remove blackhole routes */
 int
 ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
                                      struct ospf6_area *area)
@@ -295,6 +273,15 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route 
*route,
       return 0;
     }
 
+  if (area->no_summary && (route->path.subtype != 
OSPF6_PATH_SUBTYPE_DEFAULT_RT))
+    {
+      if (is_debug)
+        zlog_debug ("Area has been stubbed, purge prefix LSA");
+
+      ospf6_abr_delete_route (route, summary, summary_table, old);
+      return 0;
+    }
+
   /* do not generate if the route cost is greater or equal to LSInfinity */
   if (route->path.cost >= OSPF_LS_INFINITY)
     {
@@ -445,7 +432,6 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route 
*route,
                               summary->path.origin.adv_router, area->lsdb);
        }
       summary = ospf6_route_add (summary, summary_table);
-
     }
   else
     {
@@ -460,6 +446,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route 
*route,
   summary->path.prefix_options = route->path.prefix_options;
   summary->path.area_id = area->area_id;
   summary->path.type = OSPF6_PATH_TYPE_INTER;
+  summary->path.subtype = route->path.subtype;
   summary->path.cost = route->path.cost;
     /* summary->nexthop[0] = route->nexthop[0]; */
 
@@ -523,94 +510,132 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route 
*route,
 }
 
 void
-ospf6_abr_range_update (struct ospf6_route *range)
+ospf6_abr_range_reset_cost (struct ospf6 *ospf6)
+{
+  struct listnode *node, *nnode;
+  struct ospf6_area *oa;
+  struct ospf6_route *range;
+
+  for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+    for (range = ospf6_route_head (oa->range_table); range;
+        range = ospf6_route_next (range))
+      OSPF6_ABR_RANGE_CLEAR_COST(range);
+}
+
+static inline u_int32_t
+ospf6_abr_range_compute_cost (struct ospf6_route *range, struct ospf6 *o)
 {
-  u_int32_t cost = 0;
   struct ospf6_route *ro;
-  int gen_range_summary = 0;
-  char buf[INET6_ADDRSTRLEN];
+  u_int32_t cost = 0;
 
-  assert (range->type == OSPF6_DEST_TYPE_RANGE);
-  prefix2str (&range->prefix, buf, sizeof (buf));
+  for (ro = ospf6_route_match_head (&range->prefix, o->route_table);
+       ro; ro = ospf6_route_match_next (&range->prefix, ro))
+    {
+      if (ro->path.area_id == range->path.area_id &&
+         (ro->path.type == OSPF6_PATH_TYPE_INTRA) &&
+         ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
+       cost = MAX (cost, ro->path.cost);
+    }
+
+  return cost;
+}
+
+static inline int
+ospf6_abr_range_summary_needs_update (struct ospf6_route *range,
+                                     u_int32_t cost)
+{
+  int redo_summary = 0;
 
   if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE))
     {
       UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
-      gen_range_summary = 1;
+      redo_summary = 1;
     }
-  else
-    {
-      /* update range's cost and active flag */
-      for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table);
-          ro; ro = ospf6_route_match_next (&range->prefix, ro))
-       {
-         if (ro->path.area_id == range->path.area_id &&
-             (ro->path.type == OSPF6_PATH_TYPE_INTRA) &&
-             ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
-           cost = MAX (cost, ro->path.cost);
-       }
-    }
-
-  /* Non-zero cost is a proxy for active longer prefixes in this range.
-   * If there are active routes covered by this range AND either the configured
-   * cost has changed or the summarized cost has changed then redo summaries.
-   * Alternately, if there are no longer active prefixes and there are
-   * summary announcements, withdraw those announcements.
-   *
-   * The don't advertise code relies on the path.cost being set to UNSPEC to
-   * work the first time. Subsequent times the path.cost is not 0 anyway if 
there
-   * were active ranges.
-   */
-  if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
+  else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
     {
       if (range->path.cost != 0)
        {
          range->path.cost = 0;
-         gen_range_summary = 1;
+         redo_summary = 1;
        }
     }
-  else if (cost &&
-          (((range->path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC) &&
-            (range->path.cost != range->path.u.cost_config)) ||
-           ((range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC) &&
-            (range->path.cost != cost))))
+  else if (cost)
     {
-      if (range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC)
+      if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+          range->path.cost != range->path.u.cost_config))
        {
-         range->path.cost = cost;
+         range->path.cost = range->path.u.cost_config;
+         SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+         redo_summary = 1;
        }
-      else
+      else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path) &&
+              range->path.cost != cost)
        {
-         range->path.cost = range->path.u.cost_config;
+         range->path.cost = cost;
+         SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
+         redo_summary = 1;
        }
-
-      SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
-      gen_range_summary = 1;
     }
-  else if (!cost && CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+  else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
     {
+      /* Cost is zero, meaning no active range */
       UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
       range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
-      gen_range_summary = 1;
+      redo_summary = 1;
     }
 
-  if (gen_range_summary)
+  return (redo_summary);
+}
+
+static void
+ospf6_abr_range_update (struct ospf6_route *range)
+{
+  u_int32_t cost = 0;
+  struct listnode *node, *nnode;
+  struct ospf6_area *oa;
+  int summary_orig = 0;
+
+  assert (range->type == OSPF6_DEST_TYPE_RANGE);
+
+  /* update range's cost and active flag */
+  cost = ospf6_abr_range_compute_cost (range, ospf6);
+
+  /* Non-zero cost is a proxy for active longer prefixes in this range.
+   * If there are active routes covered by this range AND either the configured
+   * cost has changed or the summarized cost has changed then redo summaries.
+   * Alternately, if there are no longer active prefixes and there are
+   * summary announcements, withdraw those announcements.
+   *
+   * The don't advertise code relies on the path.cost being set to UNSPEC to
+   * work the first time. Subsequent times the path.cost is not 0 anyway if 
there
+   * were active ranges.
+   */
+
+  if (ospf6_abr_range_summary_needs_update (range, cost))
     {
-      ospf6_abr_originate_summary (range);
+      for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+       summary_orig += ospf6_abr_originate_summary_to_area (range, oa);
 
-      if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
+      if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) && summary_orig)
        {
-         if (IS_OSPF6_DEBUG_ABR)
-           zlog_debug ("Add discard route");
+         if (! CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+           {
+             if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug ("Add discard route");
 
-         ospf6_zebra_add_discard (range);
+             ospf6_zebra_add_discard (range);
+           }
        }
       else
        {
-         if (IS_OSPF6_DEBUG_ABR)
-           zlog_debug ("Delete discard route");
+         /* Summary removed or no summary generated as no specifics exist */
+         if (CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
+           {
+             if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug ("Delete discard route");
 
-         ospf6_zebra_delete_discard (range);
+             ospf6_zebra_delete_discard (range);
+           }
        }
     }
 }
@@ -636,6 +661,54 @@ ospf6_abr_originate_summary (struct ospf6_route *route)
     ospf6_abr_originate_summary_to_area (route, oa);
 }
 
+void
+ospf6_abr_defaults_to_stub (struct ospf6 *o)
+{
+  struct listnode *node, *nnode;
+  struct ospf6_area *oa;
+  struct ospf6_route *def, *route;
+
+  if (!o->backbone)
+    return;
+
+  def = ospf6_route_create();
+  def->type = OSPF6_DEST_TYPE_NETWORK;
+  def->prefix.family = AF_INET6;
+  def->prefix.prefixlen = 0;
+  memset (&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
+  def->type = OSPF6_DEST_TYPE_NETWORK;
+  def->path.type = OSPF6_PATH_TYPE_INTER;
+  def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
+  def->path.area_id = o->backbone->area_id;
+
+  for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
+    {
+      if (!IS_AREA_STUB (oa))
+       {
+         /* withdraw defaults when an area switches from stub to non-stub */
+         route = ospf6_route_lookup (&def->prefix, oa->summary_prefix);
+         if (route && (route->path.subtype == def->path.subtype))
+           {
+             if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug ("Withdrawing default route from non-stubby area %s",
+                           oa->name);
+             SET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+             ospf6_abr_originate_summary_to_area (def, oa);
+           }
+       }
+      else
+       {
+         /* announce defaults to stubby areas */
+         if (IS_OSPF6_DEBUG_ABR)
+           zlog_debug ("Announcing default route into stubby area %s",
+                       oa->name);
+         UNSET_FLAG (def->flag, OSPF6_ROUTE_REMOVE);
+         ospf6_abr_originate_summary_to_area (def, oa);
+       }
+    }
+  ospf6_route_delete (def);
+}
+
 /* RFC 2328 16.2. Calculating the inter-area routes */
 void
 ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
@@ -939,6 +1012,21 @@ ospf6_abr_reimport (struct ospf6_area *oa)
     ospf6_abr_examin_summary (lsa, oa);
 }
 
+void
+ospf6_abr_prefix_resummarize (struct ospf6 *o)
+{
+  struct ospf6_route *route;
+
+  if (IS_OSPF6_DEBUG_ABR)
+    zlog_debug ("Re-examining Inter-Prefix Summaries");
+
+  for (route = ospf6_route_head (o->route_table); route;
+       route = ospf6_route_next (route))
+    ospf6_abr_originate_summary(route);
+
+  if (IS_OSPF6_DEBUG_ABR)
+    zlog_debug ("Finished re-examining Inter-Prefix Summaries");
+}
 
 
 /* Display functions */
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
index 041582e..5bc2469 100644
--- a/ospf6d/ospf6_abr.h
+++ b/ospf6d/ospf6_abr.h
@@ -59,6 +59,8 @@ struct ospf6_inter_router_lsa
   { (E)->metric &= htonl (0x00000000); \
     (E)->metric |= htonl (0x00ffffff) & htonl (C); }
 
+#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = 
OSPF_AREA_RANGE_COST_UNSPEC)
+
 extern int ospf6_is_router_abr (struct ospf6 *o);
 
 extern void ospf6_abr_enable_area (struct ospf6_area *oa);
@@ -68,9 +70,11 @@ extern int ospf6_abr_originate_summary_to_area (struct 
ospf6_route *route,
                                                 struct ospf6_area *area);
 extern void ospf6_abr_originate_summary (struct ospf6_route *route);
 extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area 
*oa);
+extern void ospf6_abr_defaults_to_stub (struct ospf6 *);
 extern void ospf6_abr_examin_brouter (u_int32_t router_id);
 extern void ospf6_abr_reimport (struct ospf6_area *oa);
-extern void ospf6_abr_range_update (struct ospf6_route *range);
+extern void ospf6_abr_range_reset_cost (struct ospf6 *ospf6);
+extern void ospf6_abr_prefix_resummarize (struct ospf6 *ospf6);
 
 extern int config_write_ospf6_debug_abr (struct vty *vty);
 extern void install_element_ospf6_debug_abr (void);
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index b3cb17d..7178754 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -43,6 +43,7 @@
 #include "ospf6_interface.h"
 #include "ospf6_intra.h"
 #include "ospf6_abr.h"
+#include "ospf6_asbr.h"
 #include "ospf6d.h"
 
 int
@@ -133,12 +134,82 @@ ospf6_area_route_hook_remove (struct ospf6_route *route)
     ospf6_route_remove (copy, ospf6->route_table);
 }
 
+static void
+ospf6_area_stub_update (struct ospf6_area *area)
+{
+
+  if (IS_AREA_STUB (area))
+    {
+      if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+       zlog_debug ("Stubbing out area for if %s\n", area->name);
+      OSPF6_OPT_CLEAR (area->options, OSPF6_OPT_E);
+    }
+  else if (IS_AREA_ENABLED (area))
+    {
+      if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
+       zlog_debug ("Normal area for if %s\n", area->name);
+      OSPF6_OPT_SET (area->options, OSPF6_OPT_E);
+      ospf6_asbr_send_externals_to_area (area);
+    }
+
+  OSPF6_ROUTER_LSA_SCHEDULE(area);
+}
+
+static int
+ospf6_area_stub_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+  if (!IS_AREA_STUB(area))
+    {
+      SET_FLAG (area->flag, OSPF6_AREA_STUB);
+      ospf6_area_stub_update (area);
+    }
+
+  return (1);
+}
+
+static void
+ospf6_area_stub_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+  if (IS_AREA_STUB (area))
+    {
+      UNSET_FLAG (area->flag, OSPF6_AREA_STUB);
+      ospf6_area_stub_update (area);
+    }
+}
+
+static void
+ospf6_area_no_summary_set (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+  if (area)
+    {
+      if (!area->no_summary)
+       {
+         area->no_summary = 1;
+         ospf6_abr_range_reset_cost (ospf6);
+         ospf6_abr_prefix_resummarize (ospf6);
+       }
+    }
+}
+
+static void
+ospf6_area_no_summary_unset (struct ospf6 *ospf6, struct ospf6_area *area)
+{
+  if (area)
+    {
+      if (area->no_summary)
+       {
+         area->no_summary = 0;
+         ospf6_abr_range_reset_cost (ospf6);
+         ospf6_abr_prefix_resummarize (ospf6);
+       }
+    }
+}
+
 /* Make new area structure */
 struct ospf6_area *
 ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
 {
   struct ospf6_area *oa;
-  struct ospf6_route *route;
 
   oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
 
@@ -180,6 +251,9 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
 
   OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
 
+  SET_FLAG (oa->flag, OSPF6_AREA_ACTIVE);
+  SET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
+
   oa->ospf6 = o;
   listnode_add_sort (o->area_list, oa);
 
@@ -188,11 +262,6 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
       o->backbone = oa;
     }
 
-  /* import athoer area's routes as inter-area routes */
-  for (route = ospf6_route_head (o->route_table); route;
-       route = ospf6_route_next (route))
-    ospf6_abr_originate_summary_to_area (route, oa);
-
   return oa;
 }
 
@@ -294,16 +363,46 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
 {
   struct listnode *i;
   struct ospf6_interface *oi;
+  unsigned long result;
 
-  vty_out (vty, " Area %s%s", oa->name, VNL);
+  if (!IS_AREA_STUB (oa))
+    vty_out (vty, " Area %s%s", oa->name, VNL);
+  else
+    {
+      if (oa->no_summary)
+       {
+         vty_out (vty, " Area %s[Stub, No Summary]%s", oa->name, VNL);
+       }
+      else
+       {
+         vty_out (vty, " Area %s[Stub]%s", oa->name, VNL);
+       }
+    }
   vty_out (vty, "     Number of Area scoped LSAs is %u%s",
            oa->lsdb->count, VNL);
 
   vty_out (vty, "     Interface attached to this area:");
   for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
     vty_out (vty, " %s", oi->interface->name);
-  
   vty_out (vty, "%s", VNL);
+
+  if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec)
+    {
+      result = timeval_elapsed (recent_relative_time (), oa->ts_spf);
+      if (result/TIMER_SECOND_MICRO > 0)
+       {
+         vty_out (vty, "SPF last executed %ld.%lds ago%s",
+                  result/TIMER_SECOND_MICRO,
+                  result%TIMER_SECOND_MICRO, VTY_NEWLINE);
+       }
+      else
+       {
+         vty_out (vty, "SPF last executed %ldus ago%s",
+                  result, VTY_NEWLINE);
+       }
+    }
+  else
+    vty_out (vty, "SPF has not been run%s", VTY_NEWLINE);
 }
 
 
@@ -346,7 +445,7 @@ DEFUN (area_range,
   int ret;
   struct ospf6_area *oa;
   struct prefix prefix;
-  struct ospf6_route *range, *route;
+  struct ospf6_route *range;
   u_int32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
 
   OSPF6_CMD_AREA_GET (argv[0], oa);
@@ -398,9 +497,7 @@ DEFUN (area_range,
   if (ospf6_is_router_abr (ospf6))
     {
       /* Redo summaries if required */
-      for (route = ospf6_route_head (ospf6->route_table); route;
-          route = ospf6_route_next (route))
-       ospf6_abr_originate_summary(route);
+      ospf6_abr_prefix_resummarize (ospf6);
     }
 
   return CMD_SUCCESS;
@@ -503,6 +600,13 @@ ospf6_area_config_write (struct vty *vty)
           prefix2str (&range->prefix, buf, sizeof (buf));
           vty_out (vty, " area %s range %s%s", oa->name, buf, VNL);
         }
+      if (IS_AREA_STUB (oa))
+       {
+         if (oa->no_summary)
+           vty_out (vty, " area %s stub no-summary%s", oa->name, VNL);
+         else
+           vty_out (vty, " area %s stub%s", oa->name, VNL);
+       }
       if (PREFIX_NAME_IN (oa))
         vty_out (vty, " area %s filter-list prefix %s in%s",
                  oa->name, PREFIX_NAME_IN (oa), VNL);
@@ -846,6 +950,94 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
   return CMD_SUCCESS;
 }
 
+DEFUN (ospf6_area_stub,
+       ospf6_area_stub_cmd,
+       "area (A.B.C.D|<0-4294967295>) stub",
+       "OSPF6 area parameters\n"
+       "OSPF6 area ID in IP address format\n"
+       "OSPF6 area ID as a decimal value\n"
+       "Configure OSPF6 area as stub\n")
+{
+  struct ospf6_area *area;
+
+  OSPF6_CMD_AREA_GET(argv[0], area);
+
+  if (!ospf6_area_stub_set (ospf6, area))
+    {
+      vty_out (vty, "First deconfigure all virtual link through this area%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf6_area_no_summary_unset (ospf6, area);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_area_stub_no_summary,
+       ospf6_area_stub_no_summary_cmd,
+       "area (A.B.C.D|<0-4294967295>) stub no-summary",
+       "OSPF6 stub parameters\n"
+       "OSPF6 area ID in IP address format\n"
+       "OSPF6 area ID as a decimal value\n"
+       "Configure OSPF6 area as stub\n"
+       "Do not inject inter-area routes into stub\n")
+{
+  struct ospf6_area *area;
+
+  OSPF6_CMD_AREA_GET(argv[0], area);
+
+  if (!ospf6_area_stub_set (ospf6, area))
+    {
+      vty_out (vty, "First deconfigure all virtual link through this area%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ospf6_area_no_summary_set (ospf6, area);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub,
+       no_ospf6_area_stub_cmd,
+       "no area (A.B.C.D|<0-4294967295>) stub",
+       NO_STR
+       "OSPF6 area parameters\n"
+       "OSPF6 area ID in IP address format\n"
+       "OSPF6 area ID as a decimal value\n"
+       "Configure OSPF6 area as stub\n")
+{
+  struct ospf6_area *area;
+
+  OSPF6_CMD_AREA_GET(argv[0], area);
+
+  ospf6_area_stub_unset (ospf6, area);
+  ospf6_area_no_summary_unset (ospf6, area);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_area_stub_no_summary,
+       no_ospf6_area_stub_no_summary_cmd,
+       "no area (A.B.C.D|<0-4294967295>) stub no-summary",
+       NO_STR
+       "OSPF6 area parameters\n"
+       "OSPF6 area ID in IP address format\n"
+       "OSPF6 area ID as a decimal value\n"
+       "Configure OSPF6 area as stub\n"
+       "Do not inject inter-area routes into area\n")
+{
+  struct ospf6_area *area;
+
+  OSPF6_CMD_AREA_GET(argv[0], area);
+
+  ospf6_area_stub_unset (ospf6, area);
+  ospf6_area_no_summary_unset (ospf6, area);
+
+  return CMD_SUCCESS;
+}
+
 void
 ospf6_area_init (void)
 {
@@ -862,6 +1054,11 @@ ospf6_area_init (void)
   install_element (OSPF6_NODE, &area_range_cost_cmd);
   install_element (OSPF6_NODE, &area_range_advertise_cost_cmd);
   install_element (OSPF6_NODE, &no_area_range_cmd);
+  install_element (OSPF6_NODE, &ospf6_area_stub_no_summary_cmd);
+  install_element (OSPF6_NODE, &ospf6_area_stub_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_area_stub_no_summary_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_area_stub_cmd);
+
 
   install_element (OSPF6_NODE, &area_import_list_cmd);
   install_element (OSPF6_NODE, &no_area_import_list_cmd);
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index 6911869..3b752d9 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -46,6 +46,9 @@ struct ospf6_area
   struct ospf6_route_table *summary_prefix;
   struct ospf6_route_table *summary_router;
 
+  /* Area type */
+  int no_summary;
+
   /* OSPF interface list */
   struct list *if_list;
 
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 10ccb33..9f5337c 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -408,6 +408,23 @@ ospf6_asbr_redistribute_unset (int type)
   ospf6_asbr_routemap_unset (type);
 }
 
+/* When an area is unstubified, flood all the external LSAs in the area */
+void
+ospf6_asbr_send_externals_to_area (struct ospf6_area *oa)
+{
+  struct ospf6_lsa *lsa;
+
+  for (lsa = ospf6_lsdb_head (oa->ospf6->lsdb); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
+       {
+         zlog_debug ("%s: Flooding AS-External LSA %s\n", __func__, lsa->name);
+         ospf6_flood_area (NULL, lsa, oa);
+       }
+    }
+}
+
 void
 ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix,
                              u_int nexthop_num, struct in6_addr *nexthop)
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 73770cc..90befdc 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -91,6 +91,7 @@ extern int ospf6_redistribute_config_write (struct vty *vty);
 extern void ospf6_asbr_init (void);
 extern void ospf6_asbr_redistribute_reset (void);
 extern void ospf6_asbr_terminate (void);
+extern void ospf6_asbr_send_externals_to_area (struct ospf6_area *);
 
 extern int config_write_ospf6_debug_asbr (struct vty *vty);
 extern void install_element_ospf6_debug_asbr (void);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 9c1898d..82cf6a6 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -422,7 +422,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
     }
 }
 
-static void
+void
 ospf6_flood_area (struct ospf6_neighbor *from,
                   struct ospf6_lsa *lsa, struct ospf6_area *oa)
 {
diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h
index 3a6f300..ba7fd25 100644
--- a/ospf6d/ospf6_flood.h
+++ b/ospf6d/ospf6_flood.h
@@ -52,6 +52,8 @@ extern void ospf6_decrement_retrans_count (struct ospf6_lsa 
*lsa);
 /* flooding & clear flooding */
 extern void ospf6_flood_clear (struct ospf6_lsa *lsa);
 extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa);
+extern void ospf6_flood_area (struct ospf6_neighbor *from,
+                             struct ospf6_lsa *lsa, struct ospf6_area *oa);
 
 /* receive & install */
 extern void ospf6_receive_lsa (struct ospf6_neighbor *from,
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index c841155..c59902d 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -140,6 +140,31 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa 
*lsa)
   return 0;
 }
 
+static void
+ospf6_router_lsa_options_set (struct ospf6_area *oa,
+                             struct ospf6_router_lsa *router_lsa)
+{
+  OSPF6_OPT_CLEAR_ALL (router_lsa->options);
+  memcpy (router_lsa->options, oa->options, 3);
+
+  if (ospf6_is_router_abr (ospf6))
+    SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+  else
+    UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+
+  if (!IS_AREA_STUB (oa) && ospf6_asbr_is_asbr (oa->ospf6))
+    {
+      SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+    }
+  else
+    {
+      UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+    }
+
+  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
+  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+}
+
 int
 ospf6_router_is_stub_router (struct ospf6_lsa *lsa)
 {
@@ -194,23 +219,7 @@ ospf6_router_lsa_originate (struct thread *thread)
   router_lsa = (struct ospf6_router_lsa *)
     ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
 
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
-
-  if (ospf6_is_router_abr (ospf6))
-    SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
-  else
-    UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
-  if (ospf6_asbr_is_asbr (ospf6))
-    SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
-  else
-    UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
-  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
-  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+  ospf6_router_lsa_options_set (oa, router_lsa);
 
   /* describe links for each interfaces */
   lsdesc = (struct ospf6_router_lsdesc *)
@@ -1470,7 +1479,11 @@ ospf6_intra_route_calculation (struct ospf6_area *oa)
           if (hook_add)
             (*hook_add) (route);
         }
-
+      else
+       {
+         /* Redo the summaries as things might have changed */
+         ospf6_abr_originate_summary (route);
+       }
       route->flag = 0;
     }
 
@@ -1556,7 +1569,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
       inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
       if (brouter->path.area_id != oa->area_id)
         continue;
-      brouter->flag = OSPF6_ROUTE_REMOVE;
+      SET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE);
 
       if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
           IS_OSPF6_DEBUG_ROUTE (MEMORY))
@@ -1650,9 +1663,11 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
               IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
             zlog_info ("brouter %s still exists via area %s",
                        brouter_name, oa->name);
+          /* But re-originate summaries */
+         ospf6_abr_originate_summary (brouter);
         }
-
-      brouter->flag = 0;
+      UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD);
+      UNSET_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE);
     }
 
   if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index a85ca66..aa64a77 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -141,6 +141,7 @@ struct ospf6_lsa
 #define OSPF6_LSA_FLOODBACK  0x02
 #define OSPF6_LSA_DUPLICATE  0x04
 #define OSPF6_LSA_IMPLIEDACK 0x08
+#define OSPF6_LSA_UNAPPROVED 0x10
 #define OSPF6_LSA_SEQWRAPPED 0x20
 
 struct ospf6_lsa_handler
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 6664363..f4854b2 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -110,6 +110,10 @@ struct ospf6_path
 #define OSPF6_PATH_TYPE_REDISTRIBUTE 5
 #define OSPF6_PATH_TYPE_MAX          6
 
+#define OSPF6_PATH_SUBTYPE_DEFAULT_RT   1
+
+#define OSPF6_PATH_COST_IS_CONFIGURED(path) (path.u.cost_config != 
OSPF_AREA_RANGE_COST_UNSPEC)
+
 #include "prefix.h"
 #include "table.h"
 #include "bitfield.h"
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 9f56a1c..085f8f7 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -36,6 +36,8 @@
 #include "ospf6_lsdb.h"
 #include "ospf6_route.h"
 #include "ospf6_area.h"
+#include "ospf6_proto.h"
+#include "ospf6_abr.h"
 #include "ospf6_spf.h"
 #include "ospf6_intra.h"
 #include "ospf6_interface.h"
@@ -593,7 +595,6 @@ ospf6_spf_calculation_thread (struct thread *t)
   struct ospf6 *ospf6;
   struct timeval start, end, runtime;
   struct listnode *node;
-  struct ospf6_route *route;
   int areas_processed = 0;
   char rbuf[32];
 
@@ -603,6 +604,9 @@ ospf6_spf_calculation_thread (struct thread *t)
   /* execute SPF calculation */
   quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
 
+  if (ospf6_is_router_abr (ospf6))
+    ospf6_abr_range_reset_cost (ospf6);
+
   for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
     {
 
@@ -636,10 +640,8 @@ ospf6_spf_calculation_thread (struct thread *t)
       areas_processed++;
     }
 
-  /* Redo summaries if required */
-  for (route = ospf6_route_head (ospf6->route_table); route;
-       route = ospf6_route_next (route))
-    ospf6_abr_originate_summary(route);
+  if (ospf6_is_router_abr (ospf6))
+    ospf6_abr_defaults_to_stub (ospf6);
 
   quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
   timersub (&end, &start, &runtime);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 2d47317..ad5edbb 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -310,10 +310,6 @@ struct ospf_area
 
   /* Configured variables. */
   int external_routing;                 /* ExternalRoutingCapability. */
-#define OSPF_AREA_DEFAULT       0
-#define OSPF_AREA_STUB          1
-#define OSPF_AREA_NSSA          2
-#define OSPF_AREA_TYPE_MAX     3
   int no_summary;                       /* Don't inject summaries into stub.*/
   int shortcut_configured;              /* Area configured as shortcut. */
 #define OSPF_SHORTCUT_DEFAULT  0
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to