diff options
author | Patrick Mooney <patrick.f.mooney@gmail.com> | 2014-12-22 19:51:57 +0000 |
---|---|---|
committer | Patrick Mooney <patrick.f.mooney@gmail.com> | 2014-12-29 18:58:04 +0000 |
commit | 962713cac7fe14b223b21a942d294169c8cc26b9 (patch) | |
tree | e1a361e2ec52920b7f9387b0f799deeaffe1dc0a | |
parent | 395420a06c8cf090ff6af62325e8da10f2f841f2 (diff) | |
download | illumos-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.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/procfs/lx_prvnops.c | 65 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/syscall/lx_ioctl.c | 163 | ||||
-rw-r--r-- | usr/src/uts/intel/lx_proc/Makefile | 2 |
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 |