+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
#include "rib.h"
#include "table.h"
#include "log.h"
+#include "memory.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
/* 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)))
/* 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;
/* 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;
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 */
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 *);
#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);
}
#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 */
}
#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;
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;
lastneeded = needed;
lifconf.lifc_family = af;
- lifconf.lifc_flags = 0;
+ lifconf.lifc_flags = LIFC_NOXMIT;
lifconf.lifc_len = needed;
lifconf.lifc_buf = buf;
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;
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++;
}
#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;
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));
/* 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;
{
interface_list_ioctl (AF_INET);
interface_list_ioctl (AF_INET6);
+ interface_list_ioctl (AF_UNSPEC);
}
struct connected *
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;
{
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);
}
{
if (! if_is_up (ifp))
{
+ /* XXX: See long comment above */
if_set_flags (ifp, IFF_UP | IFF_RUNNING);
if_refresh (ifp);
}
/* Label. */
if (label)
- ifc->label = strdup (label);
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* Add to linked list. */
listnode_add (ifp->connected, ifc);
/* Label. */
if (label)
- ifc->label = strdup (label);
+ ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* Add to linked list. */
listnode_add (ifp->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;
{
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 */
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);
}
/* 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);
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:
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:
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)
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,