Browse Source

Merge volatile/cumulus_ospf6d

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
David Lamparter 6 years ago
parent
commit
e708ed69aa

+ 42 - 0
doc/ospf6d.texi

@@ -28,6 +28,44 @@ Bind interface to specified area, and start sending OSPF packets.  @var{area} ca
 be specified as 0.
 @end deffn
 
+@deffn {OSPF6 Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {}
+@deffnx {OSPF6 Command} {no timers throttle spf} {}
+This command sets the initial @var{delay}, the @var{initial-holdtime}
+and the @var{maximum-holdtime} between when SPF is calculated and the
+event which triggered the calculation. The times are specified in
+milliseconds and must be in the range of 0 to 600000 milliseconds.
+
+The @var{delay} specifies the minimum amount of time to delay SPF
+calculation (hence it affects how long SPF calculation is delayed after
+an event which occurs outside of the holdtime of any previous SPF
+calculation, and also serves as a minimum holdtime).
+
+Consecutive SPF calculations will always be seperated by at least
+'hold-time' milliseconds. The hold-time is adaptive and initially is
+set to the @var{initial-holdtime} configured with the above command.
+Events which occur within the holdtime of the previous SPF calculation
+will cause the holdtime to be increased by @var{initial-holdtime}, bounded
+by the @var{maximum-holdtime} configured with this command. If the adaptive
+hold-time elapses without any SPF-triggering event occuring then
+the current holdtime is reset to the @var{initial-holdtime}.
+
+@example
+@group
+router ospf6
+ timers throttle spf 200 400 10000
+@end group
+@end example
+
+In this example, the @var{delay} is set to 200ms, the @var{initial
+holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence
+there will always be at least 200ms between an event which requires SPF
+calculation and the actual SPF calculation. Further consecutive SPF
+calculations will always be seperated by between 400ms to 10s, the
+hold-time increasing by 400ms each time an SPF-triggering event occurs
+within the hold-time of the previous SPF calculation.
+
+@end deffn
+
 @node OSPF6 area
 @section OSPF6 area
 
@@ -60,6 +98,10 @@ Sets interface's Router Priority.  Default value is 1.
 Sets interface's Inf-Trans-Delay.  Default value is 1.
 @end deffn
 
+@deffn {Interface Command} {ipv6 ospf6 network (broadcast|point-to-point)} {}
+Set explicitly network type for specifed interface.
+@end deffn
+
 @node Redistribute routes to OSPF6
 @section Redistribute routes to OSPF6
 

+ 1 - 1
lib/Makefile.am

@@ -27,7 +27,7 @@ pkginclude_HEADERS = \
 	str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
 	plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
 	privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
-	workqueue.h route_types.h
+	workqueue.h route_types.h libospf.h
 
 EXTRA_DIST = \
 	regex.c regex-gnu.h \

+ 24 - 0
lib/if.c

@@ -304,6 +304,30 @@ if_lookup_address (struct in_addr src)
   return match;
 }
 
+/* Lookup interface by prefix */
+struct interface *
+if_lookup_prefix (struct prefix *prefix)
+{
+  struct listnode *node;
+  struct prefix addr;
+  int bestlen = 0;
+  struct listnode *cnode;
+  struct interface *ifp;
+  struct connected *c;
+
+  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+    {
+      for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+        {
+          if (prefix_cmp(c->address, prefix) == 0)
+            {
+              return ifp;
+            }
+        }
+    }
+  return NULL;
+}
+
 /* Get interface by name if given name interface doesn't exist create
    one. */
 struct interface *

+ 1 - 0
lib/if.h

@@ -245,6 +245,7 @@ extern struct interface *if_create (const char *name, int namelen);
 extern struct interface *if_lookup_by_index (unsigned int);
 extern struct interface *if_lookup_exact_address (struct in_addr);
 extern struct interface *if_lookup_address (struct in_addr);
+extern struct interface *if_lookup_prefix (struct prefix *prefix);
 
 /* These 2 functions are to be used when the ifname argument is terminated
    by a '\0' character: */

+ 92 - 0
lib/libospf.h

@@ -0,0 +1,92 @@
+/*
+ * Defines and structures common to OSPFv2 and OSPFv3
+ * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _LIBOSPFD_H
+#define _LIBOSPFD_H
+
+/* IP precedence. */
+#ifndef IPTOS_PREC_INTERNETCONTROL
+#define IPTOS_PREC_INTERNETCONTROL	0xC0
+#endif /* IPTOS_PREC_INTERNETCONTROL */
+
+/* Default protocol, port number. */
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP         89
+#endif /* IPPROTO_OSPFIGP */
+
+/* Architectual Constants */
+#ifdef DEBUG
+#define OSPF_LS_REFRESH_TIME                    60
+#else
+#define OSPF_LS_REFRESH_TIME                  1800
+#endif
+#define OSPF_MIN_LS_INTERVAL                     5
+#define OSPF_MIN_LS_ARRIVAL                      1
+#define OSPF_LSA_INITIAL_AGE                     0	/* useful for debug */
+#define OSPF_LSA_MAXAGE                       3600
+#define OSPF_CHECK_AGE                         300
+#define OSPF_LSA_MAXAGE_DIFF                   900
+#define OSPF_LS_INFINITY                  0xffffff
+#define OSPF_DEFAULT_DESTINATION        0x00000000      /* 0.0.0.0 */
+#define OSPF_INITIAL_SEQUENCE_NUMBER    0x80000001
+#define OSPF_MAX_SEQUENCE_NUMBER        0x7fffffff
+
+/* OSPF Interface Types */
+#define OSPF_IFTYPE_NONE		0
+#define OSPF_IFTYPE_POINTOPOINT		1
+#define OSPF_IFTYPE_BROADCAST		2
+#define OSPF_IFTYPE_NBMA		3
+#define OSPF_IFTYPE_POINTOMULTIPOINT	4
+#define OSPF_IFTYPE_VIRTUALLINK		5
+#define OSPF_IFTYPE_LOOPBACK            6
+#define OSPF_IFTYPE_MAX			7
+
+/* OSPF interface default values. */
+#define OSPF_OUTPUT_COST_DEFAULT           10
+#define OSPF_OUTPUT_COST_INFINITE	   UINT16_MAX
+#define OSPF_ROUTER_DEAD_INTERVAL_DEFAULT  40
+#define OSPF_ROUTER_DEAD_INTERVAL_MINIMAL   1
+#define OSPF_HELLO_INTERVAL_DEFAULT        10
+#define OSPF_ROUTER_PRIORITY_DEFAULT        1
+#define OSPF_RETRANSMIT_INTERVAL_DEFAULT    5
+#define OSPF_TRANSMIT_DELAY_DEFAULT         1
+#define OSPF_DEFAULT_BANDWIDTH		 10000	/* Kbps */
+
+#define OSPF_DEFAULT_REF_BANDWIDTH	100000  /* Kbps */
+
+#define OSPF_POLL_INTERVAL_DEFAULT         60
+#define OSPF_NEIGHBOR_PRIORITY_DEFAULT      0
+
+#define OSPF_MTU_IGNORE_DEFAULT             0
+#define OSPF_FAST_HELLO_DEFAULT             0
+
+#define OSPF_AREA_BACKBONE              0x00000000      /* 0.0.0.0 */
+
+/* SPF Throttling timer values. */
+#define OSPF_SPF_DELAY_DEFAULT              200
+#define OSPF_SPF_HOLDTIME_DEFAULT           1000
+#define OSPF_SPF_MAX_HOLDTIME_DEFAULT	    10000
+
+#define OSPF_LSA_MAXAGE_CHECK_INTERVAL		30
+#define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT	60
+
+#endif /* _LIBOSPFD_H */

+ 85 - 15
ospf6d/ospf6_abr.c

@@ -253,7 +253,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
     }
 
   /* do not generate if the route cost is greater or equal to LSInfinity */
-  if (route->path.cost >= LS_INFINITY)
+  if (route->path.cost >= OSPF_LS_INFINITY)
     {
       if (is_debug)
         zlog_debug ("The cost exceeds LSInfinity, withdraw");
@@ -296,7 +296,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
       /* ranges are ignored when originate backbone routes to transit area.
          Otherwise, if ranges are configured, the route is suppressed. */
       if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) &&
-          (route->path.area_id != BACKBONE_AREA_ID ||
+          (route->path.area_id != OSPF_AREA_BACKBONE ||
            ! IS_AREA_TRANSIT (area)))
         {
           if (is_debug)
@@ -537,13 +537,13 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
   int i;
   char buf[64];
   int is_debug = 0;
+  struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
+  struct ospf6_inter_router_lsa *router_lsa = NULL;
 
   memset (&prefix, 0, sizeof (prefix));
 
   if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
     {
-      struct ospf6_inter_prefix_lsa *prefix_lsa;
-
       if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX))
         {
           is_debug++;
@@ -564,8 +564,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
     }
   else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER))
     {
-      struct ospf6_inter_router_lsa *router_lsa;
-
       if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER))
         {
           is_debug++;
@@ -604,7 +602,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
     }
 
   /* (1) if cost == LSInfinity or if the LSA is MaxAge */
-  if (cost == LS_INFINITY)
+  if (cost == OSPF_LS_INFINITY)
     {
       if (is_debug)
         zlog_debug ("cost is LS_INFINITY, ignore");
@@ -632,6 +630,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
     }
 
   /* (3) if the prefix is equal to an active configured address range */
+  /*     or if the NU bit is set in the prefix */
   if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX))
     {
       range = ospf6_route_lookup (&prefix, oa->range_table);
@@ -643,6 +642,32 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
             ospf6_route_remove (old, table);
           return;
         }
+
+      if (CHECK_FLAG (prefix_lsa->prefix.prefix_options,
+		      OSPF6_PREFIX_OPTION_NU) ||
+	  CHECK_FLAG (prefix_lsa->prefix.prefix_options,
+		      OSPF6_PREFIX_OPTION_LA))
+	{
+          if (is_debug)
+            zlog_debug ("Prefix has NU/LA bit set, ignore");
+          if (old)
+            ospf6_route_remove (old, table);
+          return;
+	}
+    }
+
+  if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER))
+    {
+      /* To pass test suites */
+      if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) ||
+	  ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6))
+	{
+          if (is_debug)
+            zlog_debug ("Prefix has NU/LA bit set, ignore");
+          if (old)
+            ospf6_route_remove (old, table);
+          return;
+	}
     }
 
   /* (4) if the routing table entry for the ABR does not exist */
@@ -764,12 +789,34 @@ ospf6_abr_reimport (struct ospf6_area *oa)
 
 
 /* Display functions */
+static char *
+ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf,
+					    int buflen, int pos)
+{
+  struct ospf6_inter_prefix_lsa *prefix_lsa;
+  struct in6_addr in6;
+
+  if (lsa != NULL)
+    {
+      prefix_lsa = (struct ospf6_inter_prefix_lsa *)
+	OSPF6_LSA_HEADER_END (lsa->header);
+
+      ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix);
+      if (buf)
+	{
+	  inet_ntop (AF_INET6, &in6, buf, buflen);
+	  sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length);
+	}
+    }
+
+  return (buf);
+}
+
 static int
 ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
   struct ospf6_inter_prefix_lsa *prefix_lsa;
-  struct in6_addr in6;
-  char buf[64];
+  char buf[INET6_ADDRSTRLEN];
 
   prefix_lsa = (struct ospf6_inter_prefix_lsa *)
     OSPF6_LSA_HEADER_END (lsa->header);
@@ -781,14 +828,32 @@ ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
                                  buf, sizeof (buf));
   vty_out (vty, "     Prefix Options: %s%s", buf, VNL);
 
-  ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix);
-  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-  vty_out (vty, "     Prefix: %s/%d%s", buf,
-           prefix_lsa->prefix.prefix_length, VNL);
+  vty_out (vty, "     Prefix: %s%s",
+	   ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf),
+						       0), VNL);
 
   return 0;
 }
 
+static char *
+ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf,
+					    int buflen, int pos)
+{
+  struct ospf6_inter_router_lsa *router_lsa;
+
+  if (lsa != NULL)
+    {
+      router_lsa = (struct ospf6_inter_router_lsa *)
+	OSPF6_LSA_HEADER_END (lsa->header);
+
+
+      if (buf)
+	inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen);
+    }
+
+  return (buf);
+}
+
 static int
 ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
@@ -802,6 +867,7 @@ ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
   vty_out (vty, "     Options: %s%s", buf, VNL);
   vty_out (vty, "     Metric: %lu%s",
            (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL);
+
   inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf));
   vty_out (vty, "     Destination Router ID: %s%s", buf, VNL);
 
@@ -855,14 +921,18 @@ struct ospf6_lsa_handler inter_prefix_handler =
 {
   OSPF6_LSTYPE_INTER_PREFIX,
   "Inter-Prefix",
-  ospf6_inter_area_prefix_lsa_show
+  "IAP",
+  ospf6_inter_area_prefix_lsa_show,
+  ospf6_inter_area_prefix_lsa_get_prefix_str,
 };
 
 struct ospf6_lsa_handler inter_router_handler =
 {
   OSPF6_LSTYPE_INTER_ROUTER,
   "Inter-Router",
-  ospf6_inter_area_router_lsa_show
+  "IAR",
+  ospf6_inter_area_router_lsa_show,
+  ospf6_inter_area_router_lsa_get_prefix_str,
 };
 
 void

+ 39 - 10
ospf6d/ospf6_area.c

@@ -67,7 +67,8 @@ ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa)
           zlog_debug ("Schedule SPF Calculation for %s",
 		      OSPF6_AREA (lsa->lsdb->data)->name);
         }
-      ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data));
+      ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6),
+			  ospf6_lsadd_to_spf_reason(lsa));
       break;
 
     case OSPF6_LSTYPE_INTRA_PREFIX:
@@ -97,7 +98,8 @@ ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa)
           zlog_debug ("Schedule SPF Calculation for %s",
                      OSPF6_AREA (lsa->lsdb->data)->name);
         }
-      ospf6_spf_schedule (OSPF6_AREA (lsa->lsdb->data));
+      ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6),
+			  ospf6_lsremove_to_spf_reason(lsa));
       break;
 
     case OSPF6_LSTYPE_INTRA_PREFIX:
@@ -164,9 +166,18 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
   oa->summary_router->scope = oa;
 
   /* set default options */
-  OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6);
+  if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER))
+    {
+      OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6);
+      OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R);
+    }
+  else
+    {
+      OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6);
+      OSPF6_OPT_SET (oa->options, OSPF6_OPT_R);
+    }
+
   OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
-  OSPF6_OPT_SET (oa->options, OSPF6_OPT_R);
 
   oa->ospf6 = o;
   listnode_add_sort (o->area_list, oa);
@@ -182,18 +193,21 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
 void
 ospf6_area_delete (struct ospf6_area *oa)
 {
-  struct listnode *n, *nnode;
+  struct listnode *n;
   struct ospf6_interface *oi;
 
   ospf6_route_table_delete (oa->range_table);
   ospf6_route_table_delete (oa->summary_prefix);
   ospf6_route_table_delete (oa->summary_router);
 
-  /* ospf6 interface list */
-  for (ALL_LIST_ELEMENTS (oa->if_list, n, nnode, oi))
-    {
-      ospf6_interface_delete (oi);
-    }
+  /* The ospf6_interface structs store configuration
+   * information which should not be lost/reset when
+   * deleting an area.
+   * So just detach the interface from the area and
+   * keep it around. */
+  for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi))
+    oi->area = NULL;
+
   list_delete (oa->if_list);
 
   ospf6_lsdb_delete (oa->lsdb);
@@ -246,6 +260,7 @@ ospf6_area_enable (struct ospf6_area *oa)
 
   for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
     ospf6_interface_enable (oi);
+  ospf6_abr_enable_area (oa);
 }
 
 void
@@ -258,6 +273,19 @@ ospf6_area_disable (struct ospf6_area *oa)
 
   for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
     ospf6_interface_disable (oi);
+
+  ospf6_abr_disable_area (oa);
+  ospf6_lsdb_remove_all (oa->lsdb);
+  ospf6_lsdb_remove_all (oa->lsdb_self);
+
+  ospf6_spf_table_finish(oa->spf_table);
+  ospf6_route_remove_all(oa->route_table);
+
+  THREAD_OFF (oa->thread_spf_calculation);
+  THREAD_OFF (oa->thread_route_calculation);
+
+  THREAD_OFF (oa->thread_router_lsa);
+  THREAD_OFF (oa->thread_intra_prefix_lsa);
 }
 
 
@@ -401,6 +429,7 @@ DEFUN (no_area_range,
     }
 
   ospf6_route_remove (range, oa->range_table);
+
   return CMD_SUCCESS;
 }
 

+ 0 - 2
ospf6d/ospf6_area.h

@@ -105,8 +105,6 @@ struct ospf6_area
 #define OSPF6_AREA_TRANSIT    0x04 /* TransitCapability */
 #define OSPF6_AREA_STUB       0x08
 
-#define BACKBONE_AREA_ID (htonl (0))
-#define IS_AREA_BACKBONE(oa) ((oa)->area_id == BACKBONE_AREA_ID)
 #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE))
 #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE))
 #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT))

+ 66 - 15
ospf6d/ospf6_asbr.c

@@ -174,13 +174,20 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
       return;
     }
 
-  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+  if (OSPF6_ASBR_METRIC (external) == OSPF_LS_INFINITY)
     {
       if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
         zlog_debug ("Ignore LSA with LSInfinity Metric");
       return;
     }
 
+  if (CHECK_FLAG(external->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU))
+    {
+      if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
+        zlog_debug ("Ignore LSA with NU bit set Metric");
+      return;
+    }
+
   ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id);
   asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table);
   if (asbr_entry == NULL ||
@@ -402,6 +409,8 @@ ospf6_asbr_redistribute_unset (int type)
       ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
                                       &route->prefix);
     }
+
+  ospf6_asbr_routemap_unset (type);
 }
 
 void
@@ -629,7 +638,6 @@ DEFUN (ospf6_redistribute,
     return CMD_WARNING;
 
   ospf6_asbr_redistribute_unset (type);
-  ospf6_asbr_routemap_unset (type);
   ospf6_asbr_redistribute_set (type);
   return CMD_SUCCESS;
 }
@@ -670,7 +678,6 @@ DEFUN (no_ospf6_redistribute,
     return CMD_WARNING;
 
   ospf6_asbr_redistribute_unset (type);
-  ospf6_asbr_routemap_unset (type);
 
   return CMD_SUCCESS;
 }
@@ -890,7 +897,7 @@ ospf6_routemap_rule_set_metric_compile (const char *arg)
   u_int32_t metric;
   char *endp;
   metric = strtoul (arg, &endp, 0);
-  if (metric > LS_INFINITY || *endp != '\0')
+  if (metric > OSPF_LS_INFINITY || *endp != '\0')
     return NULL;
   return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
 }
@@ -1161,12 +1168,44 @@ ospf6_routemap_init (void)
 
 
 /* Display functions */
+static char *
+ospf6_as_external_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf,
+				      int buflen, int pos)
+{
+  struct ospf6_as_external_lsa *external;
+  struct in6_addr in6;
+  int prefix_length = 0;
+
+  if (lsa)
+    {
+        external = (struct ospf6_as_external_lsa *)
+	  OSPF6_LSA_HEADER_END (lsa->header);
+
+	if (pos == 0)
+	  {
+	    ospf6_prefix_in6_addr (&in6, &external->prefix);
+	    prefix_length = external->prefix.prefix_length;
+	  }
+	else {
+	  in6 = *((struct in6_addr *)
+		  ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) +
+		   OSPF6_PREFIX_SPACE (external->prefix.prefix_length)));
+	}
+	if (buf)
+	  {
+	    inet_ntop (AF_INET6, &in6, buf, buflen);
+	    if (prefix_length)
+	      sprintf (&buf[strlen(buf)], "/%d", prefix_length);
+	  }
+    }
+  return (buf);
+}
+
 static int
 ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
   struct ospf6_as_external_lsa *external;
   char buf[64];
-  struct in6_addr in6, *forwarding;
 
   assert (lsa->header);
   external = (struct ospf6_as_external_lsa *)
@@ -1191,19 +1230,15 @@ ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
            ntohs (external->prefix.prefix_refer_lstype),
            VNL);
 
-  ospf6_prefix_in6_addr (&in6, &external->prefix);
-  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-  vty_out (vty, "     Prefix: %s/%d%s", buf,
-           external->prefix.prefix_length, VNL);
+  vty_out (vty, "     Prefix: %s%s",
+	   ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL);
 
   /* Forwarding-Address */
   if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
     {
-      forwarding = (struct in6_addr *)
-        ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) +
-         OSPF6_PREFIX_SPACE (external->prefix.prefix_length));
-      inet_ntop (AF_INET6, forwarding, buf, sizeof (buf));
-      vty_out (vty, "     Forwarding-Address: %s%s", buf, VNL);
+      vty_out (vty, "     Forwarding-Address: %s%s",
+	       ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 1),
+	       VNL);
     }
 
   return 0;
@@ -1257,7 +1292,9 @@ struct ospf6_lsa_handler as_external_handler =
 {
   OSPF6_LSTYPE_AS_EXTERNAL,
   "AS-External",
-  ospf6_as_external_lsa_show
+  "ASE",
+  ospf6_as_external_lsa_show,
+  ospf6_as_external_lsa_get_prefix_str
 };
 
 void
@@ -1276,6 +1313,20 @@ ospf6_asbr_init (void)
 }
 
 void
+ospf6_asbr_redistribute_reset (void)
+{
+  int type;
+
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+    {
+      if (type == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (ospf6_zebra_is_redistribute (type))
+        ospf6_asbr_redistribute_unset(type);
+    }
+}
+
+void
 ospf6_asbr_terminate (void)
 {
   route_map_finish ();

+ 1 - 0
ospf6d/ospf6_asbr.h

@@ -89,6 +89,7 @@ extern void ospf6_asbr_redistribute_remove (int type, int ifindex,
 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 int config_write_ospf6_debug_asbr (struct vty *vty);

+ 63 - 37
ospf6d/ospf6_flood.c

@@ -113,7 +113,7 @@ ospf6_lsa_originate (struct ospf6_lsa *lsa)
   ospf6_lsdb_add (ospf6_lsa_copy (lsa), lsdb_self);
 
   lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
-                                   LS_REFRESH_TIME);
+                                   OSPF_LS_REFRESH_TIME);
 
   if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) ||
       IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type))
@@ -122,10 +122,8 @@ ospf6_lsa_originate (struct ospf6_lsa *lsa)
       ospf6_lsa_header_print (lsa);
     }
 
-  if (old)
-    ospf6_flood_clear (old);
-  ospf6_flood (NULL, lsa);
   ospf6_install_lsa (lsa);
+  ospf6_flood (NULL, lsa);
 }
 
 void
@@ -208,8 +206,8 @@ ospf6_decrement_retrans_count (struct ospf6_lsa *lsa)
 void
 ospf6_install_lsa (struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa *old;
   struct timeval now;
+  struct ospf6_lsa *old;
 
   if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) ||
       IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
@@ -222,16 +220,36 @@ ospf6_install_lsa (struct ospf6_lsa *lsa)
   if (old)
     {
       THREAD_OFF (old->expire);
+      THREAD_OFF (old->refresh);
       ospf6_flood_clear (old);
     }
 
   quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
   if (! OSPF6_LSA_IS_MAXAGE (lsa))
     lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
-                                    MAXAGE + lsa->birth.tv_sec - now.tv_sec);
+                                    OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec);
   else
     lsa->expire = NULL;
 
+  if (OSPF6_LSA_IS_SEQWRAP(lsa) &&
+      ! (CHECK_FLAG(lsa->flag,OSPF6_LSA_SEQWRAPPED) &&
+         lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)))
+   {
+     if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type))
+       zlog_debug("lsa install wrapping: sequence 0x%x",
+                  ntohl(lsa->header->seqnum));
+     SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
+     /* in lieu of premature_aging, since we do not want to recreate this lsa
+      * and/or mess with timers etc, we just want to wrap the sequence number
+      * and reflood the lsa before continuing.
+      * NOTE: Flood needs to be called right after this function call, by the
+      * caller
+      */
+     lsa->header->seqnum = htonl (OSPF_MAX_SEQUENCE_NUMBER);
+     lsa->header->age = htons (OSPF_LSA_MAXAGE);
+     ospf6_lsa_checksum (lsa->header);
+   }
+
   /* actually install */
   lsa->installed = now;
   ospf6_lsdb_add (lsa, lsa->lsdb);
@@ -292,7 +310,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
               if (ospf6_lsa_compare (lsa, req) > 0)
                 {
                   if (is_debug)
-                    zlog_debug ("Requesting is newer, next neighbor");
+                    zlog_debug ("Requesting is older, next neighbor");
                   continue;
                 }
 
@@ -300,18 +318,30 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
                  examin next neighbor */
               if (ospf6_lsa_compare (lsa, req) == 0)
                 {
-                  if (is_debug)
-                    zlog_debug ("Requesting the same, remove it, next neighbor");
+		  if (is_debug)
+		    zlog_debug ("Requesting the same, remove it, next neighbor");
+		  if (req == on->last_ls_req)
+		    {
+		      ospf6_lsa_unlock (req);
+		      on->last_ls_req = NULL;
+		    }
                   ospf6_lsdb_remove (req, on->request_list);
+		  ospf6_check_nbr_loading (on);
                   continue;
                 }
 
               /* If the new LSA is more recent, delete from request-list */
               if (ospf6_lsa_compare (lsa, req) < 0)
                 {
-                  if (is_debug)
-                    zlog_debug ("Received is newer, remove requesting");
+		  if (is_debug)
+		    zlog_debug ("Received is newer, remove requesting");
+		  if (req == on->last_ls_req)
+		    {
+		      ospf6_lsa_unlock (req);
+		      on->last_ls_req = NULL;
+		    }
                   ospf6_lsdb_remove (req, on->request_list);
+		  ospf6_check_nbr_loading (on);
                   /* fall through */
                 }
             }
@@ -358,17 +388,22 @@ ospf6_flood_interface (struct ospf6_neighbor *from,
 
   /* (4) If the new LSA was received on this interface,
      and the interface state is BDR, examin next interface */
-  if (from && from->ospf6_if == oi && oi->state == OSPF6_INTERFACE_BDR)
+  if (from && from->ospf6_if == oi)
     {
-      if (is_debug)
-        zlog_debug ("Received is from the I/F, itself BDR, next interface");
-      return;
+      if (oi->state == OSPF6_INTERFACE_BDR)
+	{
+	  if (is_debug)
+	    zlog_debug ("Received is from the I/F, itself BDR, next interface");
+	  return;
+	}
+      SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK);
     }
 
   /* (5) flood the LSA out the interface. */
   if (is_debug)
     zlog_debug ("Schedule flooding for the interface");
-  if (if_is_broadcast (oi->interface))
+  if ((oi->type == OSPF_IFTYPE_BROADCAST) ||
+      (oi->type == OSPF_IFTYPE_POINTOPOINT))
     {
       ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list);
       if (oi->thread_send_lsupdate == NULL)
@@ -530,15 +565,6 @@ ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent,
   assert (from && from->ospf6_if);
   oi = from->ospf6_if;
 
-  /* LSA has been flood back out receiving interface.
-     No acknowledgement sent. */
-  if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK))
-    {
-      if (is_debug)
-        zlog_debug ("No acknowledgement (BDR & FloodBack)");
-      return;
-    }
-
   /* LSA is more recent than database copy, but was not flooded
      back out receiving interface. Delayed acknowledgement sent
      if advertisement received from Designated Router,
@@ -797,7 +823,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
     {
       /* log */
       if (is_debug)
-        zlog_debug ("Drop MaxAge LSA with direct acknowledgement.");
+	zlog_debug ("Drop MaxAge LSA with direct acknowledgement.");
 
       /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */
       ospf6_lsdb_add (ospf6_lsa_copy (new), from->lsack_list);
@@ -837,7 +863,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
           struct timeval now, res;
           quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
           timersub (&now, &old->installed, &res);
-          if (res.tv_sec < MIN_LS_ARRIVAL)
+          if (res.tv_sec < OSPF_MIN_LS_ARRIVAL)
             {
               if (is_debug)
                 zlog_debug ("LSA can't be updated within MinLSArrival, discard");
@@ -849,7 +875,11 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
       quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received);
 
       if (is_debug)
-        zlog_debug ("Flood, Install, Possibly acknowledge the received LSA");
+        zlog_debug ("Install, Flood, Possibly acknowledge the received LSA");
+
+      /* Remove older copies of this LSA from retx lists */
+      if (old)
+	ospf6_flood_clear (old);
 
       /* (b) immediately flood and (c) remove from all retrans-list */
       /* Prevent self-originated LSA to be flooded. this is to make
@@ -858,10 +888,6 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
       if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id)
         ospf6_flood (from, new);
 
-      /* (c) Remove the current database copy from all neighbors' Link
-             state retransmission lists. */
-      /* XXX, flood_clear ? */
-
       /* (d), installing lsdb, which may cause routing
               table calculation (replacing database copy) */
       ospf6_install_lsa (new);
@@ -944,15 +970,15 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
       /* If database copy is in 'Seqnumber Wrapping',
          simply discard the received LSA */
       if (OSPF6_LSA_IS_MAXAGE (old) &&
-          old->header->seqnum == htonl (MAX_SEQUENCE_NUMBER))
+          old->header->seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER))
         {
           if (is_debug)
             {
               zlog_debug ("The LSA is in Seqnumber Wrapping");
               zlog_debug ("MaxAge & MaxSeqNum, discard");
             }
-          ospf6_lsa_delete (new);
-          return;
+	  ospf6_lsa_delete (new);
+	  return;
         }
 
       /* Otherwise, Send database copy of this LSA to this neighbor */
@@ -969,8 +995,8 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
           if (from->thread_send_lsupdate == NULL)
             from->thread_send_lsupdate =
               thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0);
-          ospf6_lsa_delete (new);
-          return;
+	  ospf6_lsa_delete (new);
+	  return;
         }
       return;
     }

+ 179 - 27
ospf6d/ospf6_interface.c

@@ -73,14 +73,20 @@ ospf6_interface_lookup_by_ifindex (int ifindex)
 
 /* schedule routing table recalculation */
 static void
-ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa)
+ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa, unsigned int reason)
 {
+  struct ospf6_interface *oi;
+
+  if (lsa == NULL)
+    return;
+
+  oi = lsa->lsdb->data;
   switch (ntohs (lsa->header->type))
     {
       case OSPF6_LSTYPE_LINK:
-        if (OSPF6_INTERFACE (lsa->lsdb->data)->state == OSPF6_INTERFACE_DR)
-          OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (OSPF6_INTERFACE (lsa->lsdb->data));
-        ospf6_spf_schedule (OSPF6_INTERFACE (lsa->lsdb->data)->area);
+        if (oi->state == OSPF6_INTERFACE_DR)
+          OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+        ospf6_spf_schedule (oi->area->ospf6, reason);
         break;
 
       default:
@@ -88,6 +94,29 @@ ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa)
     }
 }
 
+static void
+ospf6_interface_lsdb_hook_add (struct ospf6_lsa *lsa)
+{
+  ospf6_interface_lsdb_hook(lsa, ospf6_lsadd_to_spf_reason(lsa));
+}
+
+static void
+ospf6_interface_lsdb_hook_remove (struct ospf6_lsa *lsa)
+{
+  ospf6_interface_lsdb_hook(lsa, ospf6_lsremove_to_spf_reason(lsa));
+}
+
+static u_char
+ospf6_default_iftype(struct interface *ifp)
+{
+  if (if_is_pointopoint (ifp))
+    return OSPF_IFTYPE_POINTOPOINT;
+  else if (if_is_loopback (ifp))
+    return OSPF_IFTYPE_LOOPBACK;
+  else
+    return OSPF_IFTYPE_BROADCAST;
+}
+
 /* Create new ospf6 interface structure */
 struct ospf6_interface *
 ospf6_interface_create (struct interface *ifp)
@@ -112,10 +141,11 @@ ospf6_interface_create (struct interface *ifp)
   oi->transdelay = OSPF6_INTERFACE_TRANSDELAY;
   oi->priority = OSPF6_INTERFACE_PRIORITY;
 
-  oi->hello_interval = OSPF6_INTERFACE_HELLO_INTERVAL;
-  oi->dead_interval = OSPF6_INTERFACE_DEAD_INTERVAL;
-  oi->rxmt_interval = OSPF6_INTERFACE_RXMT_INTERVAL;
+  oi->hello_interval = OSPF_HELLO_INTERVAL_DEFAULT;
+  oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT;
+  oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT;
   oi->cost = OSPF6_INTERFACE_COST;
+  oi->type = ospf6_default_iftype (ifp);
   oi->state = OSPF6_INTERFACE_DOWN;
   oi->flag = 0;
   oi->mtu_ignore = 0;
@@ -134,8 +164,8 @@ ospf6_interface_create (struct interface *ifp)
   oi->lsupdate_list = ospf6_lsdb_create (oi);
   oi->lsack_list = ospf6_lsdb_create (oi);
   oi->lsdb = ospf6_lsdb_create (oi);
-  oi->lsdb->hook_add = ospf6_interface_lsdb_hook;
-  oi->lsdb->hook_remove = ospf6_interface_lsdb_hook;
+  oi->lsdb->hook_add = ospf6_interface_lsdb_hook_add;
+  oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove;
   oi->lsdb_self = ospf6_lsdb_create (oi);
 
   oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES);
@@ -189,31 +219,28 @@ void
 ospf6_interface_enable (struct ospf6_interface *oi)
 {
   UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
-
-  oi->thread_send_hello =
-    thread_add_event (master, ospf6_hello_send, oi, 0);
+  ospf6_interface_state_update (oi->interface);
 }
 
 void
 ospf6_interface_disable (struct ospf6_interface *oi)
 {
-  struct listnode *node, *nnode;
-  struct ospf6_neighbor *on;
-
   SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
 
-  for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on))
-      ospf6_neighbor_delete (on);
-
-  list_delete_all_node (oi->neighbor_list);
+  thread_execute (master, interface_down, oi, 0);
 
   ospf6_lsdb_remove_all (oi->lsdb);
+  ospf6_lsdb_remove_all (oi->lsdb_self);
   ospf6_lsdb_remove_all (oi->lsupdate_list);
   ospf6_lsdb_remove_all (oi->lsack_list);
 
   THREAD_OFF (oi->thread_send_hello);
   THREAD_OFF (oi->thread_send_lsupdate);
   THREAD_OFF (oi->thread_send_lsack);
+
+  THREAD_OFF (oi->thread_network_lsa);
+  THREAD_OFF (oi->thread_link_lsa);
+  THREAD_OFF (oi->thread_intra_prefix_lsa);
 }
 
 static struct in6_addr *
@@ -260,8 +287,7 @@ ospf6_interface_if_add (struct interface *ifp)
     }
 
   /* interface start */
-  if (oi->area)
-    thread_add_event (master, interface_up, oi, 0);
+  ospf6_interface_state_update(oi->interface);
 }
 
 void
@@ -297,8 +323,12 @@ ospf6_interface_state_update (struct interface *ifp)
     return;
   if (oi->area == NULL)
     return;
+  if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
+    return;
 
-  if (if_is_up (ifp))
+  if (if_is_operative (ifp)
+      && (ospf6_interface_get_linklocal_address(oi->interface)
+          || if_is_loopback(oi->interface)))
     thread_add_event (master, interface_up, oi, 0);
   else
     thread_add_event (master, interface_down, oi, 0);
@@ -325,6 +355,9 @@ ospf6_interface_connected_route_update (struct interface *ifp)
   if (oi->area == NULL)
     return;
 
+  if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
+    return;
+
   /* update "route to advertise" interface route table */
   ospf6_route_remove_all (oi->route_connected);
 
@@ -401,6 +434,7 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi)
       (next_state != OSPF6_INTERFACE_DR &&
        next_state != OSPF6_INTERFACE_BDR))
     ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP);
+
   if ((prev_state != OSPF6_INTERFACE_DR &&
        prev_state != OSPF6_INTERFACE_BDR) &&
       (next_state == OSPF6_INTERFACE_DR ||
@@ -606,7 +640,7 @@ interface_up (struct thread *thread)
 		oi->interface->name);
 
   /* check physical interface is up */
-  if (! if_is_up (oi->interface))
+  if (! if_is_operative (oi->interface))
     {
       if (IS_OSPF6_DEBUG_INTERFACE)
         zlog_debug ("Interface %s is down, can't execute [InterfaceUp]",
@@ -614,6 +648,16 @@ interface_up (struct thread *thread)
       return 0;
     }
 
+  /* check interface has a link-local address */
+  if (! (ospf6_interface_get_linklocal_address(oi->interface)
+         || if_is_loopback(oi->interface)))
+    {
+      if (IS_OSPF6_DEBUG_INTERFACE)
+	zlog_debug ("Interface %s has no link local address, can't execute [InterfaceUp]",
+		    oi->interface->name);
+	return 0;
+    }
+
   /* if already enabled, do nothing */
   if (oi->state > OSPF6_INTERFACE_DOWN)
     {
@@ -623,6 +667,14 @@ interface_up (struct thread *thread)
       return 0;
     }
 
+  /* If no area assigned, return */
+  if (oi->area == NULL)
+    {
+      zlog_debug ("%s: Not scheduleing Hello for %s as there is no area assigned yet", __func__,
+		  oi->interface->name);
+      return 0;
+    }
+
   /* Join AllSPFRouters */
   ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP);
 
@@ -631,11 +683,13 @@ interface_up (struct thread *thread)
 
   /* Schedule Hello */
   if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
-    thread_add_event (master, ospf6_hello_send, oi, 0);
+    oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0);
 
   /* decide next interface state */
-  if (if_is_pointopoint (oi->interface))
+  if ((if_is_pointopoint (oi->interface)) ||
+      (oi->type == OSPF_IFTYPE_POINTOPOINT)) {
     ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi);
+  }
   else if (oi->priority == 0)
     ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi);
   else
@@ -717,6 +771,9 @@ interface_down (struct thread *thread)
     zlog_debug ("Interface Event %s: [InterfaceDown]",
 		oi->interface->name);
 
+  /* Stop Hellos */
+  THREAD_OFF (oi->thread_send_hello);
+
   /* Leave AllSPFRouters */
   if (oi->state > OSPF6_INTERFACE_DOWN)
     ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP);
@@ -728,6 +785,10 @@ interface_down (struct thread *thread)
   
   list_delete_all_node (oi->neighbor_list);
 
+  /* When interface state is reset, also reset information about
+   * DR election, as it is no longer valid. */
+  oi->drouter = oi->prev_drouter = htonl(0);
+  oi->bdrouter = oi->prev_bdrouter = htonl(0);
   return 0;
 }
 
@@ -758,7 +819,7 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp)
     type = "UNKNOWN";
 
   vty_out (vty, "%s is %s, type %s%s",
-           ifp->name, updown[if_is_up (ifp)], type,
+           ifp->name, updown[if_is_operative (ifp)], type,
 	   VNL);
   vty_out (vty, "  Interface ID: %d%s", ifp->ifindex, VNL);
 
@@ -1292,7 +1353,10 @@ DEFUN (ipv6_ospf6_priority,
 
   oi->priority = strtol (argv[0], NULL, 10);
 
-  if (oi->area)
+  if (oi->area &&
+      (oi->state == OSPF6_INTERFACE_DROTHER ||
+       oi->state == OSPF6_INTERFACE_BDR ||
+       oi->state == OSPF6_INTERFACE_DR))
     ospf6_interface_state_change (dr_election (oi), oi);
 
   return CMD_SUCCESS;
@@ -1516,6 +1580,86 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list,
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_ospf6_network,
+       ipv6_ospf6_network_cmd,
+       "ipv6 ospf6 network (broadcast|point-to-point)",
+       IP6_STR
+       OSPF6_STR
+       "Network Type\n"
+       "Specify OSPFv6 broadcast network\n"
+       "Specify OSPF6 point-to-point network\n"
+       )
+{
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL) {
+    oi = ospf6_interface_create (ifp);
+  }
+  assert (oi);
+
+  if (strncmp (argv[0], "b", 1) == 0)
+    {
+      if (oi->type == OSPF_IFTYPE_BROADCAST)
+	return CMD_SUCCESS;
+
+      oi->type = OSPF_IFTYPE_BROADCAST;
+    }
+    else if (strncmp (argv[0], "point-to-p", 10) == 0)
+      {
+	if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+	  return CMD_SUCCESS;
+	}
+	oi->type = OSPF_IFTYPE_POINTOPOINT;
+      }
+
+  /* Reset the interface */
+  thread_add_event (master, interface_down, oi, 0);
+  thread_add_event (master, interface_up, oi, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_network,
+       no_ipv6_ospf6_network_cmd,
+       "no ipv6 ospf6 network",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "Network Type\n"
+       "Default to whatever interface type system specifies"
+       )
+{
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+  int type;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL) {
+    return CMD_SUCCESS;
+  }
+
+  type = ospf6_default_iftype (ifp);
+  if (oi->type == type)
+    {
+      return CMD_SUCCESS;
+    }
+  oi->type = type;
+
+  /* Reset the interface */
+  thread_add_event (master, interface_down, oi, 0);
+  thread_add_event (master, interface_up, oi, 0);
+
+  return CMD_SUCCESS;
+}
+
 static int
 config_write_ospf6_interface (struct vty *vty)
 {
@@ -1575,6 +1719,11 @@ config_write_ospf6_interface (struct vty *vty)
       if (oi->mtu_ignore)
         vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL);
 
+      if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+        vty_out (vty, " ipv6 ospf6 network point-to-point%s", VNL);
+      else if (oi->type == OSPF_IFTYPE_BROADCAST)
+	vty_out (vty, " ipv6 ospf6 network broadcast%s", VNL);
+
       vty_out (vty, "!%s", VNL);
     }
   return 0;
@@ -1632,6 +1781,9 @@ ospf6_interface_init (void)
 
   install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+
+  install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd);
 }
 
 DEFUN (debug_ospf6_interface,

+ 3 - 0
ospf6d/ospf6_interface.h

@@ -56,6 +56,9 @@ struct ospf6_interface
   /* I/F transmission delay */
   u_int32_t transdelay;
 
+  /* Network Type */
+  u_char type;
+
   /* Router Priority */
   u_char priority;
 

+ 271 - 39
ospf6d/ospf6_intra.c

@@ -46,7 +46,7 @@
 #include "ospf6_abr.h"
 #include "ospf6_flood.h"
 #include "ospf6d.h"
-
+#include "ospf6_spf.h"
 
 unsigned char conf_debug_ospf6_brouter = 0;
 u_int32_t conf_debug_ospf6_brouter_specific_router_id;
@@ -56,6 +56,42 @@ u_int32_t conf_debug_ospf6_brouter_specific_area_id;
 /* RFC2740 3.4.3.1 Router-LSA */
 /******************************/
 
+static char *
+ospf6_router_lsa_get_nbr_id (struct ospf6_lsa *lsa, char *buf, int buflen,
+			     int pos)
+{
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsdesc *lsdesc;
+  char *start, *end;
+  char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
+
+  if (lsa)
+    {
+      router_lsa = (struct ospf6_router_lsa *)
+	((char *) lsa->header + sizeof (struct ospf6_lsa_header));
+      start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
+      end = (char *) lsa->header + ntohs (lsa->header->length);
+
+      lsdesc = (struct ospf6_router_lsdesc *)
+	(start + pos*(sizeof (struct ospf6_router_lsdesc)));
+      if ((char *)lsdesc < end)
+	{
+	  if (buf && (buflen > INET_ADDRSTRLEN*2))
+	    {
+	      inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
+			 buf1, sizeof(buf1));
+	      inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
+			 buf2, sizeof(buf2));
+	      sprintf (buf, "%s/%s", buf2, buf1);
+	    }
+	}
+      else
+	return NULL;
+    }
+
+  return buf;
+}
+
 static int
 ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
@@ -105,6 +141,29 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 }
 
 int
+ospf6_router_is_stub_router (struct ospf6_lsa *lsa)
+{
+  struct ospf6_router_lsa *rtr_lsa;
+
+  if (lsa != NULL && OSPF6_LSA_IS_TYPE (ROUTER, lsa))
+    {
+      rtr_lsa = (struct ospf6_router_lsa *)
+	((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+      if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_R))
+	{
+	  return (OSPF6_IS_STUB_ROUTER);
+	}
+      else if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_V6))
+	{
+	  return (OSPF6_IS_STUB_ROUTER_V6);
+	}
+    }
+
+  return (OSPF6_NOT_STUB_ROUTER);
+}
+
+int
 ospf6_router_lsa_originate (struct thread *thread)
 {
   struct ospf6_area *oa;
@@ -215,7 +274,7 @@ ospf6_router_lsa_originate (struct thread *thread)
         }
 
       /* Point-to-Point interfaces */
-      if (if_is_pointopoint (oi->interface))
+      if (oi->type == OSPF_IFTYPE_POINTOPOINT)
         {
           for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
             {
@@ -233,7 +292,7 @@ ospf6_router_lsa_originate (struct thread *thread)
         }
 
       /* Broadcast and NBMA interfaces */
-      if (if_is_broadcast (oi->interface))
+      else if (oi->type == OSPF_IFTYPE_BROADCAST)
         {
           /* If this router is not DR,
              and If this router not fully adjacent with DR,
@@ -261,6 +320,10 @@ ospf6_router_lsa_originate (struct thread *thread)
 
           lsdesc++;
         }
+      else
+	{
+	  assert (0);		/* Unknown interface type */
+	}
 
       /* Virtual links */
         /* xxx */
@@ -268,35 +331,26 @@ ospf6_router_lsa_originate (struct thread *thread)
         /* xxx */
     }
 
-  if ((caddr_t) lsdesc != (caddr_t) router_lsa +
-                          sizeof (struct ospf6_router_lsa))
-    {
-      /* Fill LSA Header */
-      lsa_header->age = 0;
-      lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
-      lsa_header->id = htonl (link_state_id);
-      lsa_header->adv_router = oa->ospf6->router_id;
-      lsa_header->seqnum =
-        ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
-                             lsa_header->adv_router, oa->lsdb);
-      lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
-
-      /* LSA checksum */
-      ospf6_lsa_checksum (lsa_header);
-
-      /* create LSA */
-      lsa = ospf6_lsa_create (lsa_header);
-
-      /* Originate */
-      ospf6_lsa_originate_area (lsa, oa);
-
-      link_state_id ++;
-    }
-  else
-    {
-      if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
-        zlog_debug ("Nothing to describe in Router-LSA, suppress");
-    }
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
+  lsa_header->id = htonl (link_state_id);
+  lsa_header->adv_router = oa->ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
+                         lsa_header->adv_router, oa->lsdb);
+  lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+
+  /* Originate */
+  ospf6_lsa_originate_area (lsa, oa);
+
+  link_state_id ++;
 
   /* Do premature-aging of rest, undesired Router-LSAs */
   type = ntohs (OSPF6_LSTYPE_ROUTER);
@@ -316,6 +370,36 @@ ospf6_router_lsa_originate (struct thread *thread)
 /* RFC2740 3.4.3.2 Network-LSA */
 /*******************************/
 
+static char *
+ospf6_network_lsa_get_ar_id (struct ospf6_lsa *lsa, char *buf, int buflen,
+			     int pos)
+{
+  char *start, *end, *current;
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_network_lsdesc *lsdesc;
+
+  if (lsa)
+    {
+      network_lsa = (struct ospf6_network_lsa *)
+	((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+      start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
+      end = (char *) lsa->header + ntohs (lsa->header->length);
+      current = start + pos*(sizeof (struct ospf6_network_lsdesc));
+
+      if ((current + sizeof(struct ospf6_network_lsdesc)) <= end)
+	{
+	  lsdesc = (struct ospf6_network_lsdesc *)current;
+	  if (buf)
+	    inet_ntop (AF_INET, &lsdesc->router_id, buf, buflen);
+	}
+      else
+	return NULL;
+    }
+
+  return (buf);
+}
+
 static int
 ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
@@ -462,6 +546,61 @@ ospf6_network_lsa_originate (struct thread *thread)
 /* RFC2740 3.4.3.6 Link-LSA */
 /****************************/
 
+static char *
+ospf6_link_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen,
+			       int pos)
+{
+  char *start, *end, *current;
+  struct ospf6_link_lsa *link_lsa;
+  struct in6_addr in6;
+  struct ospf6_prefix *prefix;
+  int cnt = 0, prefixnum;
+
+  if (lsa)
+    {
+      link_lsa = (struct ospf6_link_lsa *)
+	((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+      if (pos == 0) {
+	inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, buflen);
+	return (buf);
+      }
+
+      prefixnum = ntohl (link_lsa->prefix_num);
+      if (pos > prefixnum)
+	return (NULL);
+
+      start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
+      end = (char *) lsa->header + ntohs (lsa->header->length);
+      current = start;
+
+      do
+	{
+	  prefix = (struct ospf6_prefix *) current;
+	  if (prefix->prefix_length == 0 ||
+	      current + OSPF6_PREFIX_SIZE (prefix) > end)
+	    {
+	      return (NULL);
+	    }
+
+	  if (cnt < pos)
+	    {
+	      current = start + pos*OSPF6_PREFIX_SIZE(prefix);
+	      cnt++;
+	    }
+	  else
+	    {
+	      memset (&in6, 0, sizeof (in6));
+	      memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
+		      OSPF6_PREFIX_SPACE (prefix->prefix_length));
+	      inet_ntop (AF_INET6, &in6, buf, buflen);
+	      return (buf);
+	    }
+	} while (current <= end);
+    }
+  return (NULL);
+}
+
 static int
 ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
@@ -614,6 +753,56 @@ ospf6_link_lsa_originate (struct thread *thread)
 /*****************************************/
 /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
 /*****************************************/
+static char *
+ospf6_intra_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf,
+				       int buflen, int pos)
+{
+  char *start, *end, *current;
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  struct in6_addr in6;
+  int prefixnum, cnt = 0;
+  struct ospf6_prefix *prefix;
+
+  if (lsa)
+    {
+      intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+	((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+      prefixnum = ntohs (intra_prefix_lsa->prefix_num);
+      if (pos > prefixnum)
+	return (NULL);
+
+      start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa);
+      end = (char *) lsa->header + ntohs (lsa->header->length);
+      current = start;
+
+      do
+	{
+	  prefix = (struct ospf6_prefix *) current;
+	  if (prefix->prefix_length == 0 ||
+	      current + OSPF6_PREFIX_SIZE (prefix) > end)
+	    {
+	      return NULL;
+	    }
+
+	  if (cnt < pos)
+	    {
+	      current = start + pos*OSPF6_PREFIX_SIZE(prefix);
+	      cnt++;
+	    }
+	  else
+	    {
+	      memset (&in6, 0, sizeof (in6));
+	      memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
+		      OSPF6_PREFIX_SPACE (prefix->prefix_length));
+	      inet_ntop (AF_INET6, &in6, buf, buflen);
+	      sprintf(&buf[strlen(buf)], "/%d", prefix->prefix_length);
+	      return (buf);
+	    }
+	} while (current <= end);
+    }
+  return (buf);
+}
 
 static int
 ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
@@ -1029,6 +1218,8 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
   struct ospf6_prefix *op;
   char *start, *current, *end;
   char buf[64];
+  struct interface *ifp;
+  int direct_connect = 0;
 
   if (OSPF6_LSA_IS_MAXAGE (lsa))
     return;
@@ -1065,6 +1256,12 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
       return;
     }
 
+  if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id)
+    {
+      /* the intra-prefix are directly connected */
+      direct_connect = 1;
+    }
+
   prefix_num = ntohs (intra_prefix_lsa->prefix_num);
   start = (caddr_t) intra_prefix_lsa +
           sizeof (struct ospf6_intra_prefix_lsa);
@@ -1077,6 +1274,20 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
       if (end < current + OSPF6_PREFIX_SIZE (op))
         break;
 
+      /* Appendix A.4.1.1 */
+      if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) ||
+	  CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA))
+	{
+	  if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
+	    {
+	      ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op),
+					  buf, sizeof (buf));
+	      zlog_debug ("%s: Skipping Prefix %s has NU/LA option set",
+			  __func__, buf);
+	    }
+	  continue;
+	}
+
       route = ospf6_route_create ();
 
       memset (&route->prefix, 0, sizeof (struct prefix));
@@ -1095,9 +1306,18 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
       route->path.cost = ls_entry->path.cost +
                          ntohs (op->prefix_metric);
 
-      for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
-           i < OSPF6_MULTI_PATH_LIMIT; i++)
-        ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
+      if (direct_connect)
+        {
+          ifp = if_lookup_prefix(&route->prefix);
+          if (ifp)
+            route->nexthop[0].ifindex = ifp->ifindex;
+        }
+      else
+        {
+          for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
+               i < OSPF6_MULTI_PATH_LIMIT; i++)
+            ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
+        }
 
       if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
         {
@@ -1342,6 +1562,10 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa)
           ! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_B))
         continue;
 
+      if (! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_V6) ||
+	  ! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_R))
+	continue;
+
       copy = ospf6_route_copy (brouter);
       copy->type = OSPF6_DEST_TYPE_ROUTER;
       copy->path.area_id = oa->area_id;
@@ -1419,28 +1643,36 @@ struct ospf6_lsa_handler router_handler =
 {
   OSPF6_LSTYPE_ROUTER,
   "Router",
-  ospf6_router_lsa_show
+  "Rtr",
+  ospf6_router_lsa_show,
+  ospf6_router_lsa_get_nbr_id
 };
 
 struct ospf6_lsa_handler network_handler =
 {
   OSPF6_LSTYPE_NETWORK,
   "Network",
-  ospf6_network_lsa_show
+  "Net",
+  ospf6_network_lsa_show,
+  ospf6_network_lsa_get_ar_id
 };
 
 struct ospf6_lsa_handler link_handler =
 {
   OSPF6_LSTYPE_LINK,
   "Link",
-  ospf6_link_lsa_show
+  "Lnk",
+  ospf6_link_lsa_show,
+  ospf6_link_lsa_get_prefix_str
 };
 
 struct ospf6_lsa_handler intra_prefix_handler =
 {
   OSPF6_LSTYPE_INTRA_PREFIX,
   "Intra-Prefix",
-  ospf6_intra_prefix_lsa_show
+  "INP",
+  ospf6_intra_prefix_lsa_show,
+  ospf6_intra_prefix_lsa_get_prefix_str
 };
 
 void

+ 18 - 5
ospf6d/ospf6_intra.h

@@ -94,6 +94,13 @@ struct ospf6_router_lsdesc
 #define OSPF6_ROUTER_LSDESC_STUB_NETWORK       3
 #define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK       4
 
+enum stub_router_mode
+  {
+    OSPF6_NOT_STUB_ROUTER,
+    OSPF6_IS_STUB_ROUTER,
+    OSPF6_IS_STUB_ROUTER_V6,
+  };
+
 #define ROUTER_LSDESC_IS_TYPE(t,x)                         \
   ((((struct ospf6_router_lsdesc *)(x))->type ==           \
    OSPF6_ROUTER_LSDESC_ ## t) ? 1 : 0)
@@ -149,32 +156,37 @@ struct ospf6_intra_prefix_lsa
 
 #define OSPF6_ROUTER_LSA_SCHEDULE(oa) \
   do { \
-    if (! (oa)->thread_router_lsa) \
+    if (! (oa)->thread_router_lsa \
+        && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
       (oa)->thread_router_lsa = \
         thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \
   } while (0)
 #define OSPF6_NETWORK_LSA_SCHEDULE(oi) \
   do { \
-    if (! (oi)->thread_network_lsa) \
+    if (! (oi)->thread_network_lsa \
+        && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
       (oi)->thread_network_lsa = \
         thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \
   } while (0)
 #define OSPF6_LINK_LSA_SCHEDULE(oi) \
   do { \
-    if (! (oi)->thread_link_lsa) \
+    if (! (oi)->thread_link_lsa \
+        && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
       (oi)->thread_link_lsa = \
         thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \
   } while (0)
 #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \
   do { \
-    if (! (oa)->thread_intra_prefix_lsa) \
+    if (! (oa)->thread_intra_prefix_lsa \
+        && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
       (oa)->thread_intra_prefix_lsa = \
         thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \
                           oa, 0); \
   } while (0)
 #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \
   do { \
-    if (! (oi)->thread_intra_prefix_lsa) \
+    if (! (oi)->thread_intra_prefix_lsa \
+        && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
       (oi)->thread_intra_prefix_lsa = \
         thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \
                           oi, 0); \
@@ -200,6 +212,7 @@ extern char *ospf6_router_lsdesc_lookup (u_char type, u_int32_t interface_id,
 extern char *ospf6_network_lsdesc_lookup (u_int32_t router_id,
                                           struct ospf6_lsa *lsa);
 
+extern int ospf6_router_is_stub_router (struct ospf6_lsa *lsa);
 extern int ospf6_router_lsa_originate (struct thread *);
 extern int ospf6_network_lsa_originate (struct thread *);
 extern int ospf6_link_lsa_originate (struct thread *);

+ 140 - 182
ospf6d/ospf6_lsa.c

@@ -75,7 +75,9 @@ struct ospf6_lsa_handler unknown_handler =
 {
   OSPF6_LSTYPE_UNKNOWN,
   "Unknown",
+  "Unk",
   ospf6_unknown_lsa_show,
+  NULL,
   OSPF6_LSA_DEBUG,
 };
 
@@ -118,6 +120,20 @@ ospf6_lstype_name (u_int16_t type)
   return buf;
 }
 
+const char *
+ospf6_lstype_short_name (u_int16_t type)
+{
+  static char buf[8];
+  struct ospf6_lsa_handler *handler;
+
+  handler = ospf6_get_lsa_handler (type);
+  if (handler && handler != &unknown_handler)
+    return handler->short_name;
+
+  snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type));
+  return buf;
+}
+
 u_char
 ospf6_lstype_debug (u_int16_t type)
 {
@@ -139,11 +155,11 @@ ospf6_lsa_is_differ (struct ospf6_lsa *lsa1,
 
   ospf6_lsa_age_current (lsa1);
   ospf6_lsa_age_current (lsa2);
-  if (ntohs (lsa1->header->age) == MAXAGE &&
-      ntohs (lsa2->header->age) != MAXAGE)
+  if (ntohs (lsa1->header->age) == OSPF_LSA_MAXAGE &&
+      ntohs (lsa2->header->age) != OSPF_LSA_MAXAGE)
     return 1;
-  if (ntohs (lsa1->header->age) != MAXAGE &&
-      ntohs (lsa2->header->age) == MAXAGE)
+  if (ntohs (lsa1->header->age) != OSPF_LSA_MAXAGE &&
+      ntohs (lsa2->header->age) == OSPF_LSA_MAXAGE)
     return 1;
 
   /* compare body */
@@ -218,19 +234,19 @@ ospf6_lsa_age_current (struct ospf6_lsa *lsa)
     zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s",
                safe_strerror (errno));
 
-  if (ntohs (lsa->header->age) >= MAXAGE)
+  if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE)
     {
       /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using
          relative time, we cannot compare against lsa birth time, so
          we catch this special case here. */
-      lsa->header->age = htons (MAXAGE);
-      return MAXAGE;
+      lsa->header->age = htons (OSPF_LSA_MAXAGE);
+      return OSPF_LSA_MAXAGE;
     }
   /* calculate age */
   ulage = now.tv_sec - lsa->birth.tv_sec;
 
   /* if over MAXAGE, set to it */
-  age = (ulage > MAXAGE ? MAXAGE : ulage);
+  age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage);
 
   lsa->header->age = htons (age);
   return age;
@@ -243,8 +259,8 @@ ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay)
   unsigned short age;
 
   age = ospf6_lsa_age_current (lsa) + transdelay;
-  if (age > MAXAGE)
-    age = MAXAGE;
+  if (age > OSPF_LSA_MAXAGE)
+    age = OSPF_LSA_MAXAGE;
   lsa->header->age = htons (age);
 }
 
@@ -258,7 +274,30 @@ ospf6_lsa_premature_aging (struct ospf6_lsa *lsa)
   THREAD_OFF (lsa->expire);
   THREAD_OFF (lsa->refresh);
 
-  lsa->header->age = htons (MAXAGE);
+  /*
+   * We clear the LSA from the neighbor retx lists now because it
+   * will not get deleted later. Essentially, changing the age to
+   * MaxAge will prevent this LSA from being matched with its
+   * existing entries in the retx list thereby causing those entries
+   * to be silently replaced with its MaxAged version, but with ever
+   * increasing retx count causing this LSA to remain forever and
+   * for the MaxAge remover thread to be called forever too.
+   *
+   * The reason the previous entry silently disappears is that when
+   * entry is added to a neighbor's retx list, it replaces the existing
+   * entry. But since the ospf6_lsdb_add() routine is generic and not aware
+   * of the special semantics of retx count, the retx count is not
+   * decremented when its replaced. Attempting to add the incr and decr
+   * retx count routines as the hook_add and hook_remove for the retx lists
+   * have a problem because the hook_remove routine is called for MaxAge
+   * entries (as will be the case in a traditional LSDB, unlike in this case
+   * where an LSDB is used as an efficient tree structure to store all kinds
+   * of data) that are added instead of calling the hook_add routine.
+   */
+
+  ospf6_flood_clear (lsa);
+
+  lsa->header->age = htons (OSPF_LSA_MAXAGE);
   thread_execute (master, ospf6_lsa_expire, lsa, 0);
 }
 
@@ -297,15 +336,15 @@ ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b)
   ageb = ospf6_lsa_age_current (b);
 
   /* MaxAge check */
-  if (agea == MAXAGE && ageb != MAXAGE)
+  if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE)
     return -1;
-  else if (agea != MAXAGE && ageb == MAXAGE)
+  else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE)
     return 1;
 
   /* Age check */
-  if (agea > ageb && agea - ageb >= MAX_AGE_DIFF)
+  if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF)
     return 1;
-  else if (agea < ageb && ageb - agea >= MAX_AGE_DIFF)
+  else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF)
     return -1;
 
   /* neither recent */
@@ -348,17 +387,19 @@ ospf6_lsa_header_print (struct ospf6_lsa *lsa)
 void
 ospf6_lsa_show_summary_header (struct vty *vty)
 {
-  vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s",
+  vty_out (vty, "%-4s %-15s%-15s%4s %8s %30s%s",
            "Type", "LSId", "AdvRouter", "Age", "SeqNum",
-           "Cksm", "Len", "Duration", VNL);
+           "Payload", VNL);
 }
 
 void
 ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
 {
   char adv_router[16], id[16];
-  struct timeval now, res;
-  char duration[16];
+  int type;
+  struct ospf6_lsa_handler *handler;
+  char buf[64], tmpbuf[80];
+  int cnt = 0;
 
   assert (lsa);
   assert (lsa->header);
@@ -367,16 +408,38 @@ ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
   inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
              sizeof (adv_router));
 
-  quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
-  timersub (&now, &lsa->installed, &res);
-  timerstring (&res, duration, sizeof (duration));
-
-  vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
-           ospf6_lstype_name (lsa->header->type),
-           id, adv_router, ospf6_lsa_age_current (lsa),
-           (u_long) ntohl (lsa->header->seqnum),
-           ntohs (lsa->header->checksum), ntohs (lsa->header->length),
-           duration, VNL);
+  type = ntohs(lsa->header->type);
+  handler = ospf6_get_lsa_handler (lsa->header->type);
+  if ((type == OSPF6_LSTYPE_INTER_PREFIX) ||
+      (type == OSPF6_LSTYPE_INTER_ROUTER) ||
+      (type == OSPF6_LSTYPE_AS_EXTERNAL))
+    {
+      vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s",
+	       ospf6_lstype_short_name (lsa->header->type),
+	       id, adv_router, ospf6_lsa_age_current (lsa),
+	       (u_long) ntohl (lsa->header->seqnum),
+	       handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL);
+    }
+  else if (type != OSPF6_LSTYPE_UNKNOWN)
+    {
+      sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx",
+	       ospf6_lstype_short_name (lsa->header->type),
+	       id, adv_router, ospf6_lsa_age_current (lsa),
+	       (u_long) ntohl (lsa->header->seqnum));
+
+      while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL)
+	{
+	  vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL);
+	  cnt++;
+	}
+    }
+  else
+    {
+      vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s",
+	       ospf6_lstype_short_name (lsa->header->type),
+	       id, adv_router, ospf6_lsa_age_current (lsa),
+	       (u_long) ntohl (lsa->header->seqnum), VNL);
+    }
 }
 
 void
@@ -427,8 +490,11 @@ ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa)
   vty_out (vty, "CheckSum: %#06hx Length: %hu%s",
            ntohs (lsa->header->checksum),
            ntohs (lsa->header->length), VNL);
-  vty_out (vty, "    Prev: %p This: %p Next: %p%s",
-           lsa->prev, lsa, lsa->next, VNL);
+  vty_out (vty, "Flag: %x %s", lsa->flag, VNL);
+  vty_out (vty, "Lock: %d %s", lsa->lock, VNL);
+  vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL);
+  vty_out (vty, "Threads: Expire: %x, Refresh: %x %s",
+	   lsa->expire, lsa->refresh, VNL);
   vty_out (vty, "%s", VNL);
   return;
 }
@@ -438,6 +504,8 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
   char adv_router[64], id[64];
   struct ospf6_lsa_handler *handler;
+  struct timeval now, res;
+  char duration[16];
 
   assert (lsa && lsa->header);
 
@@ -445,6 +513,10 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
   inet_ntop (AF_INET, &lsa->header->adv_router,
              adv_router, sizeof (adv_router));
 
+  quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+  timersub (&now, &lsa->installed, &res);
+  timerstring (&res, duration, sizeof (duration));
+
   vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
            ospf6_lstype_name (lsa->header->type), VNL);
   vty_out (vty, "Link State ID: %s%s", id, VNL);
@@ -454,6 +526,7 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
   vty_out (vty, "CheckSum: %#06hx Length: %hu%s",
            ntohs (lsa->header->checksum),
            ntohs (lsa->header->length), VNL);
+  vty_out (vty, "Duration: %s%s", duration, VNL);
 
   handler = ospf6_get_lsa_handler (lsa->header->type);
   if (handler->show == NULL)
@@ -558,6 +631,7 @@ ospf6_lsa_copy (struct ospf6_lsa *lsa)
   copy->received = lsa->received;
   copy->installed = lsa->installed;
   copy->lsdb = lsa->lsdb;
+  copy->rn = NULL;
 
   return copy;
 }
@@ -608,12 +682,12 @@ ospf6_lsa_expire (struct thread *thread)
   if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY))
     return 0;    /* dbexchange will do something ... */
 
-  /* reflood lsa */
-  ospf6_flood (NULL, lsa);
-
   /* reinstall lsa */
   ospf6_install_lsa (lsa);
 
+  /* reflood lsa */
+  ospf6_flood (NULL, lsa);
+
   /* schedule maxage remover */
   ospf6_maxage_remove (ospf6);
 
@@ -653,7 +727,7 @@ ospf6_lsa_refresh (struct thread *thread)
   new = ospf6_lsa_create (self->header);
   new->lsdb = old->lsdb;
   new->refresh = thread_add_timer (master, ospf6_lsa_refresh, new,
-                                   LS_REFRESH_TIME);
+                                   OSPF_LS_REFRESH_TIME);
 
   /* store it in the LSDB for self-originated LSAs */
   ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self);
@@ -664,9 +738,8 @@ ospf6_lsa_refresh (struct thread *thread)
       ospf6_lsa_header_print (new);
     }
 
-  ospf6_flood_clear (old);
-  ospf6_flood (NULL, new);
   ospf6_install_lsa (new);
+  ospf6_flood (NULL, new);
 
   return 0;
 }
@@ -725,7 +798,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h)
   unsigned int i; 
   unsigned int size = strlen (h->name);
 
-  if (!strcmp(h->name, "Unknown") &&
+  if (!strcmp(h->name, "unknown") &&
       h->type != OSPF6_LSTYPE_UNKNOWN)
     {
       snprintf (buf, sizeof (buf), "%#04hx", h->type);
@@ -745,7 +818,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h)
 
 DEFUN (debug_ospf6_lsa_type,
        debug_ospf6_lsa_hex_cmd,
-       "debug ospf6 lsa XXXX/0xXXXX",
+       "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)",
        DEBUG_STR
        OSPF6_STR
        "Debug Link State Advertisements (LSAs)\n"
@@ -754,44 +827,21 @@ DEFUN (debug_ospf6_lsa_type,
 {
   unsigned int i;
   struct ospf6_lsa_handler *handler = NULL;
-  unsigned long val;
-  char *endptr = NULL;
-  u_int16_t type = 0;
 
   assert (argc);
 
-  if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) ||
-      (strlen (argv[0]) == 4))
-    {
-      val = strtoul (argv[0], &endptr, 16);
-      if (*endptr == '\0')
-        type = val;
-    }
-
   for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++)
     {
       handler = vector_slot (ospf6_lsa_handler_vector, i);
       if (handler == NULL)
         continue;
-      if (type && handler->type == type)
+      if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0)
         break;
       if (! strcasecmp (argv[0], handler->name))
         break;
       handler = NULL;
     }
 
-  if (type && handler == NULL)
-    {
-      handler = (struct ospf6_lsa_handler *)
-        malloc (sizeof (struct ospf6_lsa_handler));
-      memset (handler, 0, sizeof (struct ospf6_lsa_handler));
-      handler->type = type;
-      handler->name = "Unknown";
-      handler->show = ospf6_unknown_lsa_show;
-      vector_set_index (ospf6_lsa_handler_vector,
-                        handler->type & OSPF6_LSTYPE_FCODE_MASK, handler);
-    }
-
   if (handler == NULL)
     handler = &unknown_handler;
 
@@ -799,7 +849,7 @@ DEFUN (debug_ospf6_lsa_type,
     {
       if (! strcmp (argv[1], "originate"))
         SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE);
-      if (! strcmp (argv[1], "examin"))
+      if (! strcmp (argv[1], "examine"))
         SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN);
       if (! strcmp (argv[1], "flooding"))
         SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD);
@@ -810,9 +860,18 @@ DEFUN (debug_ospf6_lsa_type,
   return CMD_SUCCESS;
 }
 
+ALIAS (debug_ospf6_lsa_type,
+       debug_ospf6_lsa_hex_detail_cmd,
+       "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+       "Specify LS type as Hexadecimal\n"
+      )
+
 DEFUN (no_debug_ospf6_lsa_type,
        no_debug_ospf6_lsa_hex_cmd,
-       "no debug ospf6 lsa XXXX/0xXXXX",
+       "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)",
        NO_STR
        DEBUG_STR
        OSPF6_STR
@@ -822,26 +881,15 @@ DEFUN (no_debug_ospf6_lsa_type,
 {
   u_int i;
   struct ospf6_lsa_handler *handler = NULL;
-  unsigned long val;
-  char *endptr = NULL;
-  u_int16_t type = 0;
 
   assert (argc);
 
-  if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) ||
-      (strlen (argv[0]) == 4))
-    {
-      val = strtoul (argv[0], &endptr, 16);
-      if (*endptr == '\0')
-        type = val;
-    }
-
   for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++)
     {
       handler = vector_slot (ospf6_lsa_handler_vector, i);
       if (handler == NULL)
         continue;
-      if (type && handler->type == type)
+      if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0)
         break;
       if (! strcasecmp (argv[0], handler->name))
         break;
@@ -854,7 +902,7 @@ DEFUN (no_debug_ospf6_lsa_type,
     {
       if (! strcmp (argv[1], "originate"))
         UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE);
-      if (! strcmp (argv[1], "examin"))
+      if (! strcmp (argv[1], "examine"))
         UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN);
       if (! strcmp (argv[1], "flooding"))
         UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD);
@@ -862,120 +910,30 @@ DEFUN (no_debug_ospf6_lsa_type,
   else
     UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG);
 
-  if (handler->debug == 0 &&
-      !strcmp(handler->name, "Unknown") && type != OSPF6_LSTYPE_UNKNOWN)
-    {
-      free (handler);
-      vector_slot (ospf6_lsa_handler_vector, i) = NULL;
-    }
-
   return CMD_SUCCESS;
 }
 
-struct cmd_element debug_ospf6_lsa_type_cmd;
-struct cmd_element debug_ospf6_lsa_type_detail_cmd;
-struct cmd_element no_debug_ospf6_lsa_type_cmd;
-struct cmd_element no_debug_ospf6_lsa_type_detail_cmd;
+ALIAS (no_debug_ospf6_lsa_type,
+       no_debug_ospf6_lsa_hex_detail_cmd,
+       "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+       "Specify LS type as Hexadecimal\n"
+      )
 
 void
 install_element_ospf6_debug_lsa (void)
 {
-  u_int i;
-  struct ospf6_lsa_handler *handler;
-#define STRSIZE  256
-#define DOCSIZE  1024
-  static char strbuf[STRSIZE];
-  static char docbuf[DOCSIZE];
-  static char detail_strbuf[STRSIZE];
-  static char detail_docbuf[DOCSIZE];
-  char *str, *no_str;
-  char *doc, *no_doc;
-
-  strbuf[0] = '\0';
-  no_str = &strbuf[strlen (strbuf)];
-  strncat (strbuf, "no ", STRSIZE - strlen (strbuf));
-  str = &strbuf[strlen (strbuf)];
-
-  strncat (strbuf, "debug ospf6 lsa (", STRSIZE - strlen (strbuf));
-  for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++)
-    {
-      handler = vector_slot (ospf6_lsa_handler_vector, i);
-      if (handler == NULL)
-        continue;
-      strncat (strbuf, ospf6_lsa_handler_name (handler),
-               STRSIZE - strlen (strbuf));
-      strncat (strbuf, "|", STRSIZE - strlen (strbuf));
-    }
-  strbuf[strlen (strbuf) - 1] = ')';
-  strbuf[strlen (strbuf)] = '\0';
-
-  docbuf[0] = '\0';
-  no_doc = &docbuf[strlen (docbuf)];
-  strncat (docbuf, NO_STR, DOCSIZE - strlen (docbuf));
-  doc = &docbuf[strlen (docbuf)];
-
-  strncat (docbuf, DEBUG_STR, DOCSIZE - strlen (docbuf));
-  strncat (docbuf, OSPF6_STR, DOCSIZE - strlen (docbuf));
-  strncat (docbuf, "Debug Link State Advertisements (LSAs)\n",
-           DOCSIZE - strlen (docbuf));
-
-  for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++)
-    {
-      handler = vector_slot (ospf6_lsa_handler_vector, i);
-      if (handler == NULL)
-        continue;
-      strncat (docbuf, "Debug ", DOCSIZE - strlen (docbuf));
-      strncat (docbuf, handler->name, DOCSIZE - strlen (docbuf));
-      strncat (docbuf, "-LSA\n", DOCSIZE - strlen (docbuf));
-    }
-  docbuf[strlen (docbuf)] = '\0';
-
-  debug_ospf6_lsa_type_cmd.string = str;
-  debug_ospf6_lsa_type_cmd.func = debug_ospf6_lsa_type;
-  debug_ospf6_lsa_type_cmd.doc = doc;
-
-  no_debug_ospf6_lsa_type_cmd.string = no_str;
-  no_debug_ospf6_lsa_type_cmd.func = no_debug_ospf6_lsa_type;
-  no_debug_ospf6_lsa_type_cmd.doc = no_doc;
-
-  strncpy (detail_strbuf, strbuf, STRSIZE);
-  strncat (detail_strbuf, " (originate|examin|flooding)",
-           STRSIZE - strlen (detail_strbuf));
-  detail_strbuf[strlen (detail_strbuf)] = '\0';
-  no_str = &detail_strbuf[0];
-  str = &detail_strbuf[strlen ("no ")];
-
-  strncpy (detail_docbuf, docbuf, DOCSIZE);
-  strncat (detail_docbuf, "Debug Originating LSA\n",
-           DOCSIZE - strlen (detail_docbuf));
-  strncat (detail_docbuf, "Debug Examining LSA\n",
-           DOCSIZE - strlen (detail_docbuf));
-  strncat (detail_docbuf, "Debug Flooding LSA\n",
-           DOCSIZE - strlen (detail_docbuf));
-  detail_docbuf[strlen (detail_docbuf)] = '\0';
-  no_doc = &detail_docbuf[0];
-  doc = &detail_docbuf[strlen (NO_STR)];
-
-  debug_ospf6_lsa_type_detail_cmd.string = str;
-  debug_ospf6_lsa_type_detail_cmd.func = debug_ospf6_lsa_type;
-  debug_ospf6_lsa_type_detail_cmd.doc = doc;
-
-  no_debug_ospf6_lsa_type_detail_cmd.string = no_str;
-  no_debug_ospf6_lsa_type_detail_cmd.func = no_debug_ospf6_lsa_type;
-  no_debug_ospf6_lsa_type_detail_cmd.doc = no_doc;
-
   install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd);
-  install_element (ENABLE_NODE, &debug_ospf6_lsa_type_cmd);
-  install_element (ENABLE_NODE, &debug_ospf6_lsa_type_detail_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd);
   install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
-  install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_cmd);
-  install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_detail_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd);
   install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd);
-  install_element (CONFIG_NODE, &debug_ospf6_lsa_type_cmd);
-  install_element (CONFIG_NODE, &debug_ospf6_lsa_type_detail_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd);
   install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd);
-  install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_cmd);
-  install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_detail_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd);
 }
 
 int
@@ -996,7 +954,7 @@ config_write_ospf6_debug_lsa (struct vty *vty)
         vty_out (vty, "debug ospf6 lsa %s originate%s",
                  ospf6_lsa_handler_name (handler), VNL);
       if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN))
-        vty_out (vty, "debug ospf6 lsa %s examin%s",
+        vty_out (vty, "debug ospf6 lsa %s examine%s",
                  ospf6_lsa_handler_name (handler), VNL);
       if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD))
         vty_out (vty, "debug ospf6 lsa %s flooding%s",

+ 8 - 3
ospf6d/ospf6_lsa.h

@@ -107,15 +107,16 @@ struct ospf6_lsa_header
   ((L)->header->adv_router == (a) && (L)->header->id == (i) && \
    (L)->header->type == (t))
 #define OSPF6_LSA_IS_DIFFER(L1, L2)  ospf6_lsa_is_differ (L1, L2)
-#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == MAXAGE)
+#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF_LSA_MAXAGE)
 #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2)
+#define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1))
+
 
 struct ospf6_lsa
 {
   char              name[64];   /* dump string */
 
-  struct ospf6_lsa *prev;
-  struct ospf6_lsa *next;
+  struct route_node *rn;
 
   unsigned char     lock;           /* reference counter */
   unsigned char     flag;           /* special meaning (e.g. floodback) */
@@ -140,12 +141,15 @@ struct ospf6_lsa
 #define OSPF6_LSA_FLOODBACK  0x02
 #define OSPF6_LSA_DUPLICATE  0x04
 #define OSPF6_LSA_IMPLIEDACK 0x08
+#define OSPF6_LSA_SEQWRAPPED 0x20
 
 struct ospf6_lsa_handler
 {
   u_int16_t type; /* host byte order */
   const char *name;
+  const char *short_name;
   int (*show) (struct vty *, struct ospf6_lsa *);
+  char *(*get_prefix_str) (struct ospf6_lsa *, char *buf, int buflen, int pos);
   u_char debug;
 };
 
@@ -208,6 +212,7 @@ extern struct ospf6_lsa_handler unknown_handler;
 
 /* Function Prototypes */
 extern const char *ospf6_lstype_name (u_int16_t type);
+extern const char *ospf6_lstype_short_name (u_int16_t type);
 extern u_char ospf6_lstype_debug (u_int16_t type);
 extern int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
 extern int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);

+ 106 - 103
ospf6d/ospf6_lsdb.c

@@ -54,9 +54,12 @@ ospf6_lsdb_create (void *data)
 void
 ospf6_lsdb_delete (struct ospf6_lsdb *lsdb)
 {
-  ospf6_lsdb_remove_all (lsdb);
-  route_table_finish (lsdb->table);
-  XFREE (MTYPE_OSPF6_LSDB, lsdb);
+  if (lsdb != NULL)
+    {
+      ospf6_lsdb_remove_all (lsdb);
+      route_table_finish (lsdb->table);
+      XFREE (MTYPE_OSPF6_LSDB, lsdb);
+    }
 }
 
 static void
@@ -70,7 +73,7 @@ ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len)
   key->prefixlen += len * 8;
 }
 
-#ifndef NDEBUG
+#ifdef DEBUG
 static void
 _lsdb_count_assert (struct ospf6_lsdb *lsdb)
 {
@@ -94,16 +97,16 @@ _lsdb_count_assert (struct ospf6_lsdb *lsdb)
   assert (num == lsdb->count);
 }
 #define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t))
-#else /*NDEBUG*/
+#else /*DEBUG*/
 #define ospf6_lsdb_count_assert(t) ((void) 0)
-#endif /*NDEBUG*/
+#endif /*DEBUG*/
 
 void
 ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
 {
   struct prefix_ipv6 key;
-  struct route_node *current, *nextnode, *prevnode;
-  struct ospf6_lsa *next, *prev, *old = NULL;
+  struct route_node *current;
+  struct ospf6_lsa *old = NULL;
 
   memset (&key, 0, sizeof (key));
   ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type));
@@ -114,55 +117,25 @@ ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
   current = route_node_get (lsdb->table, (struct prefix *) &key);
   old = current->info;
   current->info = lsa;
+  lsa->rn = current;
   ospf6_lsa_lock (lsa);
 
-  if (old)
-    {
-      if (old->prev)
-        old->prev->next = lsa;
-      if (old->next)
-        old->next->prev = lsa;
-      lsa->next = old->next;
-      lsa->prev = old->prev;
-    }
-  else
+  if (!old)
     {
-      /* next link */
-      nextnode = current;
-      route_lock_node (nextnode);
-      do {
-        nextnode = route_next (nextnode);
-      } while (nextnode && nextnode->info == NULL);
-      if (nextnode == NULL)
-        lsa->next = NULL;
-      else
-        {
-          next = nextnode->info;
-          lsa->next = next;
-          next->prev = lsa;
-          route_unlock_node (nextnode);
-        }
+      lsdb->count++;
 
-      /* prev link */
-      prevnode = current;
-      route_lock_node (prevnode);
-      do {
-        prevnode = route_prev (prevnode);
-      } while (prevnode && prevnode->info == NULL);
-      if (prevnode == NULL)
-        lsa->prev = NULL;
+      if (OSPF6_LSA_IS_MAXAGE (lsa))
+	{
+	  if (lsdb->hook_remove)
+	    (*lsdb->hook_remove) (lsa);
+	}
       else
-        {
-          prev = prevnode->info;
-          lsa->prev = prev;
-          prev->next = lsa;
-          route_unlock_node (prevnode);
-        }
-
-      lsdb->count++;
+	{
+	  if (lsdb->hook_add)
+	    (*lsdb->hook_add) (lsa);
+	}
     }
-
-  if (old)
+  else
     {
       if (OSPF6_LSA_IS_CHANGED (old, lsa))
         {
@@ -187,21 +160,9 @@ ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
                 (*lsdb->hook_add) (lsa);
             }
         }
-    }
-  else if (OSPF6_LSA_IS_MAXAGE (lsa))
-    {
-      if (lsdb->hook_remove)
-        (*lsdb->hook_remove) (lsa);
-    }
-  else
-    {
-      if (lsdb->hook_add)
-        (*lsdb->hook_add) (lsa);
+      ospf6_lsa_unlock (old);
     }
 
-  if (old)
-    ospf6_lsa_unlock (old);
-
   ospf6_lsdb_count_assert (lsdb);
 }
 
@@ -220,19 +181,15 @@ ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
   node = route_node_lookup (lsdb->table, (struct prefix *) &key);
   assert (node && node->info == lsa);
 
-  if (lsa->prev)
-    lsa->prev->next = lsa->next;
-  if (lsa->next)
-    lsa->next->prev = lsa->prev;
-
   node->info = NULL;
   lsdb->count--;
 
   if (lsdb->hook_remove)
     (*lsdb->hook_remove) (lsa);
 
+  route_unlock_node (node);	/* to free the lookup lock */
+  route_unlock_node (node);	/* to free the original lock */
   ospf6_lsa_unlock (lsa);
-  route_unlock_node (node);
 
   ospf6_lsdb_count_assert (lsdb);
 }
@@ -255,6 +212,8 @@ ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
   node = route_node_lookup (lsdb->table, (struct prefix *) &key);
   if (node == NULL || node->info == NULL)
     return NULL;
+
+  route_unlock_node (node);
   return (struct ospf6_lsa *) node->info;
 }
 
@@ -306,21 +265,9 @@ ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router,
 
   if (prefix_same (&node->p, p))
     {
-      struct route_node *prev = node;
-      struct ospf6_lsa *lsa_prev;
-      struct ospf6_lsa *lsa_next;
-
       node = route_next (node);
       while (node && node->info == NULL)
         node = route_next (node);
-
-      lsa_prev = prev->info;
-      lsa_next = (node ? node->info : NULL);
-      assert (lsa_prev);
-      assert (lsa_prev->next == lsa_next);
-      if (lsa_next)
-        assert (lsa_next->prev == lsa_prev);
-      zlog_debug ("lsdb_lookup_next: assert OK with previous LSA");
     }
 
   if (! node)
@@ -346,7 +293,6 @@ ospf6_lsdb_head (struct ospf6_lsdb *lsdb)
   if (node == NULL)
     return NULL;
 
-  route_unlock_node (node);
   if (node->info)
     ospf6_lsa_lock ((struct ospf6_lsa *) node->info);
   return (struct ospf6_lsa *) node->info;
@@ -355,12 +301,20 @@ ospf6_lsdb_head (struct ospf6_lsdb *lsdb)
 struct ospf6_lsa *
 ospf6_lsdb_next (struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa *next = lsa->next;
+  struct route_node *node = lsa->rn;
+  struct ospf6_lsa *next = NULL;
 
-  ospf6_lsa_unlock (lsa);
-  if (next)
-    ospf6_lsa_lock (next);
+  do {
+    node = route_next (node);
+  } while (node && node->info == NULL);
 
+  if ((node != NULL) && (node->info != NULL))
+    {
+      next = node->info;
+      ospf6_lsa_lock (next);
+    }
+
+  ospf6_lsa_unlock (lsa);
   return next;
 }
 
@@ -390,8 +344,6 @@ ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router,
 
   if (node == NULL)
     return NULL;
-  else
-    route_unlock_node (node);
 
   if (! prefix_match ((struct prefix *) &key, &node->p))
     return NULL;
@@ -406,18 +358,19 @@ struct ospf6_lsa *
 ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router,
                              struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa *next = lsa->next;
+  struct ospf6_lsa *next = ospf6_lsdb_next(lsa);
 
   if (next)
     {
       if (next->header->type != type ||
           next->header->adv_router != adv_router)
-        next = NULL;
+	{
+	  route_unlock_node (next->rn);
+	  ospf6_lsa_unlock (next);
+	  next = NULL;
+	}
     }
 
-  if (next)
-    ospf6_lsa_lock (next);
-  ospf6_lsa_unlock (lsa);
   return next;
 }
 
@@ -444,8 +397,6 @@ ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb)
 
   if (node == NULL)
     return NULL;
-  else
-    route_unlock_node (node);
 
   if (! prefix_match ((struct prefix *) &key, &node->p))
     return NULL;
@@ -459,17 +410,18 @@ ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb)
 struct ospf6_lsa *
 ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa *next = lsa->next;
+  struct ospf6_lsa *next = ospf6_lsdb_next (lsa);
 
   if (next)
     {
       if (next->header->type != type)
-        next = NULL;
+	{
+	  route_unlock_node (next->rn);
+	  ospf6_lsa_unlock (next);
+	  next = NULL;
+	}
     }
 
-  if (next)
-    ospf6_lsa_lock (next);
-  ospf6_lsa_unlock (lsa);
   return next;
 }
 
@@ -477,11 +429,62 @@ void
 ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb)
 {
   struct ospf6_lsa *lsa;
+
+  if (lsdb == NULL)
+    return;
+
   for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa))
     ospf6_lsdb_remove (lsa, lsdb);
 }
 
 void
+ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa)
+{
+  if (lsa != NULL)
+    {
+      if (lsa->rn != NULL)
+	route_unlock_node (lsa->rn);
+      ospf6_lsa_unlock (lsa);
+    }
+}
+
+int
+ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb)
+{
+  int reschedule = 0;
+  struct ospf6_lsa *lsa;
+
+  for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa))
+    {
+      if (! OSPF6_LSA_IS_MAXAGE (lsa))
+	continue;
+      if (lsa->retrans_count != 0)
+	{
+	  reschedule = 1;
+	  continue;
+	}
+      if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type))
+	zlog_debug ("Remove MaxAge %s", lsa->name);
+      if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED))
+      {
+        UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
+        /*
+         * lsa->header->age = 0;
+         */
+        lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER + 1);
+        ospf6_lsa_checksum (lsa->header);
+