[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