diff options
Diffstat (limited to 'zebra/if_ioctl_solaris.c')
| -rw-r--r-- | zebra/if_ioctl_solaris.c | 562 | 
1 files changed, 274 insertions, 288 deletions
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 08af2aa350..fce36ebc1d 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -37,338 +37,324 @@  #include "zebra/ioctl_solaris.h"  #include "zebra/rib.h" -static int if_get_addr (struct interface *, struct sockaddr *, const char *); -static void interface_info_ioctl (struct interface *); +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; -static int -interface_list_ioctl (int af) +static int interface_list_ioctl(int af)  { -  int ret; -  int sock; +	int ret; +	int sock;  #define IFNUM_BASE 32 -  struct lifnum lifn; -  int ifnum; -  struct lifreq *lifreq; -  struct lifconf lifconf; -  struct interface *ifp; -  int n; -  int save_errno; -  size_t needed, lastneeded = 0; -  char *buf = NULL; - -  if (zserv_privs.change(ZPRIVS_RAISE)) -    zlog_err("Can't raise privileges"); -   -  sock = socket (af, SOCK_DGRAM, 0); -  if (sock < 0) -    { -      zlog_warn ("Can't make %s socket stream: %s", -                 (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno)); -                  -      if (zserv_privs.change(ZPRIVS_LOWER)) -        zlog_err("Can't lower privileges"); -         -      return -1; -    } - -calculate_lifc_len:     /* must hold privileges to enter here */ -  lifn.lifn_family = af; -  lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */ -  ret = ioctl (sock, SIOCGLIFNUM, &lifn); -  save_errno = errno; -   -  if (zserv_privs.change(ZPRIVS_LOWER)) -    zlog_err("Can't lower privileges"); -  -  if (ret < 0) -    { -      zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s", -                 safe_strerror (save_errno)); -      close (sock); -      return -1; -    } -  ifnum = lifn.lifn_count; - -  /* -   * When calculating the buffer size needed, add a small number -   * of interfaces to those we counted.  We do this to capture -   * the interface status of potential interfaces which may have -   * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. -   */ -  needed = (ifnum + 4) * sizeof (struct lifreq); -  if (needed > lastneeded || needed < lastneeded / 2) -    { -      if (buf != NULL) -        XFREE (MTYPE_TMP, buf); -      if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL) -        { -          zlog_warn ("interface_list_ioctl: malloc failed"); -          close (sock); -          return -1; -        } -    } -  lastneeded = needed; - -  lifconf.lifc_family = af; -  lifconf.lifc_flags = LIFC_NOXMIT; -  lifconf.lifc_len = needed; -  lifconf.lifc_buf = buf; - -  if (zserv_privs.change(ZPRIVS_RAISE)) -    zlog_err("Can't raise privileges"); -     -  ret = ioctl (sock, SIOCGLIFCONF, &lifconf); - -  if (ret < 0) -    { -      if (errno == EINVAL) -        goto calculate_lifc_len; /* deliberately hold privileges */ - -      zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno)); - -      if (zserv_privs.change(ZPRIVS_LOWER)) -        zlog_err("Can't lower privileges"); - -      goto end; -    } - -  if (zserv_privs.change(ZPRIVS_LOWER)) -    zlog_err("Can't lower privileges"); -     -  /* Allocate interface. */ -  lifreq = lifconf.lifc_req; - -  for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq)) -    { -      /* 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; -      uint64_t lifflags; -       -      /* We should exclude ~IFF_UP interfaces, as we'll find out about them -       * coming up later through RTM_NEWADDR message on the route socket. -       */ -      if (if_get_flags_direct (lifreq->lifr_name, &lifflags, -                           lifreq->lifr_addr.ss_family) -          || !CHECK_FLAG (lifflags, IFF_UP)) -        { -          lifreq++; -          continue; -        } -       -      /* Find the normalised 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, VRF_DEFAULT, 0); - -      if (lifreq->lifr_addr.ss_family == AF_INET) -        ifp->flags |= IFF_IPV4; - -      if (lifreq->lifr_addr.ss_family == AF_INET6) -        { -          ifp->flags |= IFF_IPV6; -        } -         -      if_add_update (ifp); - -      interface_info_ioctl (ifp); -       -      /* 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); -         -      /* Poke the interface flags. Lets IFF_UP mangling kick in */ -      if_flags_update (ifp, ifp->flags); -       -      lifreq++; -    } +	struct lifnum lifn; +	int ifnum; +	struct lifreq *lifreq; +	struct lifconf lifconf; +	struct interface *ifp; +	int n; +	int save_errno; +	size_t needed, lastneeded = 0; +	char *buf = NULL; + +	if (zserv_privs.change(ZPRIVS_RAISE)) +		zlog_err("Can't raise privileges"); + +	sock = socket(af, SOCK_DGRAM, 0); +	if (sock < 0) { +		zlog_warn("Can't make %s socket stream: %s", +			  (af == AF_INET ? "AF_INET" : "AF_INET6"), +			  safe_strerror(errno)); + +		if (zserv_privs.change(ZPRIVS_LOWER)) +			zlog_err("Can't lower privileges"); + +		return -1; +	} + +calculate_lifc_len: /* must hold privileges to enter here */ +	lifn.lifn_family = af; +	lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */ +	ret = ioctl(sock, SIOCGLIFNUM, &lifn); +	save_errno = errno; + +	if (zserv_privs.change(ZPRIVS_LOWER)) +		zlog_err("Can't lower privileges"); + +	if (ret < 0) { +		zlog_warn("interface_list_ioctl: SIOCGLIFNUM failed %s", +			  safe_strerror(save_errno)); +		close(sock); +		return -1; +	} +	ifnum = lifn.lifn_count; + +	/* +	 * When calculating the buffer size needed, add a small number +	 * of interfaces to those we counted.  We do this to capture +	 * the interface status of potential interfaces which may have +	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. +	 */ +	needed = (ifnum + 4) * sizeof(struct lifreq); +	if (needed > lastneeded || needed < lastneeded / 2) { +		if (buf != NULL) +			XFREE(MTYPE_TMP, buf); +		if ((buf = XMALLOC(MTYPE_TMP, needed)) == NULL) { +			zlog_warn("interface_list_ioctl: malloc failed"); +			close(sock); +			return -1; +		} +	} +	lastneeded = needed; + +	lifconf.lifc_family = af; +	lifconf.lifc_flags = LIFC_NOXMIT; +	lifconf.lifc_len = needed; +	lifconf.lifc_buf = buf; + +	if (zserv_privs.change(ZPRIVS_RAISE)) +		zlog_err("Can't raise privileges"); + +	ret = ioctl(sock, SIOCGLIFCONF, &lifconf); + +	if (ret < 0) { +		if (errno == EINVAL) +			goto calculate_lifc_len; /* deliberately hold privileges +						    */ + +		zlog_warn("SIOCGLIFCONF: %s", safe_strerror(errno)); + +		if (zserv_privs.change(ZPRIVS_LOWER)) +			zlog_err("Can't lower privileges"); + +		goto end; +	} + +	if (zserv_privs.change(ZPRIVS_LOWER)) +		zlog_err("Can't lower privileges"); + +	/* Allocate interface. */ +	lifreq = lifconf.lifc_req; + +	for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) { +		/* 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; +		uint64_t lifflags; + +		/* We should exclude ~IFF_UP interfaces, as we'll find out about +		 * them +		 * coming up later through RTM_NEWADDR message on the route +		 * socket. +		 */ +		if (if_get_flags_direct(lifreq->lifr_name, &lifflags, +					lifreq->lifr_addr.ss_family) +		    || !CHECK_FLAG(lifflags, IFF_UP)) { +			lifreq++; +			continue; +		} + +		/* Find the normalised 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, +					 VRF_DEFAULT, 0); + +		if (lifreq->lifr_addr.ss_family == AF_INET) +			ifp->flags |= IFF_IPV4; + +		if (lifreq->lifr_addr.ss_family == AF_INET6) { +			ifp->flags |= IFF_IPV6; +		} + +		if_add_update(ifp); + +		interface_info_ioctl(ifp); + +		/* 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); + +		/* Poke the interface flags. Lets IFF_UP mangling kick in */ +		if_flags_update(ifp, ifp->flags); + +		lifreq++; +	}  end: -  close (sock); -  XFREE (MTYPE_TMP, lifconf.lifc_buf); -  return ret; +	close(sock); +	XFREE(MTYPE_TMP, lifconf.lifc_buf); +	return ret;  }  /* Get interface's index by ioctl. */ -static int -if_get_index (struct interface *ifp) +static int if_get_index(struct interface *ifp)  { -  int ret; -  struct lifreq lifreq; +	int ret; +	struct lifreq lifreq; -  lifreq_set_name (&lifreq, ifp->name); +	lifreq_set_name(&lifreq, ifp->name); -  if (ifp->flags & IFF_IPV4) -    ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq); -  else if (ifp->flags & IFF_IPV6) -    ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq); -  else -    ret = -1; +	if (ifp->flags & IFF_IPV4) +		ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq); +	else if (ifp->flags & IFF_IPV6) +		ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq); +	else +		ret = -1; -  if (ret < 0) -    { -      zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name); -      return ret; -    } +	if (ret < 0) { +		zlog_warn("SIOCGLIFINDEX(%s) failed", ifp->name); +		return ret; +	} -  /* OK we got interface index. */ +/* OK we got interface index. */  #ifdef ifr_ifindex -  ifp->ifindex = lifreq.lifr_ifindex; +	ifp->ifindex = lifreq.lifr_ifindex;  #else -  ifp->ifindex = lifreq.lifr_index; +	ifp->ifindex = lifreq.lifr_index;  #endif -  return ifp->ifindex; - +	return ifp->ifindex;  }  /* Interface address lookup by ioctl.  This function only looks up     IPv4 address. */ -#define ADDRLEN(sa) (((sa)->sa_family == AF_INET ?  \ -                sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6))) +#define ADDRLEN(sa)                                                            \ +	(((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in)              \ +				     : sizeof(struct sockaddr_in6)))  #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, const char *label) +static int if_get_addr(struct interface *ifp, struct sockaddr *addr, +		       const char *label)  { -  int ret; -  struct lifreq lifreq; -  struct sockaddr_storage mask, dest; -  char *dest_pnt = NULL; -  u_char prefixlen = 0; -  afi_t af; -  int flags = 0; - -  /* 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)); -  af = addr->sa_family; - -  /* Point to point or broad cast address pointer init. */ -  dest_pnt = NULL; - -  if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) -    { -      memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); -      if (af == AF_INET) -        dest_pnt = (char *) &(SIN (&dest)->sin_addr); -      else -        dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); -      flags = ZEBRA_IFA_PEER; -    } - -  if (af == AF_INET) -    { -      ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); -       -      if (ret < 0) -        { -          if (errno != EADDRNOTAVAIL) -            { -              zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, -                         safe_strerror (errno)); -              return ret; -            } -          return 0; -        } -      memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); - -      prefixlen = ip_masklen (SIN (&mask)->sin_addr); -      if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) -	{ -          memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); -          dest_pnt = (char *) &SIN (&dest)->sin_addr; -        } -    } -  else if (af == AF_INET6) -    { -      if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) -	{ -	  if (ifp->flags & IFF_POINTOPOINT) -	    prefixlen = IPV6_MAX_BITLEN; -	  else -	    zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", -		       ifp->name, safe_strerror (errno)); +	int ret; +	struct lifreq lifreq; +	struct sockaddr_storage mask, dest; +	char *dest_pnt = NULL; +	u_char prefixlen = 0; +	afi_t af; +	int flags = 0; + +	/* 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)); +	af = addr->sa_family; + +	/* Point to point or broad cast address pointer init. */ +	dest_pnt = NULL; + +	if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) { +		memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr)); +		if (af == AF_INET) +			dest_pnt = (char *)&(SIN(&dest)->sin_addr); +		else +			dest_pnt = (char *)&(SIN6(&dest)->sin6_addr); +		flags = ZEBRA_IFA_PEER;  	} -      else -	{ -	  prefixlen = lifreq.lifr_addrlen; + +	if (af == AF_INET) { +		ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq); + +		if (ret < 0) { +			if (errno != EADDRNOTAVAIL) { +				zlog_warn("SIOCGLIFNETMASK (%s) fail: %s", +					  ifp->name, safe_strerror(errno)); +				return ret; +			} +			return 0; +		} +		memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr)); + +		prefixlen = ip_masklen(SIN(&mask)->sin_addr); +		if (!dest_pnt +		    && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) { +			memcpy(&dest, &lifreq.lifr_broadaddr, +			       sizeof(struct sockaddr_in)); +			dest_pnt = (char *)&SIN(&dest)->sin_addr; +		} +	} else if (af == AF_INET6) { +		if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) { +			if (ifp->flags & IFF_POINTOPOINT) +				prefixlen = IPV6_MAX_BITLEN; +			else +				zlog_warn("SIOCGLIFSUBNET (%s) fail: %s", +					  ifp->name, safe_strerror(errno)); +		} else { +			prefixlen = lifreq.lifr_addrlen; +		}  	} -    } -  /* Set address to the interface. */ -  if (af == AF_INET) -    connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, -                        (struct in_addr *) dest_pnt, label); -  else if (af == AF_INET6) -    connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, -                        (struct in6_addr *) dest_pnt, label); +	/* Set address to the interface. */ +	if (af == AF_INET) +		connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen, +				   (struct in_addr *)dest_pnt, label); +	else if (af == AF_INET6) +		connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, +				   prefixlen, (struct in6_addr *)dest_pnt, +				   label); -  return 0; +	return 0;  }  /* Fetch interface information via ioctl(). */ -static void -interface_info_ioctl (struct interface *ifp) +static void interface_info_ioctl(struct interface *ifp)  { -  if_get_index (ifp); -  if_get_flags (ifp); -  if_get_mtu (ifp); -  if_get_metric (ifp); +	if_get_index(ifp); +	if_get_flags(ifp); +	if_get_mtu(ifp); +	if_get_metric(ifp);  }  /* Lookup all interface information. */ -void -interface_list (struct zebra_ns *zns) +void interface_list(struct zebra_ns *zns)  { -  if (zns->ns_id != NS_DEFAULT) -    { -      zlog_warn ("interface_list: ignore NS %u", zns->ns_id); -      return; -    } -  interface_list_ioctl (AF_INET); -  interface_list_ioctl (AF_INET6); -  interface_list_ioctl (AF_UNSPEC); +	if (zns->ns_id != NS_DEFAULT) { +		zlog_warn("interface_list: ignore NS %u", zns->ns_id); +		return; +	} +	interface_list_ioctl(AF_INET); +	interface_list_ioctl(AF_INET6); +	interface_list_ioctl(AF_UNSPEC);  } -struct connected * -if_lookup_linklocal (struct interface *ifp) +struct connected *if_lookup_linklocal(struct interface *ifp)  { -  struct listnode *node; -  struct connected *ifc; +	struct listnode *node; +	struct connected *ifc; -  if (ifp == NULL) -    return NULL; +	if (ifp == NULL) +		return NULL; -  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) -    { -      if ((ifc->address->family == AF_INET6) && -          (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6))) -        return ifc; -    } +	for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { +		if ((ifc->address->family == AF_INET6) +		    && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6))) +			return ifc; +	} -  return NULL; +	return NULL;  }  | 
