summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/ChangeLog37
-rw-r--r--zebra/connected.c12
-rw-r--r--zebra/connected.h5
-rw-r--r--zebra/if_ioctl.c3
-rw-r--r--zebra/if_ioctl_solaris.c50
-rw-r--r--zebra/if_proc.c2
-rw-r--r--zebra/interface.c15
-rw-r--r--zebra/ioctl_solaris.c50
-rw-r--r--zebra/kernel_socket.c14
-rw-r--r--zebra/rt_netlink.c4
10 files changed, 149 insertions, 43 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 0d69e751..e1723603 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,40 @@
+2005-11-03 Paul Jakma <paul.jakma@sun.com>
+
+ * connected.{c,h}: Include memory.h
+ (connected_add_ipv4) Use MTYPE for ifc label.
+ (connected_add_ipv6) Also should accept label. Store it in ifp.
+ (connected_del_ipv4) Taking label as argument is pointless.
+ * rt_netlink.c: (netlink_interface_addr) update label usage
+ for connected_{add,delete} functions.
+ * if_ioctl.c: (if_getaddrs) NULL label for connected_add_ipv6.
+ * if_ioctl_solaris.c: (interface_list_ioctl) Pass LIFC_NOXMIT
+ so we also find out about NOXMIT interfaces like VNI.
+ Bit of hackery to turn interface names into the primary
+ interface name, later with routing socket messages we only
+ will about primary interfaces anyway, so we must normalise
+ the name.
+ (if_get_addr) take label as argument, so it can
+ be passed to connected_add.
+ If label is provided, then it is interface name to issue the
+ ioctl for address information on, not the ifp name.
+ (interface_list) List AF_UNSPEC too, just in case.
+ * if_proc.c: (ifaddr_proc_ipv6) label for connected_add_ipv6.
+ * interface.c: (if_addr_wakeup) Some very bogus code - sets
+ IFF_RUNNING - add comment.
+ (if_refresh)
+ (ip_address_install) Use MTYPE for ifc label.
+ * ioctl_solaris.c: (if_mangle_up) New function. Hackery to make
+ IFF_UP reflect whether any addresses are left on the
+ interface, as we get signalled for IFF_UP flags change on the
+ primary interface only. Logical interfaces dont generate
+ IFINFO, but we do get an RTM_DELADDR.
+ (if_get_flags) Call if_mangle_up before return.
+ * kernel_socket.c: (ifam_read) Fixup calls to
+ connected_{add,delete} to match above changes. Rename gate
+ variable to brd, less confusing.
+ Pass the interface name as a label, if it is not same name
+ as ifp->name.
+
2005-10-11 Paul Jakma <paul.jakma@sun.com>
* connected.{c,h}: (connected_{add,delete}_ipv4) label should
diff --git a/zebra/connected.c b/zebra/connected.c
index 58d964fc..105e4b11 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -29,6 +29,7 @@
#include "rib.h"
#include "table.h"
#include "log.h"
+#include "memory.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
@@ -219,7 +220,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
/* Label of this address. */
if (label)
- ifc->label = strdup (label);
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* Check same connected route. */
if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
@@ -267,8 +268,7 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
/* 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,
- const char *label)
+ u_char prefixlen, struct in_addr *broad)
{
struct prefix_ipv4 p;
struct connected *ifc;
@@ -330,7 +330,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
/* 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;
@@ -356,6 +356,10 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
ifc->destination = (struct prefix *) p;
}
+ /* Label of this address. */
+ if (label)
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
+
if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
connected_withdraw (current); /* implicit update of existing address */
diff --git a/zebra/connected.h b/zebra/connected.h
index 26e809c4..289b03c7 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -33,8 +33,7 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
extern void
connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
- u_char prefixlen, struct in_addr *broad,
- const 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 *);
@@ -42,7 +41,7 @@ extern void connected_down_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
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);
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
index 66d8327d..b00a29cd 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -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 */
}
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c
index efa65060..898c1610 100644
--- a/zebra/if_ioctl_solaris.c
+++ b/zebra/if_ioctl_solaris.c
@@ -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;
@@ -71,7 +71,7 @@ interface_list_ioctl (int af)
calculate_lifc_len: /* must hold privileges to enter here */
lifn.lifn_family = af;
- lifn.lifn_flags = 0;
+ lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
ret = ioctl (sock, SIOCGLIFNUM, &lifn);
save_errno = errno;
@@ -108,7 +108,7 @@ calculate_lifc_len: /* must hold privileges to enter here */
lastneeded = needed;
lifconf.lifc_family = af;
- lifconf.lifc_flags = 0;
+ lifconf.lifc_flags = LIFC_NOXMIT;
lifconf.lifc_len = needed;
lifconf.lifc_buf = buf;
@@ -138,9 +138,22 @@ calculate_lifc_len: /* must hold privileges to enter here */
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;
+
+ 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 +171,15 @@ calculate_lifc_len: /* must hold privileges to enter here */
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++;
}
@@ -209,8 +230,9 @@ if_get_index (struct interface *ifp)
#define SIN(s) ((struct sockaddr_in *)(s))
#define SIN6(s) ((struct sockaddr_in6 *)(s))
+/* Retrieve address information for the given ifp */
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;
@@ -219,8 +241,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr)
u_char prefixlen = 0;
afi_t af;
- /* Interface's name and address family. */
- strncpy (lifreq.lifr_name, ifp->name, IFNAMSIZ);
+ /* Interface's name and address family.
+ * We need to use the logical interface name / label, if we've been
+ * given one, in order to get the right address
+ */
+ strncpy (lifreq.lifr_name, (label : label ? ifp->name), IFNAMSIZ);
/* Interface's address. */
memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
@@ -306,11 +331,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr)
/* 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 +357,7 @@ interface_list ()
{
interface_list_ioctl (AF_INET);
interface_list_ioctl (AF_INET6);
+ interface_list_ioctl (AF_UNSPEC);
}
struct connected *
diff --git a/zebra/if_proc.c b/zebra/if_proc.c
index 3257d03c..6002595a 100644
--- a/zebra/if_proc.c
+++ b/zebra/if_proc.c
@@ -240,7 +240,7 @@ ifaddr_proc_ipv6 ()
str2in6_addr (addr, &p.prefix);
p.prefixlen = plen;
- connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL);
+ connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL, ifname);
}
fclose (fp);
return 0;
diff --git a/zebra/interface.c b/zebra/interface.c
index 49fffcf5..5f9c7a23 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -209,6 +209,16 @@ if_addr_wakeup (struct interface *ifp)
{
if (! if_is_up (ifp))
{
+ /* XXX: WTF is it trying to set flags here?
+ * caller has just gotten a new interface, has been
+ * handed the flags already. This code has no business
+ * trying to override administrative status of the interface.
+ * The only call path to here which doesn't originate from
+ * kernel event is irdp - what on earth is it trying to do?
+ *
+ * further RUNNING is not a settable flag on any system
+ * I (paulj) am aware of.
+ */
if_set_flags (ifp, IFF_UP | IFF_RUNNING);
if_refresh (ifp);
}
@@ -236,6 +246,7 @@ if_addr_wakeup (struct interface *ifp)
{
if (! if_is_up (ifp))
{
+ /* XXX: See long comment above */
if_set_flags (ifp, IFF_UP | IFF_RUNNING);
if_refresh (ifp);
}
@@ -1172,7 +1183,7 @@ ip_address_install (struct vty *vty, struct interface *ifp,
/* Label. */
if (label)
- ifc->label = strdup (label);
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* Add to linked list. */
listnode_add (ifp->connected, ifc);
@@ -1363,7 +1374,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
/* Label. */
if (label)
- ifc->label = strdup (label);
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* Add to linked list. */
listnode_add (ifp->connected, ifc);
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c
index 43e1e83f..ec1d2c44 100644
--- a/zebra/ioctl_solaris.c
+++ b/zebra/ioctl_solaris.c
@@ -274,11 +274,35 @@ 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.
+ */
+static inline void
+if_mangle_up (struct interface *ifp)
+{
+ if (listcount(ifp->connected) > 0)
+ SET_FLAG (ifp->flags, IFF_UP);
+ else
+ UNSET_FLAG (ifp->flags, IFF_UP);
+}
+
/* get interface flags */
void
if_get_flags (struct interface *ifp)
{
- int ret;
+ int ret4, ret6;
struct lifreq lifreq;
unsigned long flags4 = 0, flags6 = 0;
@@ -286,25 +310,27 @@ 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 (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);
}
+
+ /* only update flags if one of above succeeded */
+ if ( !(ret4 && ret6) )
+ ifp->flags = (flags4 | flags6);
- ifp->flags = (flags4 | flags6);
+ if_mangle_up (ifp);
}
/* Set interface flags */
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index f391d53a..c264437d 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -465,7 +465,7 @@ int
ifam_read (struct ifa_msghdr *ifam)
{
struct interface *ifp;
- union sockunion addr, mask, gate;
+ union sockunion addr, mask, brd;
/* Check does this interface exist or not. */
ifp = if_lookup_by_index (ifam->ifam_index);
@@ -476,7 +476,7 @@ ifam_read (struct ifa_msghdr *ifam)
}
/* Allocate and read address information. */
- ifam_read_mesg (ifam, &addr, &mask, &gate);
+ ifam_read_mesg (ifam, &addr, &mask, &brd);
/* Check interface flag for implicit up of the interface. */
if_refresh (ifp);
@@ -488,11 +488,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:
@@ -505,12 +506,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:
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 254c3bd7..6db8496d 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -686,7 +686,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
else
connected_delete_ipv4 (ifp, flags,
(struct in_addr *) addr, ifa->ifa_prefixlen,
- (struct in_addr *) broad, label);
+ (struct in_addr *) broad);
}
#ifdef HAVE_IPV6
if (ifa->ifa_family == AF_INET6)
@@ -694,7 +694,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (h->nlmsg_type == RTM_NEWADDR)
connected_add_ipv6 (ifp,
(struct in6_addr *) addr, ifa->ifa_prefixlen,
- (struct in6_addr *) broad);
+ (struct in6_addr *) broad, label);
else
connected_delete_ipv6 (ifp,
(struct in6_addr *) addr, ifa->ifa_prefixlen,