summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2014-12-22 19:51:57 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2014-12-29 18:58:04 +0000
commit962713cac7fe14b223b21a942d294169c8cc26b9 (patch)
treee1a361e2ec52920b7f9387b0f799deeaffe1dc0a
parent395420a06c8cf090ff6af62325e8da10f2f841f2 (diff)
downloadillumos-joyent-962713cac7fe14b223b21a942d294169c8cc26b9.tar.gz
OS-3662 lxbrand emulate /proc/net/if_inet6
OS-3667 lxbrand support RO ifconfig Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_proc.h1
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c65
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_ioctl.c163
-rw-r--r--usr/src/uts/intel/lx_proc/Makefile2
4 files changed, 160 insertions, 71 deletions
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_proc.h b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
index 96dd0c13ba..1b4ee707c1 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_proc.h
+++ b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
@@ -134,6 +134,7 @@ typedef enum lxpr_nodetype {
LXPR_NET_ARP, /* /proc/net/arp */
LXPR_NET_DEV, /* /proc/net/dev */
LXPR_NET_DEV_MCAST, /* /proc/net/dev_mcast */
+ LXPR_NET_IF_INET6, /* /proc/net/if_inet6 */
LXPR_NET_IGMP, /* /proc/net/igmp */
LXPR_NET_IP_MR_CACHE, /* /proc/net/ip_mr_cache */
LXPR_NET_IP_MR_VIF, /* /proc/net/ip_mr_vif */
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index feb4a10714..0c9ab07c5b 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -70,6 +70,10 @@
#include <sys/rctl.h>
#include <sys/kstat.h>
#include <sys/lx_misc.h>
+#include <inet/ip.h>
+#include <inet/ip_ire.h>
+#include <inet/ip6.h>
+#include <inet/ip_if.h>
/* Dependent on procfs */
extern kthread_t *prchoose(proc_t *);
@@ -149,6 +153,7 @@ static void lxpr_read_pid_status(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_arp(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_dev(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_dev_mcast(lxpr_node_t *, lxpr_uiobuf_t *);
+static void lxpr_read_net_if_inet6(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_igmp(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_ip_mr_cache(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_net_ip_mr_vif(lxpr_node_t *, lxpr_uiobuf_t *);
@@ -297,6 +302,7 @@ static lxpr_dirent_t netdir[] = {
{ LXPR_NET_ARP, "arp" },
{ LXPR_NET_DEV, "dev" },
{ LXPR_NET_DEV_MCAST, "dev_mcast" },
+ { LXPR_NET_IF_INET6, "if_inet6" },
{ LXPR_NET_IGMP, "igmp" },
{ LXPR_NET_IP_MR_CACHE, "ip_mr_cache" },
{ LXPR_NET_IP_MR_VIF, "ip_mr_vif" },
@@ -476,6 +482,7 @@ static void (*lxpr_read_function[LXPR_NFILES])() = {
lxpr_read_net_arp, /* /proc/net/arp */
lxpr_read_net_dev, /* /proc/net/dev */
lxpr_read_net_dev_mcast, /* /proc/net/dev_mcast */
+ lxpr_read_net_if_inet6, /* /proc/net/if_inet6 */
lxpr_read_net_igmp, /* /proc/net/igmp */
lxpr_read_net_ip_mr_cache, /* /proc/net/ip_mr_cache */
lxpr_read_net_ip_mr_vif, /* /proc/net/ip_mr_vif */
@@ -550,6 +557,7 @@ static vnode_t *(*lxpr_lookup_function[LXPR_NFILES])() = {
lxpr_lookup_not_a_dir, /* /proc/net/arp */
lxpr_lookup_not_a_dir, /* /proc/net/dev */
lxpr_lookup_not_a_dir, /* /proc/net/dev_mcast */
+ lxpr_lookup_not_a_dir, /* /proc/net/if_inet6 */
lxpr_lookup_not_a_dir, /* /proc/net/igmp */
lxpr_lookup_not_a_dir, /* /proc/net/ip_mr_cache */
lxpr_lookup_not_a_dir, /* /proc/net/ip_mr_vif */
@@ -624,6 +632,7 @@ static int (*lxpr_readdir_function[LXPR_NFILES])() = {
lxpr_readdir_not_a_dir, /* /proc/net/arp */
lxpr_readdir_not_a_dir, /* /proc/net/dev */
lxpr_readdir_not_a_dir, /* /proc/net/dev_mcast */
+ lxpr_readdir_not_a_dir, /* /proc/net/if_inet6 */
lxpr_readdir_not_a_dir, /* /proc/net/igmp */
lxpr_readdir_not_a_dir, /* /proc/net/ip_mr_cache */
lxpr_readdir_not_a_dir, /* /proc/net/ip_mr_vif */
@@ -1725,6 +1734,62 @@ lxpr_read_net_dev_mcast(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
{
}
+static void
+lxpr_inet6_out(in6_addr_t addr, char buf[33])
+{
+ uint8_t *ip = addr.s6_addr;
+ char digits[] = "0123456789abcdef";
+ int i;
+ for (i = 0; i < 16; i++) {
+ buf[2 * i] = digits[ip[i] >> 4];
+ buf[2 * i + 1] = digits[ip[i] & 0xf];
+ }
+ buf[32] = '\0';
+}
+
+/* ARGSUSED */
+static void
+lxpr_read_net_if_inet6(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ netstack_t *ns;
+ ip_stack_t *ipst;
+ ill_t *ill;
+ ipif_t *ipif;
+ ill_walk_context_t ctx;
+ char ifname[LIFNAMSIZ], ip6out[33];
+
+ ns = netstack_get_current();
+ if (ns == NULL)
+ return;
+ ipst = ns->netstack_ip;
+
+ rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+ ill = ILL_START_WALK_V6(&ctx, ipst);
+
+ for (; ill != NULL; ill = ill_next(&ctx, ill)) {
+ for (ipif = ill->ill_ipif; ipif != NULL;
+ ipif = ipif->ipif_next) {
+ uint_t index = ill->ill_phyint->phyint_ifindex;
+ int plen = ip_mask_to_plen_v6(&ipif->ipif_v6net_mask);
+ in6addr_scope_t scope = ip_addr_scope_v6(
+ &ipif->ipif_v6lcl_addr);
+ /* Always report PERMANENT flag */
+ int flag = 0x80;
+
+ ipif_get_name(ipif, ifname, sizeof (ifname));
+ lx_ifname_convert(ifname, LX_IFNAME_FROMNATIVE);
+ lxpr_inet6_out(ipif->ipif_v6lcl_addr, ip6out);
+ /* Scope output is shifted on Linux */
+ scope = scope << 4;
+
+ lxpr_uiobuf_printf(uiobuf, "%32s %02x %02x %02x %02x"
+ " %8s\n", ip6out, index, plen, scope, flag, ifname);
+ }
+ }
+ rw_exit(&ipst->ips_ill_g_lock);
+ netstack_rele(ns);
+}
+
/* ARGSUSED */
static void
lxpr_read_net_igmp(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
diff --git a/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c b/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c
index 09a528604f..14d8d47d67 100644
--- a/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c
+++ b/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c
@@ -39,6 +39,7 @@
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if_arp.h>
+#include <sys/ioccom.h>
/*
* Supported ioctls
@@ -785,69 +786,45 @@ ict_siocatmark(file_t *fp, int cmd, intptr_t arg, int lxcmd)
return (0);
}
-static int
-ict_siocifhwaddr(file_t *fp, int cmd, struct ifreq *req)
+static void
+ict_convert_ifflags(uint64_t *flags, boolean_t tonative)
{
- struct arpreq arpreq;
- int error, rv;
-
- /*
- * We're not going to support SIOCSIFHWADDR, but we need to be able to
- * check the result of the copyin first to see if the command should
- * have returned EFAULT.
- */
- if (cmd == LX_SIOCSIFHWADDR)
- return (set_errno(EINVAL));
-
- if (strcmp(req->ifr_name, "lo0") == 0) {
- /* Abuse ifr_addr for linux ifr_hwaddr */
- bzero(&req->ifr_addr, sizeof (struct sockaddr));
- req->ifr_addr.sa_family = LX_ARPHRD_LOOPBACK;
- return (0);
+ uint64_t buf;
+ buf = *flags & (IFF_UP | IFF_BROADCAST | IFF_DEBUG |
+ IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOTRAILERS |
+ IFF_RUNNING | IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
+
+ /* Linux has different shift for multicast flag */
+ if (tonative == B_TRUE) {
+ if (*flags & 0x1000)
+ buf |= IFF_MULTICAST;
+ } else {
+ if (*flags & IFF_MULTICAST)
+ buf |= 0x1000;
}
-
- error = VOP_IOCTL(fp->f_vnode, SIOCGIFADDR, (intptr_t)req,
- FLFAKE(fp), fp->f_cred, &rv, NULL);
- /* set_errno will be performed by ict_sioifreq */
- if (error != 0)
- return (error);
-
- bzero(&arpreq, sizeof (arpreq));
- bcopy(&req->ifr_addr, &arpreq.arp_pa, sizeof (struct sockaddr));
-
- error = VOP_IOCTL(fp->f_vnode, SIOCGARP, (intptr_t)&arpreq,
- FLFAKE(fp), fp->f_cred, &rv, NULL);
- if (error != 0)
- return (error);
-
- /* Abuse ifr_addr for linux ifr_hwaddr */
- bcopy(&arpreq.arp_ha, &req->ifr_addr, sizeof (struct sockaddr));
- /* consider all non-loopback as ethernet for now */
- req->ifr_addr.sa_family = LX_ARPHRD_ETHER;
-
- return (0);
+ *flags = buf;
}
static int
-ict_sioifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd)
+ict_siolifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd)
{
struct ifreq req;
- int error, rv, len;
+ struct lifreq lreq;
+ int error, rv, len;
- /* The Linux ifreq is smaller than illumos */
+ /* Convert from Linux ifreq to illumos lifreq */
if (curproc->p_model == DATAMODEL_LP64)
len = sizeof (lx_ifreq64_t);
else
len = sizeof (lx_ifreq32_t);
- bzero(&req, sizeof (req));
-
if (copyin((struct ifreq *)arg, &req, len) != 0)
return (set_errno(EFAULT));
- lx_ifname_convert(req.ifr_name, LX_IFNAME_TONATIVE);
+ bzero(&lreq, sizeof (lreq));
+ strncpy(lreq.lifr_name, req.ifr_name, IFNAMSIZ);
+ bcopy(&req.ifr_ifru, &lreq.lifr_lifru, len - IFNAMSIZ);
+ lx_ifname_convert(lreq.lifr_name, LX_IFNAME_TONATIVE);
switch (cmd) {
- case SIOCGIFFLAGS:
- case SIOCSIFFLAGS:
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
@@ -861,13 +838,54 @@ ict_sioifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd)
case SIOCGIFMTU:
case SIOCSIFMTU:
case SIOCGIFINDEX:
- error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&req,
+ /*
+ * Convert cmd from SIO*IF* to SIO*LIF*.
+ * This is needed since Linux allows ifreq operations on ipv6
+ * sockets where illumos does not.
+ */
+ cmd = ((cmd & IOC_INOUT) |
+ _IOW('i', ((cmd & 0xff) + 100), struct lifreq));
+ error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq,
FLFAKE(fp), fp->f_cred, &rv, NULL);
break;
- case LX_SIOCGIFHWADDR:
- case LX_SIOCSIFHWADDR:
- error = ict_siocifhwaddr(fp, cmd, &req);
+ case SIOCGIFFLAGS:
+ cmd = SIOCGLIFFLAGS;
+ error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq,
+ FLFAKE(fp), fp->f_cred, &rv, NULL);
+ if (error == 0)
+ ict_convert_ifflags(&lreq.lifr_flags, B_FALSE);
break;
+ case SIOCSIFFLAGS:
+ cmd = SIOCSLIFFLAGS;
+ ict_convert_ifflags(&lreq.lifr_flags, B_TRUE);
+ error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq,
+ FLFAKE(fp), fp->f_cred, &rv, NULL);
+ break;
+ case SIOCGIFHWADDR:
+ cmd = SIOCGLIFHWADDR;
+ error = VOP_IOCTL(fp->f_vnode, cmd, (intptr_t)&lreq,
+ FLFAKE(fp), fp->f_cred, &rv, NULL);
+ /*
+ * SIOCGIFHWADDR on Linux sets sa_family to ARPHRD_ETHER (1) on
+ * ethernet and ARPHRD_LOOPBACK (772) on loopback.
+ */
+ if (error == EADDRNOTAVAIL &&
+ strncmp(lreq.lifr_name, "lo", 2) == 0) {
+ /* Emulate success on suspected loopbacks */
+ lreq.lifr_addr.ss_family = 772;
+ error = 0;
+ } else if (error == 0) {
+ /* Default to Ethernet for all successes */
+ lreq.lifr_addr.ss_family = 1;
+ }
+ break;
+
+ case LX_SIOCSIFHWADDR:
+ /*
+ * We're not going to support SIOCSIFHWADDR, but we need to be
+ * able to check the result of the copyin first to see if the
+ * command should have returned EFAULT.
+ */
default:
error = EINVAL;
}
@@ -875,8 +893,13 @@ ict_sioifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd)
if (error != 0)
return (set_errno(error));
- lx_ifname_convert(req.ifr_name, LX_IFNAME_FROMNATIVE);
- if (copyout(&req, (struct ifreq *)arg, len) != 0)
+ /* Convert back to a Linux ifreq */
+ lx_ifname_convert(lreq.lifr_name, LX_IFNAME_FROMNATIVE);
+ bzero(&req, sizeof (req));
+ strncpy(req.ifr_name, lreq.lifr_name, IFNAMSIZ);
+ bcopy(&lreq.lifr_lifru, &req.ifr_ifru, len - IFNAMSIZ);
+
+ if (copyout(&req, (struct lifreq *)arg, len) != 0)
return (set_errno(EFAULT));
return (0);
@@ -1069,23 +1092,23 @@ static ioc_cmd_translator_t ioc_translators[] = {
IOC_CMD_TRANSLATOR_PASS(SIOCSPGRP)
IOC_CMD_TRANSLATOR_PASS(SIOCGPGRP)
IOC_CMD_TRANSLATOR_FILTER(SIOCATMARK, ict_siocatmark)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFFLAGS, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFFLAGS, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFDSTADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFDSTADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFBRDADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFBRDADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFNETMASK, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFNETMASK, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMETRIC, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMETRIC, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMTU, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMTU, ict_sioifreq)
- IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFHWADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCSIFHWADDR, ict_sioifreq)
- IOC_CMD_TRANSLATOR_FILTER(SIOCGIFINDEX, ict_sioifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFFLAGS, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFFLAGS, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFDSTADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFDSTADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFBRDADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFBRDADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFNETMASK, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFNETMASK, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMETRIC, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMETRIC, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMTU, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMTU, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFHWADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCSIFHWADDR, ict_siolifreq)
+ IOC_CMD_TRANSLATOR_FILTER(SIOCGIFINDEX, ict_siolifreq)
IOC_CMD_TRANSLATOR_FILTER(SIOCGIFCONF, ict_siocgifconf)
IOC_CMD_TRANSLATOR_END
diff --git a/usr/src/uts/intel/lx_proc/Makefile b/usr/src/uts/intel/lx_proc/Makefile
index 04873fcd72..0d3d5511bf 100644
--- a/usr/src/uts/intel/lx_proc/Makefile
+++ b/usr/src/uts/intel/lx_proc/Makefile
@@ -72,7 +72,7 @@ CFLAGS += $(CCVERBOSE)
#
# Depends on procfs and lx_brand
#
-LDFLAGS += -dy -Nfs/procfs -Nbrand/lx_brand -Ndrv/inotify
+LDFLAGS += -dy -Nfs/procfs -Nbrand/lx_brand -Ndrv/inotify -Ndrv/ip
#
# For now, disable these lint checks; maintainers should endeavor