[quagga-users 4920] Re: Re[3]: Re[2]: why quagga behave so strange?

Paul Jakma paul at clubi.ie
Wed Jul 13 17:58:36 IST 2005


Hi,

On Tue, 28 Jun 2005, jing shen wrote:

> thanks, I'll be waiting for patch.

Sorry for the delay, could you try the attached patch?

I havn't yet tested this exact version of the patch (its a result of 
merging to CVS), but will go off to do that now, if there are 
problems an updated version will be at:

http://hibernia.jakma.org/~paul/patches/quagga-zebra-solaris-0.99.diff

With this patch, zebra should treat Solaris "logical interfaces" as 
addresses of the primary interface, recording the "logical 
interface" name as an address 'label' if possible. So, eg:

lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
         inet 127.0.0.1 netmask ff000000
bge0: flags=1004843<UP,BROADCAST,RUNNING,MULTICAST,DHCP,IPv4> mtu 1500 index 2
         inet 10.8.57.40 netmask ffffff00 broadcast 10.8.57.255
         ether 0:3:ba:44:43:42
vni0: flags=20010100c1<UP,RUNNING,NOARP,NOXMIT,IPv4,VIRTUAL> mtu 0 index 9
         inet 172.17.0.1 netmask ffffff00
vni0:1: flags=20010100c1<UP,RUNNING,NOARP,NOXMIT,IPv4,VIRTUAL> mtu 0 index 9
         inet 172.17.1.1 netmask ffffff00
vni0:2: flags=20010100c1<UP,RUNNING,NOARP,NOXMIT,IPv4,VIRTUAL> mtu 0 index 9
         inet 172.17.2.1 netmask ffffff00
lo0: flags=2002000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv6,VIRTUAL> mtu 8252 index 1
         inet6 ::1/128
bge0: flags=2000841<UP,RUNNING,MULTICAST,IPv6> mtu 1500 index 2
         inet6 fe80::203:baff:fe44:4342/10
         ether 0:3:ba:44:43:42
bge0:1: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
         inet6 2002:a08:3903:1:203:baff:fe44:4342/64

Should appear in zebra's "show interface" as:

Interface bge0 is up, line protocol detection is disabled
   index 2 metric 1 mtu 1500 <UP,BROADCAST,RUNNING,MULTICAST,IFF_IPv4,IFF_IPv6>
   inet 10.8.57.40/24 broadcast 10.8.57.255
   inet6 fe80::203:baff:fe44:4342/10
   inet6 2002:a08:3903:1:203:baff:fe44:4342/10 bge0:1
Interface lo0 is up, line protocol detection is disabled
   index 1 metric 1 mtu 8232 <UP,LOOPBACK,RUNNING,MULTICAST,IFF_IPv4,IFF_IPv6>mtu6 8252
   inet 127.0.0.1/8
   inet6 ::1/128
Interface vni0 is up, line protocol detection is disabled
   index 9 metric 1 mtu 0 <UP,RUNNING,NOARP,IFF_IPv4>
   inet 172.17.1.1/24 vni0:1
   inet 172.17.2.1/24 vni0:2

The address 'labels' wont appear on Solaris 9 though.

This patch should solve all the alias address issues of zebra on 
solaris. You should, with this patch, /never/ get a logical interface 
appearing as its own interface in zebra, addresses should always 
appear on the correct interface, regardless of IPv4/IPv6.

Feedback greatly appreciated. :)

regards,
-- 
Paul Jakma	paul at clubi.ie	paul at jakma.org	Key ID: 64A2FF6A
Fortune:
There are people so addicted to exaggeration that they can't tell the
truth without lying.
 		-- Josh Billings
-------------- next part --------------
Index: zebra/connected.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/connected.c,v
retrieving revision 1.14
diff -u -p -r1.14 connected.c
--- zebra/connected.c	28 Jun 2005 17:17:12 -0000	1.14
+++ zebra/connected.c	13 Jul 2005 15:43:05 -0000
@@ -227,7 +227,7 @@ connected_down_ipv4 (struct interface *i
 /* Delete connected IPv4 route to the interface. */
 void
 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
-		       u_char prefixlen, struct in_addr *broad, char *label)
+		       u_char prefixlen, struct in_addr *broad)
 {
   struct prefix_ipv4 p;
   struct connected *ifc;
@@ -316,7 +316,7 @@ connected_up_ipv6 (struct interface *ifp
 /* Add connected IPv6 route to the interface. */
 void
 connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
-		    u_char prefixlen, struct in6_addr *broad)
+		    u_char prefixlen, struct in6_addr *broad, char *label)
 {
   struct prefix_ipv6 *p;
   struct connected *ifc;
@@ -353,6 +353,10 @@ connected_add_ipv6 (struct interface *if
       listnode_add (ifp->connected, ifc);
     }
 
+  /* Label of this address. */
+  if (label)
+    ifc->label = strdup (label);
+  
   /* Update interface address information to protocol daemon. */
   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
     {
Index: zebra/connected.h
===================================================================
RCS file: /var/cvsroot/quagga/zebra/connected.h,v
retrieving revision 1.2
diff -u -p -r1.2 connected.h
--- zebra/connected.h	28 Jun 2005 17:17:12 -0000	1.2
+++ zebra/connected.h	13 Jul 2005 15:43:05 -0000
@@ -32,7 +32,7 @@ connected_add_ipv4 (struct interface *if
 
 extern void
 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
-		       u_char prefixlen, struct in_addr *broad, char *label);
+		       u_char prefixlen, struct in_addr *broad);
 
 extern void connected_up_ipv4 (struct interface *, struct connected *);
 extern void connected_down_ipv4 (struct interface *, struct connected *);
@@ -43,7 +43,7 @@ connected_check_ipv6 (struct interface *
 
 extern void
 connected_add_ipv6 (struct interface *ifp, struct in6_addr *address,
-		    u_char prefixlen, struct in6_addr *broad);
+		    u_char prefixlen, struct in6_addr *broad, char *label);
 extern void
 connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
 		       u_char prefixlen, struct in6_addr *broad);
Index: zebra/if_ioctl.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/if_ioctl.c,v
retrieving revision 1.8
diff -u -p -r1.8 if_ioctl.c
--- zebra/if_ioctl.c	28 Jun 2005 17:17:12 -0000	1.8
+++ zebra/if_ioctl.c	13 Jul 2005 15:43:05 -0000
@@ -305,7 +305,8 @@ if_getaddrs (void)
 	    }	
 #endif          
 
-	  connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
+	  connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, 
+	                      dest_pnt, NULL);
 	}
 #endif /* HAVE_IPV6 */
     }
Index: zebra/if_ioctl_solaris.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/if_ioctl_solaris.c,v
retrieving revision 1.9
diff -u -p -r1.9 if_ioctl_solaris.c
--- zebra/if_ioctl_solaris.c	10 Apr 2005 16:54:26 -0000	1.9
+++ zebra/if_ioctl_solaris.c	13 Jul 2005 15:43:05 -0000
@@ -34,7 +34,7 @@
 #include "zebra/interface.h"
 
 void lifreq_set_name (struct lifreq *, struct interface *);
-static int if_get_addr (struct interface *, struct sockaddr *);
+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;
 
@@ -108,7 +108,7 @@ calculate_lifc_len:     /* must hold pri
   lastneeded = needed;
 
   lifconf.lifc_family = af;
-  lifconf.lifc_flags = 0;
+  lifconf.lifc_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
   lifconf.lifc_len = needed;
   lifconf.lifc_buf = buf;
 
@@ -138,9 +138,24 @@ calculate_lifc_len:     /* must hold pri
 
   for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
     {
-      ifp = if_get_by_name_len(lifreq->lifr_name,
-			       strnlen(lifreq->lifr_name,
-				       sizeof(lifreq->lifr_name)));
+      /* we treat Solaris logical interfaces as addresses, because that is
+       * how PF_ROUTE on Solaris treats them. Hence we can not directly use
+       * the lifreq_name to get the ifp.  We need to normalise the name
+       * before attempting get.
+       *
+       * Solaris logical interface names are in the form of:
+       * <interface name>:<logical interface id>
+       */
+      unsigned int normallen = 0;
+      
+      printf ("%s: lifreq name %s\n", __func__, lifreq->lifr_name);
+      
+      while ( (normallen < sizeof(lifreq->lifr_name))
+             && ( *(lifreq->lifr_name + normallen) != '\0')
+             && ( *(lifreq->lifr_name + normallen) != ':') )
+        normallen++;
+      
+      ifp = if_get_by_name_len(lifreq->lifr_name, normallen);
 
       if (lifreq->lifr_addr.ss_family == AF_INET)
         ifp->flags |= IFF_IPV4;
@@ -158,7 +173,15 @@ calculate_lifc_len:     /* must hold pri
       if_add_update (ifp);
 
       interface_info_ioctl (ifp);
-      if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr);
+      
+      /* If a logical interface pass the full name so it can be
+       * as a label on the address
+       */
+      if ( *(lifreq->lifr_name + normallen) != '\0')
+        if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
+                     lifreq->lifr_name);
+      else
+        if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
       lifreq++;
     }
 
@@ -210,7 +233,7 @@ if_get_index (struct interface *ifp)
 #define SIN6(s) ((struct sockaddr_in6 *)(s))
 
 static int
-if_get_addr (struct interface *ifp, struct sockaddr *addr)
+if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
 {
   int ret;
   struct lifreq lifreq;
@@ -306,11 +329,11 @@ if_get_addr (struct interface *ifp, stru
   /* Set address to the interface. */
   if (af == AF_INET)
     connected_add_ipv4 (ifp, 0, &SIN (addr)->sin_addr, prefixlen,
-                        (struct in_addr *) dest_pnt, NULL);
+                        (struct in_addr *) dest_pnt, label);
 #ifdef HAVE_IPV6
   else if (af == AF_INET6)
     connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen,
-                        (struct in6_addr *) dest_pnt);
+                        (struct in6_addr *) dest_pnt, label);
 #endif /* HAVE_IPV6 */
 
   return 0;
@@ -332,6 +355,7 @@ interface_list ()
 {
   interface_list_ioctl (AF_INET);
   interface_list_ioctl (AF_INET6);
+  interface_list_ioctl (AF_UNSPEC);
 }
 
 struct connected *
Index: zebra/interface.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/interface.c,v
retrieving revision 1.27
diff -u -p -r1.27 interface.c
--- zebra/interface.c	28 Jun 2005 17:17:12 -0000	1.27
+++ zebra/interface.c	13 Jul 2005 15:43:06 -0000
@@ -291,13 +291,7 @@ if_add_update (struct interface *ifp)
 }
 
 
-/* Handle an interface delete event
- * 
- * This function is only called  when support for
- * RTM_IFANNOUNCE or AF_NETLINK sockets (RTM_DELLINK message)
- * is available. It is not called on, eg, Solaris.
- */
-#if (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK))
+/* Handle an interface delete event */
 void 
 if_delete_update (struct interface *ifp)
 {
@@ -405,7 +399,6 @@ if_delete_update (struct interface *ifp)
      interface deletion message. */
   ifp->ifindex = IFINDEX_INTERNAL;
 }
-#endif /* (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK) */
 
 /* Interface is up. */
 void
Index: zebra/ioctl_solaris.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/ioctl_solaris.c,v
retrieving revision 1.6
diff -u -p -r1.6 ioctl_solaris.c
--- zebra/ioctl_solaris.c	30 Jan 2005 18:49:28 -0000	1.6
+++ zebra/ioctl_solaris.c	13 Jul 2005 15:43:06 -0000
@@ -278,7 +278,7 @@ if_unset_prefix (struct interface *ifp, 
 void
 if_get_flags (struct interface *ifp)
 {
-  int ret;
+  int ret4, ret6;
   struct lifreq lifreq;
   unsigned long flags4 = 0, flags6 = 0;
 
@@ -286,25 +286,33 @@ if_get_flags (struct interface *ifp)
     {
       lifreq_set_name (&lifreq, ifp);
       
-      ret = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
-
-      flags4 = (lifreq.lifr_flags & 0xffffffff);
-      if (!(flags4 & IFF_UP))
-        flags4 &= ~IFF_IPV4;
+      ret4 = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      
+      if (!ret4)
+        {
+          flags4 = (lifreq.lifr_flags & 0xffffffff);
+          if ( !CHECK_FLAG(flags4, IFF_UP) )
+            UNSET_FLAG (flags4, IFF_IPV4);
+        }
     }
 
   if (ifp->flags & IFF_IPV6)
     {
       lifreq_set_name (&lifreq, ifp);
       
-      ret = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
-              
-      flags6 = (lifreq.lifr_flags & 0xffffffff);
-      if (!(flags6 & IFF_UP))
-        flags6 &= ~IFF_IPV6;
+      ret6 = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      
+      if (!ret6)
+        {
+          flags6 = (lifreq.lifr_flags & 0xffffffff);
+          if ( !CHECK_FLAG (flags6, IFF_UP) )
+            UNSET_FLAG (flags6, IFF_IPV6);
+        }
     }
-
-  ifp->flags = (flags4 | flags6);
+  
+  /* only update flags if one of above succeeded */
+  if ( !(ret4 && ret6) )
+    ifp->flags = (flags4 | flags6);
 }
 
 /* Set interface flags */
Index: zebra/kernel_socket.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/kernel_socket.c,v
retrieving revision 1.26
diff -u -p -r1.26 kernel_socket.c
--- zebra/kernel_socket.c	28 Jun 2005 17:20:26 -0000	1.26
+++ zebra/kernel_socket.c	13 Jul 2005 15:43:06 -0000
@@ -83,7 +83,7 @@ extern struct zebra_t zebrad;
       int len = SAROUNDUP ((PNT)); \
       if ( ((DEST) != NULL) && \
            af_check (((struct sockaddr *)(PNT))->sa_family)) \
-        memcpy ((caddr_t)(DEST), (PNT), len); \
+        memcpy ((DEST), (PNT), len); \
       (PNT) += len; \
     }
 #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \
@@ -91,10 +91,31 @@ extern struct zebra_t zebrad;
     { \
       int len = SAROUNDUP ((PNT)); \
       if ( ((DEST) != NULL) ) \
-        memcpy ((caddr_t)(DEST), (PNT), len); \
+        memcpy ((DEST), (PNT), len); \
       (PNT) += len; \
     }
 
+#define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \
+  if ((RTMADDRS) & (RTA)) \
+    { \
+      int len = SAROUNDUP ((PNT)); \
+      struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \
+      if (IS_ZEBRA_DEBUG_KERNEL) \
+        zlog_debug ("%s: RTA_SDL_GET nlen %d, alen %d", \
+                    __func__, sdl->sdl_nlen, sdl->sdl_alen); \
+      if ( ((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \
+           && (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len) ) \
+        { \
+          memcpy ((DEST), sdl->sdl_data, sdl->sdl_nlen); \
+          (DEST)[sdl->sdl_nlen] = '\0'; \
+          (LEN) = sdl->sdl_nlen; \
+        } \
+      (PNT) += len; \
+    } \
+  else \
+    { \
+      (LEN) = 0; \
+    }
 /* Routing socket message types. */
 struct message rtm_type_str[] =
 {
@@ -144,6 +165,9 @@ struct message rtm_flag_str[] =
   {RTF_LLINFO,    "LLINFO"},
   {RTF_STATIC,    "STATIC"},
   {RTF_BLACKHOLE, "BLACKHOLE"},
+#ifdef RTF_PRIVATE
+  {RTF_PRIVATE,   "PRIVATE"},
+#endif /* RTF_PRIVATE */
   {RTF_PROTO1,    "PROTO1"},
   {RTF_PROTO2,    "PROTO2"},
 #ifdef RTF_PRCLONING
@@ -167,6 +191,12 @@ struct message rtm_flag_str[] =
 #ifdef RTF_MULTICAST
   {RTF_MULTICAST, "MULTICAST"},
 #endif /* RTF_MULTICAST */
+#ifdef RTF_MULTIRT
+  {RTF_MULTIRT,   "MULTIRT"},
+#endif /* RTF_MULTIRT */
+#ifdef RTF_SETSRC
+  {RTF_SETSRC,    "SETSRC"},
+#endif /* RTF_SETSRC */
   {0,             NULL}
 };
 
@@ -215,9 +245,21 @@ ifan_read (struct if_announcemsghdr *ifa
 {
   struct interface *ifp;
 
-  ifp = if_lookup_by_index (ifan->ifan_index);
-  if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
+  /* some systems (Solaris particularly) have a 1:many ifindex:ifname
+   */
+  ifp = if_lookup_by_name_len (ifan->ifan_name, sizeof(ifan->ifan_name));
+  
+  if (ifp)
+    assert ( (ifp->ifindex == IFINDEX_INTERNAL)
+            || (ifp->ifindex == ifan->ifan_index) );
+
+  if ( (ifp == NULL || ifp->ifindex == IFINDEX_INTERNAL)
+      && ifan->ifan_what == IFAN_ARRIVAL)
     {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+        zlog_debug ("%s: creating interface for ifindex %d, name %s",
+                    __func__, ifan->ifan_index, ifan->ifan_name);
+      
       /* Create Interface */
       ifp = if_get_by_name_len(ifan->ifan_name,
 			       strnlen(ifan->ifan_name,
@@ -225,19 +267,16 @@ ifan_read (struct if_announcemsghdr *ifa
       ifp->ifindex = ifan->ifan_index;
 
       if_add_update (ifp);
+      if_get_flags (ifp);
+      if_get_mtu (ifp);
+      if_get_metric (ifp);
     }
   else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE)
-    {
-      if_delete_update (ifp);
-      if_delete (ifp);
-    }
-
-  if_get_flags (ifp);
-  if_get_mtu (ifp);
-  if_get_metric (ifp);
-
+    if_delete_update (ifp);
+  
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("interface %s index %d", ifp->name, ifp->ifindex);
+    zlog_debug ("%s: interface %s index %d", 
+                __func__, ifan->ifan_name, ifan->ifan_index);
 
   return 0;
 }
@@ -252,10 +291,13 @@ int
 ifm_read (struct if_msghdr *ifm)
 {
   struct interface *ifp = NULL;
-  struct sockaddr_dl *sdl = NULL;
-  void *cp;
-  unsigned int i;
-
+  char ifname[IFNAMSIZ];
+  short ifnlen = 0;
+  caddr_t *cp;
+  
+  /* terminate ifname at head (for strnlen) and tail (for safety) */
+  ifname[IFNAMSIZ - 1] = '\0';
+  
   /* paranoia: sanity check structure */
   if (ifm->ifm_msglen < sizeof(struct if_msghdr))
     {
@@ -282,68 +324,56 @@ ifm_read (struct if_msghdr *ifm)
   	cp = cp + 12;
 #endif
 
+  RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
+  RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
+  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
+  RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp);
+  
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)"));
+  
   /* 
-   * Check for each sockaddr in turn, advancing over it.  After this
-   * loop, sdl should point to a sockaddr_dl iff one was present.
+   * Look up on ifindex first, because ifindices are the primary handle for
+   * interfaces across the user/kernel boundary, for most systems.  (Some
+   * messages, such as up/down status changes on NetBSD, do not include a
+   * sockaddr_dl).
    */
-  for (i = 1; i != 0; i <<= 1) 
+  if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL )
     {
-      if (i & ifm->ifm_addrs)
+      /* we have an ifp, verify that the name matches as some systems,
+       * eg Solaris, have a 1:many association of ifindex:ifname
+       * if they dont match, we dont have the correct ifp and should
+       * set it back to NULL to let next check do lookup by name
+       */
+      if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) )
         {
-	  if (i == RTA_IFP)
-	    {
-	      sdl = (struct sockaddr_dl *)cp;
-	      break;
-            }
-	  /* XXX warning: pointer of type `void *' used in arithmetic */
-	  cp += SAROUNDUP(cp);
+          if (IS_ZEBRA_DEBUG_KERNEL)
+            zlog_debug ("%s: ifp name %s doesnt match sdl name %s",
+                        __func__, ifp->name, ifname);
+          ifp = NULL;
         }
     }
-
-  /* Ensure that sdl, if present, is actually a sockaddr_dl. */
-  if (sdl != NULL && sdl->sdl_family != AF_LINK)
-    {
-      zlog_err ("ifm_read: sockaddr_dl bad AF %d\n",
-		sdl->sdl_family);
-      return -1;
-    }
-
-  /* 
-   * Look up on ifindex first, because ifindices are the primary
-   * handle for interfaces across the user/kernel boundary.  (Some
-   * messages, such as up/down status changes on NetBSD, do not
-   * include a sockaddr_dl).
-   */
-  ifp = if_lookup_by_index (ifm->ifm_index);
-
+  
   /* 
-   * If lookup by index was unsuccessful and we have a name, try
-   * looking up by name.  Interfaces specified in the configuration
-   * file for which the ifindex has not been determined will have
-   * ifindex == IFINDEX_INTERNAL, and such interfaces are found by this search,
-   * and then their ifindex values can be filled in.
+   * If we dont have an ifp, try looking up by name.  Particularly as some
+   * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname
+   * is therefore our unique handle to that interface.
+   *
+   * Interfaces specified in the configuration file for which the ifindex
+   * has not been determined will have ifindex == IFINDEX_INTERNAL, and such
+   * interfaces are found by this search, and then their ifindex values can
+   * be filled in.
    */
-  if (ifp == NULL && sdl != NULL)
-    {
-      /*
-       * paranoia: sanity check name length.  nlen does not include
-       * trailing zero, but IFNAMSIZ max length does.
-       *
-       * XXX Is this test correct?  Should it be '>=' or '>'?  And is it even
-       * necessary now that we are using if_lookup_by_name_len?
-       */
-      if (sdl->sdl_nlen >= IFNAMSIZ)
-	{
-	  zlog_err ("ifm_read: illegal sdl_nlen %d\n", sdl->sdl_nlen);
-	  return -1;
-	}
-
-      ifp = if_lookup_by_name_len (sdl->sdl_data, sdl->sdl_nlen);
-    }
+  if ( (ifp == NULL) && ifnlen)
+    ifp = if_lookup_by_name (ifname);
 
   /*
-   * If ifp does not exist or has an invalid index (IFINDEX_INTERNAL), create or
-   * fill in an interface.
+   * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL),
+   * create or fill in an interface.
    */
   if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL))
     {
@@ -351,17 +381,25 @@ ifm_read (struct if_msghdr *ifm)
        * To create or fill in an interface, a sockaddr_dl (via
        * RTA_IFP) is required.
        */
-      if (sdl == NULL)
+      if (!ifnlen)
 	{
-	  zlog_warn ("Interface index %d (new) missing RTA_IFP sockaddr_dl\n",
+	  zlog_warn ("Interface index %d (new) missing ifname\n",
 		     ifm->ifm_index);
 	  return -1;
 	}
-
+      
       if (ifp == NULL)
-	/* Interface that zebra was not previously aware of, so create. */ 
-      	ifp = if_create (sdl->sdl_data, sdl->sdl_nlen);
+        {
+	  /* Interface that zebra was not previously aware of, so create. */ 
+	  ifp = if_create (ifname, ifnlen);
+	  if (IS_ZEBRA_DEBUG_KERNEL)
+	    zlog_debug ("%s: creating ifp for ifindex %d", 
+	                __func__, ifm->ifm_index);
+        }
 
+      if (IS_ZEBRA_DEBUG_KERNEL)
+        zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d",
+                    __func__, ifp->name, ifp->ifindex);
       /* 
        * Fill in newly created interface structure, or larval
        * structure with ifindex IFINDEX_INTERNAL.
@@ -375,13 +413,6 @@ ifm_read (struct if_msghdr *ifm)
 #endif /* __bsdi__ */
       if_get_metric (ifp);
 
-      /* 
-       * XXX sockaddr_dl contents can be larger than the structure
-       * definition, so the user of the stored structure must be
-       * careful not to read off the end.
-       */
-      memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
-
       if_add_update (ifp);
     }
   else
@@ -393,11 +424,31 @@ ifm_read (struct if_msghdr *ifm)
      * but apparently do not trigger action.)
      */
     {
+      if (ifp->ifindex != ifm->ifm_index)
+        {
+          zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, "
+                     "ifm index %d", 
+                     __func__, ifp->name, ifp->ifindex, ifm->ifm_index);
+          return -1;
+        }
+      
       if (if_is_up (ifp))
 	{
 	  ifp->flags = ifm->ifm_flags;
 	  if (! if_is_up (ifp))
-	    if_down (ifp);
+	    {
+	      if_down (ifp);
+#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
+               */
+              if_delete_update (ifp);
+#endif /* RTM_IFANNOUNCE */  
+            }
 	}
       else
 	{
@@ -412,7 +463,8 @@ ifm_read (struct if_msghdr *ifm)
 #endif /* HAVE_NET_RT_IFLIST */
 
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("interface %s index %d", ifp->name, ifp->ifindex);
+    zlog_debug ("%s: interface %s index %d", 
+                __func__, ifp->name, ifp->ifindex);
 
   return 0;
 }
@@ -422,7 +474,9 @@ void
 ifam_read_mesg (struct ifa_msghdr *ifm,
 		union sockunion *addr,
 		union sockunion *mask,
-		union sockunion *dest)
+		union sockunion *dest,
+		char *ifname,
+		short *ifnlen)
 {
   caddr_t pnt, end;
 
@@ -439,11 +493,16 @@ ifam_read_mesg (struct ifa_msghdr *ifm,
   RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifam_addrs, pnt);
   RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
-  RTA_ADDR_GET (NULL, RTA_IFP, ifm->ifam_addrs, pnt);
+  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
   RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
   RTA_ADDR_GET (dest, RTA_BRD, ifm->ifam_addrs, pnt);
 
+  if (IS_ZEBRA_DEBUG_KERNEL)
+      zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", 
+                  __func__, ifm->ifam_index, 
+                  (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs);
+  
   /* Assert read up end point matches to end point */
   if (pnt != end)
     zlog_warn ("ifam_read() does't read all socket data");
@@ -453,20 +512,46 @@ ifam_read_mesg (struct ifa_msghdr *ifm,
 int
 ifam_read (struct ifa_msghdr *ifam)
 {
-  struct interface *ifp;
-  union sockunion addr, mask, gate;
-
-  /* Check does this interface exist or not. */
-  ifp = if_lookup_by_index (ifam->ifam_index);
-  if (ifp == NULL) 
+  struct interface *ifp = NULL;
+  union sockunion addr, mask, brd;
+  char ifname[INTERFACE_NAMSIZ];
+  short ifnlen = 0;
+  char isalias = 0;
+  
+  ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0';
+  
+  /* Allocate and read address information. */
+  ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen);
+  
+  /* name is the canonical handle for an interface */
+  if (ifnlen)
+    ifp = if_lookup_by_name (ifname);
+  else
+    zlog_warn ("%s: no interface name", __func__);
+  
+  /* No interface name. Maybe no RTA_IFP was supplied, try index lookup
+   * This could give us wrong ifp on 1:many ifindex:ifname systems
+   */
+  if (ifp == NULL 
+      && ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) )
     {
-      zlog_warn ("no interface for index %d", ifam->ifam_index); 
+      zlog_warn ("%s: no interface for ifname %s, index %d", 
+                 __func__, ifname, ifam->ifam_index);
       return -1;
     }
-
-  /* Allocate and read address information. */
-  ifam_read_mesg (ifam, &addr, &mask, &gate);
-
+  
+  if (ifp->ifindex != ifam->ifam_index)
+    {
+      zlog_warn ("%s: index mismatch, ifam: name %s, index %d, "
+                 "ifp: name %s, index %d",
+                 __func__, ifname, ifam->ifam_index,
+                 ifp->name, ifp->ifindex);
+      return -1;
+    }
+  
+  if (strncmp (ifp->name, ifname, INTERFACE_NAMSIZ))
+    isalias = 1;
+  
   /* Check interface flag for implicit up of the interface. */
   if_refresh (ifp);
 
@@ -477,11 +562,12 @@ ifam_read (struct ifa_msghdr *ifam)
       if (ifam->ifam_type == RTM_NEWADDR)
 	connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, 
 			    ip_masklen (mask.sin.sin_addr),
-			    &gate.sin.sin_addr, NULL);
+			    &brd.sin.sin_addr,
+			    (isalias ? ifname : NULL) );
       else
 	connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, 
 			       ip_masklen (mask.sin.sin_addr),
-			       &gate.sin.sin_addr, NULL);
+			       &brd.sin.sin_addr);
       break;
 #ifdef HAVE_IPV6
     case AF_INET6:
@@ -494,12 +580,13 @@ ifam_read (struct ifa_msghdr *ifam)
 	connected_add_ipv6 (ifp,
 			    &addr.sin6.sin6_addr, 
 			    ip6_masklen (mask.sin6.sin6_addr),
-			    &gate.sin6.sin6_addr);
+			    &brd.sin6.sin6_addr,
+			    (isalias ? ifname : NULL) );
       else
 	connected_delete_ipv6 (ifp,
 			       &addr.sin6.sin6_addr, 
 			       ip6_masklen (mask.sin6.sin6_addr),
-			       &gate.sin6.sin6_addr);
+			       &brd.sin6.sin6_addr);
       break;
 #endif /* HAVE_IPV6 */
     default:
@@ -514,7 +601,9 @@ int
 rtm_read_mesg (struct rt_msghdr *rtm,
 	       union sockunion *dest,
 	       union sockunion *mask,
-	       union sockunion *gate)
+	       union sockunion *gate,
+	       char *ifname,
+	       short *ifnlen)
 {
   caddr_t pnt, end;
 
@@ -538,7 +627,7 @@ rtm_read_mesg (struct rt_msghdr *rtm,
   RTA_ADDR_GET (gate, RTA_GATEWAY, rtm->rtm_addrs, pnt);
   RTA_ATTR_GET (mask, RTA_NETMASK, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_GENMASK, rtm->rtm_addrs, pnt);
-  RTA_ADDR_GET (NULL, RTA_IFP, rtm->rtm_addrs, pnt);
+  RTA_NAME_GET (ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen);
   RTA_ADDR_GET (NULL, RTA_IFA, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_BRD, rtm->rtm_addrs, pnt);
@@ -561,6 +650,8 @@ rtm_read (struct rt_msghdr *rtm)
   int flags;
   u_char zebra_flags;
   union sockunion dest, mask, gate;
+  char ifname[INTERFACE_NAMSIZ + 1];
+  short ifnlen = 0;
 
   zebra_flags = 0;
 
@@ -571,7 +662,7 @@ rtm_read (struct rt_msghdr *rtm)
 
   /* Read destination and netmask and gateway from rtm message
      structure. */
-  flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
+  flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
 
 #ifdef RTF_CLONED	/*bsdi, netbsd 1.6*/
   if (flags & RTF_CLONED)
@@ -812,7 +903,7 @@ rtmsg_debug (struct rt_msghdr *rtm)
   zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
   rtm_flag_dump (rtm->rtm_flags);
   zlog_debug ("Kernel: message seq %d", rtm->rtm_seq);
-  zlog_debug ("Kernel: pid %d", rtm->rtm_pid);
+  zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs);
 }
 
 /* This is pretty gross, better suggestions welcome -- mhandler */


More information about the Quagga-users mailing list