diff options
Diffstat (limited to 'zebra/ioctl_solaris.c')
-rw-r--r-- | zebra/ioctl_solaris.c | 91 |
1 files changed, 49 insertions, 42 deletions
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index ec1d2c44..2f05bf12 100644 --- a/zebra/ioctl_solaris.c +++ b/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; |