summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2015-05-29 14:58:44 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2015-06-05 20:02:22 +0000
commitb730089b8afae637d9a4bda3ef929625e41e0329 (patch)
tree5bbb79a31b0beeb0539a2bc106ce600a9437f653
parentf678cef01a1f7e4c11d44044991bee1a3b3c0823 (diff)
downloadillumos-joyent-b730089b8afae637d9a4bda3ef929625e41e0329.tar.gz
OS-4338 lxbrand expose route info via netlink
OS-3866 lxbrand ip route show fails OS-4275 lxbrand ansible unable to query network facts Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/socket.c5
-rw-r--r--usr/src/uts/common/brand/lx/io/lx_netlink.c346
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c29
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_brand.h1
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_ioctl.c59
-rw-r--r--usr/src/uts/intel/lx_brand/Makefile3
6 files changed, 412 insertions, 31 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/socket.c b/usr/src/lib/brand/lx/lx_brand/common/socket.c
index d5e5d90199..3b0220549d 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/socket.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/socket.c
@@ -862,8 +862,9 @@ calc_addr_size(struct sockaddr *a, int nlen, lx_addr_type_t *type)
struct sockaddr name;
sa_family_t family;
size_t fsize = sizeof (name.sa_family);
+ int copylen = MIN(nlen, sizeof (struct sockaddr));
- if (uucopy(a, &name, sizeof (struct sockaddr)) != 0)
+ if (uucopy(a, &name, copylen) != 0)
return (-errno);
family = LTOS_FAMILY(name.sa_family);
@@ -2274,8 +2275,6 @@ lx_sendmsg(int sockfd, void *lmp, int flags)
* Perform conversion on msg_name, if present.
*/
if (msg.msg_name != NULL) {
- if (msg.msg_namelen < sizeof (struct sockaddr))
- return (-EINVAL);
size = calc_addr_size(msg.msg_name, msg.msg_namelen, &type);
if (size < 0)
return (size);
diff --git a/usr/src/uts/common/brand/lx/io/lx_netlink.c b/usr/src/uts/common/brand/lx/io/lx_netlink.c
index 35ee5b97ed..2e80e1bf11 100644
--- a/usr/src/uts/common/brand/lx/io/lx_netlink.c
+++ b/usr/src/uts/common/brand/lx/io/lx_netlink.c
@@ -30,7 +30,10 @@
#include <sys/sockio.h>
#include <sys/brand.h>
#include <inet/ip.h>
+#include <inet/ip6.h>
#include <inet/ip_impl.h>
+#include <inet/ip_ire.h>
+#include <sys/lx_brand.h>
#include <sys/lx_misc.h>
#include <sys/ethernet.h>
#include <sys/dlpi.h>
@@ -140,24 +143,25 @@
/*
* rtnetlink(7) attribute constants
*/
-#define LX_NETLINK_RTA_UNSPEC 1
-#define LX_NETLINK_RTA_DST 2
-#define LX_NETLINK_RTA_SRC 3
-#define LX_NETLINK_RTA_IIF 4
-#define LX_NETLINK_RTA_OIF 5
-#define LX_NETLINK_RTA_GATEWAY 6
-#define LX_NETLINK_RTA_PRIORITY 7
-#define LX_NETLINK_RTA_PREFSRC 8
-#define LX_NETLINK_RTA_METRICS 9
-#define LX_NETLINK_RTA_MULTIPATH 10
-#define LX_NETLINK_RTA_PROTOINFO 11
-#define LX_NETLINK_RTA_FLOW 12
-#define LX_NETLINK_RTA_CACHEINFO 13
-#define LX_NETLINK_RTA_SESSION 14
-#define LX_NETLINK_RTA_MP_ALGO 15
-#define LX_NETLINK_RTA_TABLE 16
-#define LX_NETLINK_RTA_MARK 17
-#define LX_NETLINK_RTA_MFC_STATS 18
+#define LX_NETLINK_RTA_UNSPEC 0
+#define LX_NETLINK_RTA_DST 1
+#define LX_NETLINK_RTA_SRC 2
+#define LX_NETLINK_RTA_IIF 3
+#define LX_NETLINK_RTA_OIF 4
+#define LX_NETLINK_RTA_GATEWAY 5
+#define LX_NETLINK_RTA_PRIORITY 6
+#define LX_NETLINK_RTA_PREFSRC 7
+#define LX_NETLINK_RTA_METRICS 8
+#define LX_NETLINK_RTA_MULTIPATH 9
+#define LX_NETLINK_RTA_PROTOINFO 10
+#define LX_NETLINK_RTA_FLOW 11
+#define LX_NETLINK_RTA_CACHEINFO 12
+#define LX_NETLINK_RTA_SESSION 13
+#define LX_NETLINK_RTA_MP_ALGO 14
+#define LX_NETLINK_RTA_TABLE 15
+#define LX_NETLINK_RTA_MARK 16
+#define LX_NETLINK_RTA_MFC_STATS 17
+#define LX_NETLINK_MAX_RTA LX_NETLINK_RTA_MFC_STATS
/*
* rtnetlink(7) NEWLINK/DELLINK/GETLINK constants
@@ -256,6 +260,38 @@
#define LX_IFF_DORMANT (1<<17)
#define LX_IFF_ECHO (1<<18)
+/* rtm_table */
+#define LX_ROUTE_TABLE_MAIN 254
+
+/* rtm_type */
+#define LX_RTN_UNSPEC 0
+#define LX_RTN_UNICAST 1
+#define LX_RTN_LOCAL 2
+#define LX_RTN_BROADCAST 3
+#define LX_RTN_ANYCAST 4
+#define LX_RTN_MULTICAST 5
+#define LX_RTN_BLACKHOLE 6
+#define LX_RTN_UNREACHABLE 7
+#define LX_RTN_PROHIBIT 8
+#define LX_RTN_THROW 9
+#define LX_RTN_NAT 10
+#define LX_RTN_XRESOLVE 11
+
+/* rtm_protocol */
+#define LX_RTPROT_UNSPEC 0
+#define LX_RTPROT_REDIRECT 1 /* From ICMP redir */
+#define LX_RTPROT_KERNEL 2 /* From kernel */
+#define LX_RTPROT_BOOT 3 /* From boot */
+#define LX_RTPROT_STATIC 4 /* From administrator */
+#define LX_RTPROT_NULL 0xff /* Uninitialized */
+
+/* rtm_scope */
+#define LX_RTSCOPE_UNIVERSE 0
+#define LX_RTSCOPE_SITE 200
+#define LX_RTSCOPE_LINK 253
+#define LX_RTSCOPE_HOST 254
+#define LX_RTSCOPE_NOWHERE 255
+
/*
* Netlink sockopts
@@ -270,6 +306,22 @@
#define LX_NETLINK_SO_RX_RING 6
#define LX_NETLINK_SO_TX_RING 7
+#define LXNLMSG_ALIGNTO 4
+#define LXNLMSG_ALIGN(len) \
+ (((len) + LXNLMSG_ALIGNTO - 1) & ~(LXNLMSG_ALIGNTO - 1))
+#define LXNLMSG_HDRLEN \
+ ((int)LXNLMSG_ALIGN(sizeof (lx_netlink_hdr_t)))
+#define LXNLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define LXNLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define LXNLMSG_DATA(nlh) ((void*)(((char *)nlh) + NLMSG_LENGTH(0)))
+#define LXNLMSG_PAYLOAD(nlh, len) \
+ ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define LXATTR_PAYLOAD(lxa) \
+ ((void*)((caddr_t)(lxa) + sizeof (lx_netlink_attr_t)))
+#define LXATTR_HDRLEN LXNLMSG_ALIGN(sizeof (lx_netlink_attr_t))
+#define LXATTR_LEN(len) (LXATTR_HDRLEN + LXNLMSG_ALIGN(len))
+
typedef struct lx_netlink_hdr {
uint32_t lxnh_len; /* length of message */
uint16_t lxnh_type; /* type of message */
@@ -306,6 +358,18 @@ typedef struct lx_netlink_ifaddrmsg {
uint8_t lxnl_ifa_index; /* interface index */
} lx_netlink_ifaddrmsg_t;
+typedef struct lx_netlink_rtmsg {
+ uint8_t rtm_family; /* route AF */
+ uint8_t rtm_dst_len; /* destination addr length */
+ uint8_t rtm_src_len; /* source addr length */
+ uint8_t rtm_tos; /* TOS filter */
+ uint8_t rtm_table; /* routing table ID */
+ uint8_t rtm_protocol; /* routing protocol */
+ uint8_t rtm_scope;
+ uint8_t rtm_type;
+ uint32_t rtm_flags;
+} lx_netlink_rtmsg_t;
+
typedef struct lx_netlink_sockaddr {
sa_family_t lxnl_family; /* AF_LX_NETLINK */
uint16_t lxnl_pad; /* padding */
@@ -507,25 +571,23 @@ lx_netlink_reply_add(lx_netlink_reply_t *reply, void *payload, uint32_t size)
{
lx_netlink_hdr_t *hdr;
lx_netlink_sock_t *lxsock = reply->lxnr_sock;
- uint32_t align, alignto = LX_NETLINK_NLA_ALIGNTO;
+ uint32_t aligned;
mblk_t *mp = reply->lxnr_mp;
if (reply->lxnr_errno)
return;
- align = (alignto - (size & (alignto - 1))) & (alignto - 1);
-
+ aligned = LXNLMSG_ALIGN(size);
hdr = (lx_netlink_hdr_t *)mp->b_rptr;
- if (hdr->lxnh_len + size + align > lxsock->lxns_bufsize) {
+ if (hdr->lxnh_len + aligned > lxsock->lxns_bufsize) {
reply->lxnr_errno = E2BIG;
return;
}
bcopy(payload, mp->b_wptr, size);
-
- hdr->lxnh_len += size + align;
- mp->b_wptr += size + align;
+ hdr->lxnh_len += aligned;
+ mp->b_wptr += aligned;
}
static void
@@ -548,11 +610,11 @@ lx_netlink_reply_msg(lx_netlink_reply_t *reply, void *payload, uint32_t size)
bzero(mp->b_rptr, lxsock->lxns_bufsize);
hdr = (lx_netlink_hdr_t *)mp->b_rptr;
hdr->lxnh_flags = LX_NETLINK_NLM_F_MULTI;
- hdr->lxnh_len = sizeof (lx_netlink_hdr_t);
+ hdr->lxnh_len = LXNLMSG_ALIGN(sizeof (lx_netlink_hdr_t));
hdr->lxnh_seq = reply->lxnr_hdr.lxnh_seq;
hdr->lxnh_pid = lxsock->lxns_port;
- mp->b_wptr += sizeof (lx_netlink_hdr_t);
+ mp->b_wptr += LXNLMSG_ALIGN(sizeof (lx_netlink_hdr_t));
if (payload == NULL) {
/*
@@ -738,6 +800,52 @@ lx_netlink_reply_error(lx_netlink_sock_t *lxsock,
return (0);
}
+static int
+lx_netlink_parse_msg_attrs(mblk_t *mp, void **msgp, unsigned int msg_size,
+ lx_netlink_attr_t **attrp, unsigned int *attr_max)
+{
+ lx_netlink_hdr_t *hdr = (lx_netlink_hdr_t *)mp->b_rptr;
+ lx_netlink_attr_t *lxa;
+ unsigned char *buf = mp->b_rptr + LXNLMSG_HDRLEN;
+ unsigned int i;
+ uint32_t buf_left = MBLKL(mp) - LXNLMSG_HDRLEN;
+ uint32_t msg_left = hdr->lxnh_len;
+
+ msg_size = LXNLMSG_ALIGN(msg_size);
+ if (msg_size > buf_left || msg_size > msg_left) {
+ return (-1);
+ }
+
+ *msgp = (void *)buf;
+ buf += msg_size;
+ buf_left -= msg_size;
+ msg_left -= msg_size;
+
+ /* Do not bother with attr parsing if not requested */
+ if (attrp == NULL || *attr_max == 0) {
+ return (0);
+ }
+
+ for (i = 0; i < *attr_max; i++) {
+ if (buf_left < LXATTR_HDRLEN || msg_left < LXATTR_HDRLEN) {
+ break;
+ }
+
+ lxa = (lx_netlink_attr_t *)buf;
+ if (lxa->lxna_len > buf_left || lxa->lxna_len > msg_left) {
+ return (-1);
+ }
+
+ attrp[i] = lxa;
+ buf += lxa->lxna_len;
+ buf_left -= lxa->lxna_len;
+ msg_left -= lxa->lxna_len;
+ }
+ *attr_max = i;
+
+ return (0);
+}
+
static void
lx_netlink_getlink_lifreq(lx_netlink_reply_t *reply, struct lifreq *lifr)
{
@@ -1015,6 +1123,188 @@ lx_netlink_getaddr(lx_netlink_sock_t *lxsock, lx_netlink_hdr_t *hdr, mblk_t *mp)
return (0);
}
+struct lx_getroute_ctx {
+ lx_netlink_reply_t *lgrtctx_reply;
+ lx_netlink_rtmsg_t *lgrtctx_rtmsg;
+ lx_netlink_attr_t *lgrtctx_attrs[LX_NETLINK_MAX_RTA];
+ unsigned int lgrtctx_max_attr;
+ lx_netlink_attr_t *lgrtctx_rtadst;
+};
+
+static void
+lx_netlink_getroute_ipv4(ire_t *ire, struct lx_getroute_ctx *ctx)
+{
+ lx_netlink_reply_t *reply = ctx->lgrtctx_reply;
+ lx_netlink_rtmsg_t *rtmsg = ctx->lgrtctx_rtmsg;
+ lx_netlink_attr_t *rtadst = ctx->lgrtctx_rtadst;
+ lx_netlink_rtmsg_t res;
+ ill_t *ill = NULL;
+
+ /* Certain IREs are too specific for netlink */
+ if ((ire->ire_type & (IRE_BROADCAST | IRE_MULTICAST | IRE_NOROUTE |
+ IRE_LOOPBACK | IRE_LOCAL)) != 0 || ire->ire_testhidden != 0) {
+ return;
+ }
+ /*
+ * When listing routes, CLONE entries are undesired.
+ * They are required for 'ip route get' on a local address.
+ */
+ if (rtmsg->rtm_dst_len == 0 && (ire->ire_type & IRE_IF_CLONE) != 0) {
+ return;
+ }
+
+ bzero(&res, sizeof (res));
+ res.rtm_family = LX_AF_INET;
+ res.rtm_table = LX_ROUTE_TABLE_MAIN;
+ res.rtm_type = LX_RTN_UNICAST;
+ res.rtm_dst_len = ire->ire_masklen;
+
+ if (ire->ire_type & (IRE_IF_NORESOLVER|IRE_IF_RESOLVER)) {
+ /* Interface-local networks considered kernel-created */
+ res.rtm_protocol = LX_RTPROT_KERNEL;
+ res.rtm_scope = LX_RTSCOPE_LINK;
+ } else if (ire->ire_flags & RTF_STATIC) {
+ res.rtm_protocol = LX_RTPROT_STATIC;
+ }
+
+ if (rtmsg->rtm_dst_len == 0x20 && rtadst != NULL) {
+ /*
+ * SpecifY single-destination route.
+ * RTA_DST details will be added later
+ */
+ res.rtm_dst_len = rtmsg->rtm_dst_len;
+ }
+
+
+ lx_netlink_reply_msg(reply, &res, sizeof (res));
+
+ if (rtmsg->rtm_dst_len == 0x20 && rtadst != NULL) {
+ /* Add RTA_DST details for single-destination route. */
+ lx_netlink_reply_attr(reply, LX_NETLINK_RTA_DST,
+ LXATTR_PAYLOAD(rtadst), sizeof (ipaddr_t));
+ } else if (ire->ire_masklen != 0) {
+ lx_netlink_reply_attr(reply, LX_NETLINK_RTA_DST,
+ &ire->ire_addr, sizeof (ire->ire_addr));
+ }
+
+ if (ire->ire_ill != NULL) {
+ ill = ire->ire_ill;
+ } else if (ire->ire_dep_parent != NULL) {
+ ill = ire->ire_dep_parent->ire_ill;
+ }
+
+ if (ill != NULL) {
+ uint32_t ifindex, addr_src;
+
+ ifindex = ill->ill_phyint->phyint_ifindex;
+ lx_netlink_reply_attr(reply, LX_NETLINK_RTA_OIF,
+ &ifindex, sizeof (ifindex));
+
+ addr_src = ill->ill_ipif->ipif_lcl_addr;
+ lx_netlink_reply_attr(reply, LX_NETLINK_RTA_PREFSRC,
+ &addr_src, sizeof (addr_src));
+ }
+
+ if (ire->ire_flags & RTF_GATEWAY) {
+ lx_netlink_reply_attr(reply, LX_NETLINK_RTA_GATEWAY,
+ &ire->ire_gateway_addr, sizeof (ire->ire_gateway_addr));
+ }
+
+ lx_netlink_reply_send(reply);
+}
+
+/*ARGSUSED*/
+static int
+lx_netlink_getroute(lx_netlink_sock_t *lxsock, lx_netlink_hdr_t *hdr,
+ mblk_t *mp)
+{
+ struct lx_getroute_ctx ctx;
+ lx_netlink_reply_t *reply;
+ lx_netlink_rtmsg_t rtmsg, *rtmsgp;
+ int rtmsg_size = sizeof (rtmsg);
+ netstack_t *ns;
+ int i;
+
+ bzero(&ctx, sizeof (ctx));
+ ctx.lgrtctx_max_attr = LX_NETLINK_MAX_RTA;
+
+ if (lx_netlink_parse_msg_attrs(mp, (void **)&rtmsgp,
+ rtmsg_size, ctx.lgrtctx_attrs, &ctx.lgrtctx_max_attr) != 0) {
+ return (EPROTO);
+ }
+
+ /*
+ * Older version of libnetlink send a truncated rtmsg struct for
+ * certain RTM_GETROUTE queries. We must detect this condition and
+ * truncate our input to prevent later confusion.
+ */
+ if (curproc->p_zone->zone_brand == &lx_brand &&
+ lx_kern_version_cmp(curproc->p_zone, "2.6.32") <= 0 &&
+ rtmsgp->rtm_dst_len == 0) {
+ rtmsg_size = sizeof (rtmsg.rtm_family);
+ }
+ bzero(&rtmsg, sizeof (rtmsg));
+ bcopy(rtmsgp, &rtmsg, rtmsg_size);
+ ctx.lgrtctx_rtmsg = &rtmsg;
+
+ /* If RTA_DST was passed, it effects later decisions */
+ for (i = 0; i < ctx.lgrtctx_max_attr; i++) {
+ lx_netlink_attr_t *attr = ctx.lgrtctx_attrs[i];
+
+ if (attr->lxna_type == LX_NETLINK_RTA_DST &&
+ attr->lxna_len == LXATTR_LEN(sizeof (ipaddr_t))) {
+ ctx.lgrtctx_rtadst = attr;
+ break;
+ }
+ }
+
+ reply = lx_netlink_reply(lxsock, hdr, LX_NETLINK_RTM_NEWROUTE);
+ if (reply == NULL) {
+ return (ENOMEM);
+ }
+ ctx.lgrtctx_reply = reply;
+
+ /* Do not report anything outside the main table */
+ if (rtmsg.rtm_table != LX_ROUTE_TABLE_MAIN &&
+ rtmsg.rtm_table != 0) {
+ lx_netlink_reply_done(reply);
+ return (0);
+ }
+
+ ns = netstack_get_current();
+ if (ns == NULL) {
+ lx_netlink_reply_done(reply);
+ return (0);
+ }
+ if (rtmsg.rtm_family == LX_AF_INET || rtmsg.rtm_family == 0) {
+ if (rtmsg.rtm_dst_len == 0x20 && ctx.lgrtctx_rtadst != NULL) {
+ /* resolve route for host */
+ ipaddr_t *dst = LXATTR_PAYLOAD(ctx.lgrtctx_rtadst);
+ ire_t *ire_dst;
+
+ ire_dst = ire_route_recursive_dstonly_v4(*dst, 0, 0,
+ ns->netstack_ip);
+ lx_netlink_getroute_ipv4(ire_dst, &ctx);
+ ire_refrele(ire_dst);
+ } else {
+ /* get route listing */
+ ire_walk_v4(&lx_netlink_getroute_ipv4, &ctx, ALL_ZONES,
+ ns->netstack_ip);
+ }
+ }
+ if (rtmsg.rtm_family == LX_AF_INET6) {
+ /* punt on ipv6 for now */
+ netstack_rele(ns);
+ lx_netlink_reply_done(reply);
+ return (EPROTO);
+ }
+ netstack_rele(ns);
+
+ lx_netlink_reply_done(reply);
+ return (0);
+}
+
+
/*ARGSUSED*/
static int
lx_netlink_audit(lx_netlink_sock_t *lxsock, lx_netlink_hdr_t *hdr, mblk_t *mp)
@@ -1057,6 +1347,8 @@ lx_netlink_send(sock_lower_handle_t handle, mblk_t *mp,
LX_NETLINK_RTM_GETLINK, lx_netlink_getlink },
{ LX_NETLINK_ROUTE,
LX_NETLINK_RTM_GETADDR, lx_netlink_getaddr },
+ { LX_NETLINK_ROUTE,
+ LX_NETLINK_RTM_GETROUTE, lx_netlink_getroute },
{ LX_NETLINK_AUDIT,
LX_NETLINK_NLMSG_NONE, lx_netlink_audit },
{ LX_NETLINK_KOBJECT_UEVENT,
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index c22d782b68..4e3396503e 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -170,6 +170,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <lx_signum.h>
+#include <util/sscanf.h>
int lx_debug = 0;
@@ -1291,6 +1292,34 @@ lx_set_kern_version(zone_t *zone, char *vers)
}
/*
+ * Compare linux kernel version to the one set for the zone.
+ * Returns greater than 0 if zone version is higher, less than 0 if the zone
+ * version is lower, and 0 if the version are equal.
+ */
+int
+lx_kern_version_cmp(zone_t *zone, const char *vers)
+{
+ int zvers[3] = {0, 0, 0};
+ int cvers[3] = {0, 0, 0};
+ int i;
+
+ VERIFY(zone->zone_brand == &lx_brand);
+
+ (void) sscanf(ztolxzd(zone)->lxzd_kernel_version, "%d.%d.%d", &zvers[0],
+ &zvers[1], &zvers[2]);
+ (void) sscanf(vers, "%d.%d.%d", &cvers[0], &cvers[1], &cvers[2]);
+
+ for (i = 0; i < 3; i++) {
+ if (zvers[i] > cvers[i]) {
+ return (1);
+ } else if (zvers[i] < cvers[i]) {
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
* Linux unconditionally removes the setuid and setgid bits when changing
* file ownership. This brand hook overrides the illumos native behaviour,
* which is based on the PRIV_FILE_SETID privilege.
diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h
index aeeab5ca78..00a365993e 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h
@@ -639,6 +639,7 @@ typedef struct lx_zone_data {
#endif
extern char *lx_get_zone_kern_version(zone_t *);
+extern int lx_kern_version_cmp(zone_t *, const char *);
extern void lx_lwp_set_native_stack_current(lx_lwp_data_t *, uintptr_t);
extern void lx_divert(klwp_t *, uintptr_t);
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 3112d743a4..893cc3a52b 100644
--- a/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c
+++ b/usr/src/uts/common/brand/lx/syscall/lx_ioctl.c
@@ -45,6 +45,9 @@
#include <sys/ethernet.h>
#include <sys/dlpi.h>
#include <sys/lx_autofs.h>
+#include <sys/netstack.h>
+#include <inet/ip.h>
+#include <inet/ip_if.h>
/*
* Supported ioctls
@@ -94,6 +97,7 @@
#define LX_SIOCGPGRP 0x8904
#define LX_SIOCATMARK 0x8905
#define LX_SIOCGSTAMP 0x8906
+#define LX_SIOCGIFNAME 0x8910
#define LX_SIOCGIFCONF 0x8912
#define LX_SIOCGIFFLAGS 0x8913
#define LX_SIOCSIFFLAGS 0x8914
@@ -838,6 +842,60 @@ ict_sioghwaddr(file_t *fp, struct lifreq *lreq)
}
static int
+ict_siocgifname(file_t *fp, int cmd, intptr_t arg, int lxcmd)
+{
+ struct ifreq req;
+ int len;
+ char name[LIFNAMSIZ];
+ netstack_t *ns;
+ ip_stack_t *ipst;
+ phyint_t *phyi;
+
+ if (fp->f_vnode->v_type != VSOCK) {
+ return (set_errno(EINVAL));
+ }
+
+ len = (curproc->p_model == DATAMODEL_LP64) ? sizeof (lx_ifreq64_t) :
+ sizeof (lx_ifreq32_t);
+ if (copyin((struct ifreq *)arg, &req, len) != 0) {
+ return (set_errno(EFAULT));
+ }
+
+ /*
+ * Since Linux calls this ioctl on all sorts of sockets, perform the
+ * interface name lookup manually.
+ */
+ if ((ns = netstack_get_current()) == NULL) {
+ return (set_errno(EINVAL));
+ }
+ ipst = ns->netstack_ip;
+
+ rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+ phyi = avl_find(&ipst->ips_phyint_g_list->phyint_list_avl_by_index,
+ (void *) &req.ifr_index, NULL);
+ if (phyi != NULL) {
+ strncpy(name, phyi->phyint_name, LIFNAMSIZ);
+ lx_ifname_convert(name, LX_IF_FROMNATIVE);
+ } else {
+ name[0] = '\0';
+ }
+
+ rw_exit(&ipst->ips_ill_g_lock);
+ netstack_rele(ns);
+
+ if (strlen(name) != 0) {
+ /* Truncate for ifreq and copyout */
+ strncpy(req.ifr_name, name, IFNAMSIZ);
+ if (copyout(&req, (struct ifreq *)arg, len) != 0) {
+ return (set_errno(EFAULT));
+ }
+ return (0);
+ }
+
+ return (set_errno(EINVAL));
+}
+
+static int
ict_siolifreq(file_t *fp, int cmd, intptr_t arg, int lxcmd)
{
struct ifreq req;
@@ -1154,6 +1212,7 @@ static ioc_cmd_translator_t ioc_translators[] = {
IOC_CMD_TRANSLATOR_FILTER(SIOCGIFINDEX, ict_siolifreq)
IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFTXQLEN, ict_siolifreq)
IOC_CMD_TRANSLATOR_FILTER(SIOCGIFCONF, ict_siocgifconf)
+ IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFNAME, ict_siocgifname)
/* dtrace related */
IOC_CMD_TRANSLATOR_PTHRU(DTRACEHIOC_ADD)
diff --git a/usr/src/uts/intel/lx_brand/Makefile b/usr/src/uts/intel/lx_brand/Makefile
index 01ac92512c..b0b4cd2903 100644
--- a/usr/src/uts/intel/lx_brand/Makefile
+++ b/usr/src/uts/intel/lx_brand/Makefile
@@ -21,7 +21,7 @@
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright 2014 Joyent, Inc. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
# This makefile drives the production of the kernel component of
# the lx brand
@@ -58,6 +58,7 @@ LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
INC_PATH += -I$(UTSBASE)/common/brand/lx -I$(LX_CMN)
+INC_PATH += -I$(SRC)/common
AS_INC_PATH += -I$(UTSBASE)/i86pc/genassym/$(OBJS_DIR)
#