Browse Source

[zebra/solaris] Interface state fixups for Solaris.

2006-01-25 Paul Jakma <paul.jakma@sun.com>

	* (general) More solaris PF_ROUTE hacks. The IFF_UP mangling
	  for solaris was incomplete on the PF_ROUTE side. fix it.
	  This changeset generally uglifies things. For some future
	  work I'd like to see the state changes seperated out from
	  the details of the code. Differences between systems might
	  then be slightly easier to implement without convoluted
	  hacks.
	  Changes should be specific to Solaris mostly, however
	  also tested on FreeBSD 6.
	* if_ioctl_solaris.c: (interface_list_ioctl) ignore ~IFF_UP
	  interfaces, we'll hear about them when/if interface goes up
	  through NEWADDR.
	  Update flags explicitely at end of it to kick mangling.
	* ioctl_solaris.c: (if_mangle_up) removed to interface.c, in
	  kind.
	  (lifreq_set_name) more convenient to take the string, than
	  the ifp.
	  (if_get_flags_direct) new convenience function, returns
	  the actual flags. Used during bootstrap in if_ioctl_solaris.c
	  to peek at flags of logical interfaces to see whether or
	  not to ignore them.
	  (if_get_flags) ENXIO means it's gone, poke out IFF_UP and
	  kick flags update.
	  (if_{un,}set_flags) flags argument should be 64bit.
	* ioctl.{c,h}: flags argument should be 64bit.
	* interface.h: Add a 'primary_state' flag to struct zebra_if on
	  SUNOS_5.
	  Export if_flags_update.
	* interface.c: (if_flags_mangle) moved over in kind from
	  ioctl_solaris.c. Nasty kludge to try get IFF_UP right, as
	  much as is possible. Also keep track of the actual IFF_UP
	  value for the primary interface, so we can know when the ifp
	  must be deleted.
	  (if_flags_update) Take a new interface flags value, apply it
	  to the interface, and take whatever actions are required due
	  to flag transitions.
	  (if_refresh) flag state change logic is moved out to
	  previous. Just call if_get_flags, which will end up using
	  previous to effect the update of flags.
	  (if_flag_dump_vty) IFF_IPV{4,6} aren't interesting, VIRTUAL
	  and NOXMIT are though.
	* kernel_socket.c: (ifm_read) Down->Down transitions shouldn't
	  create ifp, for non-IFANNOUNCE systems.
	  Use if_flags_update to update flags.
	  flag transition logic is now handled automatically through
	  if_flags_update.
	  (ifam_read) Better to call if_refresh *after* adding
 	  connected addresses, as connected count affects IFF_UP on
 	  IFF_UP-mangled systems.
 	  On Solaris, Up->Down due to DELADDR means we need to delete
	  the ifp - the IFINFO might already have been and gone.
	* rt.h: include other dependent headers.
paul 13 years ago
parent
commit
5c78b3d006
9 changed files with 257 additions and 92 deletions
  1. 55 0
      zebra/ChangeLog
  2. 19 1
      zebra/if_ioctl_solaris.c
  3. 71 15
      zebra/interface.c
  4. 9 0
      zebra/interface.h
  5. 4 3
      zebra/ioctl.c
  6. 2 2
      zebra/ioctl.h
  7. 49 42
      zebra/ioctl_solaris.c
  8. 47 29
      zebra/kernel_socket.c
  9. 1 0
      zebra/rt.h

+ 55 - 0
zebra/ChangeLog

@@ -1,3 +1,58 @@
+2006-01-25 Paul Jakma <paul.jakma@sun.com>
+
+	* (general) More solaris PF_ROUTE hacks. The IFF_UP mangling
+	  for solaris was incomplete on the PF_ROUTE side. fix it.
+	  This changeset generally uglifies things. For some future
+	  work I'd like to see the state changes seperated out from
+	  the details of the code. Differences between systems might
+	  then be slightly easier to implement without convoluted
+	  hacks.
+	  Changes should be specific to Solaris mostly, however
+	  also tested on FreeBSD 6.
+	* if_ioctl_solaris.c: (interface_list_ioctl) ignore ~IFF_UP
+	  interfaces, we'll hear about them when/if interface goes up
+	  through NEWADDR.
+	  Update flags explicitely at end of it to kick mangling.
+	* ioctl_solaris.c: (if_mangle_up) removed to interface.c, in
+	  kind.
+	  (lifreq_set_name) more convenient to take the string, than
+	  the ifp.
+	  (if_get_flags_direct) new convenience function, returns
+	  the actual flags. Used during bootstrap in if_ioctl_solaris.c
+	  to peek at flags of logical interfaces to see whether or
+	  not to ignore them.
+	  (if_get_flags) ENXIO means it's gone, poke out IFF_UP and
+	  kick flags update.
+	  (if_{un,}set_flags) flags argument should be 64bit.
+	* ioctl.{c,h}: flags argument should be 64bit. 
+	* interface.h: Add a 'primary_state' flag to struct zebra_if on
+	  SUNOS_5.
+	  Export if_flags_update.
+	* interface.c: (if_flags_mangle) moved over in kind from
+	  ioctl_solaris.c. Nasty kludge to try get IFF_UP right, as
+	  much as is possible. Also keep track of the actual IFF_UP
+	  value for the primary interface, so we can know when the ifp
+	  must be deleted.
+	  (if_flags_update) Take a new interface flags value, apply it
+	  to the interface, and take whatever actions are required due
+	  to flag transitions.
+	  (if_refresh) flag state change logic is moved out to
+	  previous. Just call if_get_flags, which will end up using
+	  previous to effect the update of flags.
+	  (if_flag_dump_vty) IFF_IPV{4,6} aren't interesting, VIRTUAL
+	  and NOXMIT are though.
+	* kernel_socket.c: (ifm_read) Down->Down transitions shouldn't
+	  create ifp, for non-IFANNOUNCE systems.
+	  Use if_flags_update to update flags.
+	  flag transition logic is now handled automatically through
+	  if_flags_update.
+	  (ifam_read) Better to call if_refresh *after* adding
+ 	  connected addresses, as connected count affects IFF_UP on
+ 	  IFF_UP-mangled systems.
+ 	  On Solaris, Up->Down due to DELADDR means we need to delete
+	  the ifp - the IFINFO might already have been and gone.
+	* rt.h: include other dependent headers.
+
 2006-01-19 Paul Jakma <paul.jakma@sun.com>
 
         * (general) various miscellaneous compiler warning fixes.

+ 19 - 1
zebra/if_ioctl_solaris.c

@@ -33,7 +33,8 @@
 
 #include "zebra/interface.h"
 
-void lifreq_set_name (struct lifreq *, struct interface *);
+void lifreq_set_name (struct lifreq *, const char *);
+int if_get_flags_direct (const char *, uint64_t *, unsigned int af);
 static int if_get_addr (struct interface *, struct sockaddr *, const char *);
 static void interface_info_ioctl (struct interface *);
 extern struct zebra_privs_t zserv_privs;
@@ -147,7 +148,20 @@ calculate_lifc_len:     /* must hold privileges to enter here */
        * <interface name>:<logical interface id>
        */
       unsigned int normallen = 0;
+      uint64_t lifflags;
       
+      /* We should exclude ~IFF_UP interfaces, as we'll find out about them
+       * coming up later through RTM_NEWADDR message on the route socket.
+       */
+      if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
+                           lifreq->lifr_addr.ss_family)
+          || !CHECK_FLAG (lifflags, IFF_UP))
+        {
+          lifreq++;
+          continue;
+        }
+      
+      /* Find the normalised name */
       while ( (normallen < sizeof(lifreq->lifr_name))
              && ( *(lifreq->lifr_name + normallen) != '\0')
              && ( *(lifreq->lifr_name + normallen) != ':') )
@@ -180,6 +194,10 @@ calculate_lifc_len:     /* must hold privileges to enter here */
                      lifreq->lifr_name);
       else
         if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
+        
+      /* Poke the interface flags. Lets IFF_UP mangling kick in */
+      if_flags_update (ifp, ifp->flags);
+      
       lifreq++;
     }
 

+ 71 - 15
zebra/interface.c

@@ -187,6 +187,73 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc)
   return 0;
 }
 
+/* if_flags_mangle: A place for hacks that require mangling
+ * or tweaking the interface flags.
+ *
+ * ******************** Solaris flags hacks **************************
+ *
+ * Solaris IFF_UP flag reflects only the primary interface as the
+ * routing socket only sends IFINFO for the primary interface.  Hence  
+ * ~IFF_UP does not per se imply all the logical interfaces are also   
+ * down - which we only know of as addresses. Instead we must determine
+ * whether the interface really is up or not according to how many   
+ * addresses are still attached. (Solaris always sends RTM_DELADDR if
+ * an interface, logical or not, goes ~IFF_UP).
+ *
+ * Ie, we mangle IFF_UP to *additionally* reflect whether or not there
+ * are addresses left in struct connected, not just the actual underlying
+ * IFF_UP flag.
+ *
+ * We must hence remember the real state of IFF_UP, which we do in
+ * struct zebra_if.primary_state.
+ *
+ * Setting IFF_UP within zebra to administratively shutdown the
+ * interface will affect only the primary interface/address on Solaris.
+ ************************End Solaris flags hacks ***********************
+ */
+static inline void
+if_flags_mangle (struct interface *ifp, uint64_t *newflags)
+{
+#ifdef SUNOS_5
+  struct zebra_if *zif = ifp->info;
+  
+  zif->primary_state = *newflags & (IFF_UP & 0xff);
+  
+  if (CHECK_FLAG (zif->primary_state, IFF_UP)
+      || listcount(ifp->connected) > 0)
+    SET_FLAG (*newflags, IFF_UP);
+  else
+    UNSET_FLAG (*newflags, IFF_UP);
+#endif /* SUNOS_5 */
+}
+
+/* Update the flags field of the ifp with the new flag set provided.
+ * Take whatever actions are required for any changes in flags we care
+ * about.
+ *
+ * newflags should be the raw value, as obtained from the OS.
+ */
+void
+if_flags_update (struct interface *ifp, uint64_t newflags)
+{
+  if_flags_mangle (ifp, &newflags);
+    
+  if (if_is_operative (ifp))
+    {
+      /* operative -> inoperative? */
+      ifp->flags = newflags;
+      if (!if_is_operative (ifp))
+        if_down (ifp);
+    }
+  else
+    {
+      /* inoperative -> operative? */
+      ifp->flags = newflags;
+      if (if_is_operative (ifp))
+        if_up (ifp);
+    }
+}
+
 /* Wake up configured address if it is not in current kernel
    address. */
 static void
@@ -478,23 +545,12 @@ if_down (struct interface *ifp)
 void
 if_refresh (struct interface *ifp)
 {
-  if (if_is_operative (ifp))
-    {
-      if_get_flags (ifp);
-      if (! if_is_operative (ifp))
-	if_down (ifp);
-    }
-  else
-    {
-      if_get_flags (ifp);
-      if (if_is_operative (ifp))
-	if_up (ifp);
-    }
+  if_get_flags (ifp);
 }
 
 /* Printout flag information into vty */
 static void
-if_flag_dump_vty (struct vty *vty, unsigned long flag)
+if_flag_dump_vty (struct vty *vty, uint64_t flag)
 {
   int separator = 0;
 
@@ -526,8 +582,8 @@ if_flag_dump_vty (struct vty *vty, unsigned long flag)
   IFF_OUT_VTY (IFF_LINK2, "LINK2");
   IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST");
 #ifdef SOLARIS_IPV6
-  IFF_OUT_VTY (IFF_IPV4, "IFF_IPv4");
-  IFF_OUT_VTY (IFF_IPV6, "IFF_IPv6");
+  IFF_OUT_VTY (IFF_VIRTUAL, "IFF_VIRTUAL");
+  IFF_OUT_VTY (IFF_NOXMIT, "IFF_NOXMIT");
 #endif /* SOLARIS_IPV6 */
   vty_out (vty, ">");
 }

+ 9 - 0
zebra/interface.h

@@ -201,6 +201,14 @@ struct zebra_if
   struct irdp_interface irdp;
 #endif
 
+#ifdef SUNOS_5
+  /* the real IFF_UP state of the primary interface.
+   * need this to differentiate between all interfaces being
+   * down (but primary still plumbed) and primary having gone
+   * ~IFF_UP, and all addresses gone.
+   */
+  u_char primary_state;
+#endif /* SUNOS_5 */
 };
 
 extern void if_delete_update (struct interface *ifp);
@@ -208,6 +216,7 @@ extern void if_add_update (struct interface *ifp);
 extern void if_up (struct interface *);
 extern void if_down (struct interface *);
 extern void if_refresh (struct interface *);
+extern void if_flags_update (struct interface *, uint64_t);
 extern int if_subnet_add (struct interface *, struct connected *);
 extern int if_subnet_delete (struct interface *, struct connected *);
 

+ 4 - 3
zebra/ioctl.c

@@ -31,6 +31,7 @@
 
 #include "zebra/rib.h"
 #include "zebra/rt.h"
+#include "zebra/interface.h"
 
 extern struct zebra_privs_t zserv_privs;
 
@@ -350,12 +351,12 @@ if_get_flags (struct interface *ifp)
       return;
     }
 
-  ifp->flags = ifreq.ifr_flags & 0x0000ffff;
+  if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff));
 }
 
 /* Set interface flags */
 int
-if_set_flags (struct interface *ifp, unsigned long flags)
+if_set_flags (struct interface *ifp, uint64_t flags)
 {
   int ret;
   struct ifreq ifreq;
@@ -378,7 +379,7 @@ if_set_flags (struct interface *ifp, unsigned long flags)
 
 /* Unset interface's flag. */
 int
-if_unset_flags (struct interface *ifp, unsigned long flags)
+if_unset_flags (struct interface *ifp, uint64_t flags)
 {
   int ret;
   struct ifreq ifreq;

+ 2 - 2
zebra/ioctl.h

@@ -27,8 +27,8 @@
 extern void ifreq_set_name (struct ifreq *, struct interface *);
 extern int if_ioctl (u_long, caddr_t);
 
-extern int if_set_flags (struct interface *, unsigned long);
-extern int if_unset_flags (struct interface *, unsigned long);
+extern int if_set_flags (struct interface *, uint64_t);
+extern int if_unset_flags (struct interface *, uint64_t);
 extern void if_get_flags (struct interface *);
 
 extern int if_set_prefix (struct interface *, struct connected *);

+ 49 - 42
zebra/ioctl_solaris.c

@@ -31,14 +31,15 @@
 
 #include "zebra/rib.h"
 #include "zebra/rt.h"
+#include "zebra/interface.h"
 
 extern struct zebra_privs_t zserv_privs;
 
 /* clear and set interface name string */
 void
-lifreq_set_name (struct lifreq *lifreq, struct interface *ifp)
+lifreq_set_name (struct lifreq *lifreq, const char *ifname)
 {
-  strncpy (lifreq->lifr_name, ifp->name, IFNAMSIZ);
+  strncpy (lifreq->lifr_name, ifname, IFNAMSIZ);
 }
 
 /* call ioctl system call */
@@ -129,7 +130,7 @@ if_get_metric (struct interface *ifp)
   struct lifreq lifreq;
   int ret;
 
-  lifreq_set_name (&lifreq, ifp);
+  lifreq_set_name (&lifreq, ifp->name);
 
   if (ifp->flags & IFF_IPV4)
     ret = AF_IOCTL (AF_INET, SIOCGLIFMETRIC, (caddr_t) & lifreq);
@@ -158,7 +159,7 @@ if_get_mtu (struct interface *ifp)
   
   if (ifp->flags & IFF_IPV4)
     {
-      lifreq_set_name (&lifreq, ifp);
+      lifreq_set_name (&lifreq, ifp->name);
       ret = AF_IOCTL (AF_INET, SIOCGLIFMTU, (caddr_t) & lifreq);
       if (ret < 0)
         {
@@ -177,7 +178,7 @@ if_get_mtu (struct interface *ifp)
     return;
     
   memset(&lifreq, 0, sizeof(lifreq));
-  lifreq_set_name (&lifreq, ifp);
+  lifreq_set_name (&lifreq, ifp->name);
 
   ret = AF_IOCTL (AF_INET6, SIOCGLIFMTU, (caddr_t) & lifreq);
   if (ret < 0)
@@ -274,28 +275,28 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc)
   return 0;
 }
 
-/* Solaris IFF_UP flag reflects only the primary interface as the
- * routing socket only sends IFINFO for the primary interface.  Hence  
- * ~IFF_UP does not per se imply all the logical interfaces are also   
- * down - which we only know of as addresses. Instead we must determine
- * whether the interface really is up or not according to how many   
- * addresses are still attached. (Solaris always sends RTM_DELADDR if
- * an interface, logical or not, goes ~IFF_UP).
- *
- * Ie, we mangle IFF_UP to reflect whether or not there are addresses
- * left in struct connected, not the actual underlying IFF_UP flag
- * (which corresponds to just one address of all the logical interfaces)
- *
- * Setting IFF_UP within zebra to administratively shutdown the
- * interface will affect only the primary interface/address on Solaris.
+/* Get just the flags for the given name.
+ * Used by the normal 'if_get_flags' function, as well
+ * as the bootup interface-list code, which has to peek at per-address
+ * flags in order to figure out which ones should be ignored..
  */
-static inline void
-if_mangle_up (struct interface *ifp)
+int
+if_get_flags_direct (const char *ifname, uint64_t *flags, unsigned int af)
 {
-  if (listcount(ifp->connected) > 0)
-    SET_FLAG (ifp->flags, IFF_UP);
-  else
-    UNSET_FLAG (ifp->flags, IFF_UP);
+  struct lifreq lifreq;
+  int ret;
+    
+  lifreq_set_name (&lifreq, ifname);
+  
+  ret = AF_IOCTL (af, SIOCGLIFFLAGS, (caddr_t) &lifreq);
+  
+  if (ret)
+    zlog_debug ("%s: ifname %s, error %s (%d)",
+                __func__, ifname, safe_strerror (errno), errno);
+  
+  *flags = lifreq.lifr_flags;
+  
+  return ret;
 }
 
 /* get interface flags */
@@ -303,44 +304,50 @@ void
 if_get_flags (struct interface *ifp)
 {
   int ret4, ret6;
-  struct lifreq lifreq;
-  unsigned long flags4 = 0, flags6 = 0;
+  uint64_t newflags = 0;
+  uint64_t tmpflags;
 
   if (ifp->flags & IFF_IPV4)
     {
-      lifreq_set_name (&lifreq, ifp);
-      
-      ret4 = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      ret4 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET);
       
       if (!ret4)
-        flags4 = (lifreq.lifr_flags & 0xffffffff);
+        newflags |= tmpflags;
+      else if (errno == ENXIO)
+        {
+          /* it's gone */
+          UNSET_FLAG (ifp->flags, IFF_UP);
+          if_flags_update (ifp, ifp->flags);
+        }
     }
 
   if (ifp->flags & IFF_IPV6)
     {
-      lifreq_set_name (&lifreq, ifp);
-      
-      ret6 = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      ret6 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET6);
       
       if (!ret6)
-        flags6 = (lifreq.lifr_flags & 0xffffffff);
+        newflags |= tmpflags;
+      else if (errno == ENXIO)
+        {
+          /* it's gone */
+          UNSET_FLAG (ifp->flags, IFF_UP);
+          if_flags_update (ifp, ifp->flags);
+        }
     }
   
   /* only update flags if one of above succeeded */
   if ( !(ret4 && ret6) )
-    ifp->flags = (flags4 | flags6);
-
-  if_mangle_up (ifp);
+    if_flags_update (ifp, newflags);
 }
 
 /* Set interface flags */
 int
-if_set_flags (struct interface *ifp, unsigned long flags)
+if_set_flags (struct interface *ifp, uint64_t flags)
 {
   int ret;
   struct lifreq lifreq;
 
-  lifreq_set_name (&lifreq, ifp);
+  lifreq_set_name (&lifreq, ifp->name);
 
   lifreq.lifr_flags = ifp->flags;
   lifreq.lifr_flags |= flags;
@@ -363,12 +370,12 @@ if_set_flags (struct interface *ifp, unsigned long flags)
 
 /* Unset interface's flag. */
 int
-if_unset_flags (struct interface *ifp, unsigned long flags)
+if_unset_flags (struct interface *ifp, uint64_t flags)
 {
   int ret;
   struct lifreq lifreq;
 
-  lifreq_set_name (&lifreq, ifp);
+  lifreq_set_name (&lifreq, ifp->name);
 
   lifreq.lifr_flags = ifp->flags;
   lifreq.lifr_flags &= ~flags;

+ 47 - 29
zebra/kernel_socket.c

@@ -396,6 +396,14 @@ ifm_read (struct if_msghdr *ifm)
 		     ifm->ifm_index);
 	  return -1;
 	}
+
+#ifndef RTM_IFANNOUNCE
+      /* Down->Down interface should be ignored here.
+       * See further comment below.
+       */
+      if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP))
+        return 0;
+#endif /* !RTM_IFANNOUNCE */
       
       if (ifp == NULL)
         {
@@ -414,7 +422,7 @@ ifm_read (struct if_msghdr *ifm)
        * structure with ifindex IFINDEX_INTERNAL.
        */
       ifp->ifindex = ifm->ifm_index;
-      ifp->flags = ifm->ifm_flags;
+      if_flags_update (ifp, ifm->ifm_flags);
 #if defined(__bsdi__)
       if_kvm_get_mtu (ifp);
 #else
@@ -441,34 +449,26 @@ ifm_read (struct if_msghdr *ifm)
           return -1;
         }
       
-      if (if_is_up (ifp))
-	{
-	  ifp->flags = ifm->ifm_flags;
-	  if (! if_is_up (ifp))
-	    {
-	      if_down (ifp);
+      /* update flags and handle operative->inoperative transition, if any */
+      if_flags_update (ifp, ifm->ifm_flags);
+      
 #ifndef RTM_IFANNOUNCE
-              /* No RTM_IFANNOUNCE on this platform, so we can never
-               * distinguish between down and delete. We must presume
-               * it has been deleted.
-               * Eg, Solaris will not notify us of unplumb.
-               *
-               * XXX: Fixme - this should be runtime detected
-               * So that a binary compiled on a system with IFANNOUNCE
-               * will still behave correctly if run on a platform without
-               */
-              if_delete_update (ifp);
+      if (!if_is_up (ifp))
+          {
+            /* No RTM_IFANNOUNCE on this platform, so we can never
+             * distinguish between ~IFF_UP and delete. We must presume
+             * it has been deleted.
+             * Eg, Solaris will not notify us of unplumb.
+             *
+             * XXX: Fixme - this should be runtime detected
+             * So that a binary compiled on a system with IFANNOUNCE
+             * will still behave correctly if run on a platform without
+             */
+            if_delete_update (ifp);
+          }
 #endif /* RTM_IFANNOUNCE */
-            }
-	}
-      else
-	{
-	  ifp->flags = ifm->ifm_flags;
-	  if (if_is_up (ifp))
-	    if_up (ifp);
-	}
     }
-  
+
 #ifdef HAVE_NET_RT_IFLIST
   ifp->stats = ifm->ifm_data;
 #endif /* HAVE_NET_RT_IFLIST */
@@ -546,9 +546,6 @@ ifam_read (struct ifa_msghdr *ifam)
   
   ifp->metric = ifam->ifam_metric;
   
-  /* Check interface flag for implicit up of the interface. */
-  if_refresh (ifp);
-
   /* Add connected address. */
   switch (sockunion_family (&addr))
     {
@@ -587,6 +584,27 @@ ifam_read (struct ifa_msghdr *ifam)
       /* Unsupported family silently ignore... */
       break;
     }
+  
+  /* Check interface flag for implicit up of the interface. */
+  if_refresh (ifp);
+
+#ifdef SUNOS_5
+  /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. 
+   * See comments for SUNOS_5 in interface.c::if_flags_mangle.
+   * 
+   * Here we take care of case where the real IFF_UP was previously
+   * unset (as kept in struct zebra_if.primary_state) and the mangled
+   * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned
+   * to unset due to the lost non-primary address having DELADDR'd.
+   *
+   * we must delete the interface, because in between here and next
+   * event for this interface-name the administrator could unplumb
+   * and replumb the interface.
+   */
+  if (!if_is_up (ifp))
+    if_delete_update (ifp);
+#endif /* SUNOS_5 */
+  
   return 0;
 }
 

+ 1 - 0
zebra/rt.h

@@ -25,6 +25,7 @@
 
 #include "prefix.h"
 #include "if.h"
+#include "zebra/rib.h"
 
 extern int kernel_add_ipv4 (struct prefix *, struct rib *);
 extern int kernel_delete_ipv4 (struct prefix *, struct rib *);