diff --git a/drivers/infiniband/ulp/ipoib/Makefile b/drivers/infiniband/ulp/ipoib/Makefile
index e5430dd..9915cf8 100644
--- a/drivers/infiniband/ulp/ipoib/Makefile
+++ b/drivers/infiniband/ulp/ipoib/Makefile
@@ -6,7 +6,8 @@ ib_ipoib-y					:= ipoib_main.o \
 						   ipoib_verbs.o \
 						   ipoib_vlan.o \
 						   ipoib_ethtool.o \
-						   ipoib_netlink.o
+						   ipoib_netlink.o \
+						   ipoib_ioctl.o
 ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM)		+= ipoib_cm.o
 ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG)	+= ipoib_fs.o
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index edc5b85..01b8d4d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -434,6 +434,15 @@ struct ipoib_neigh {
 	unsigned long       alive;
 };
 
+/* ioctl API */
+#define IPOIBGETSGUID		SIOCDEVPRIVATE
+
+struct ipoib_ioctl_getsgid_data {
+	u64	gid;
+	u64	subnet_prefix;
+	int	fd;
+};
+
 #define IPOIB_UD_MTU(ib_mtu)		(ib_mtu - IPOIB_ENCAP_LEN)
 #define IPOIB_UD_BUF_SIZE(ib_mtu)	(ib_mtu + IB_GRH_BYTES)
 
@@ -452,6 +461,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid);
 extern struct workqueue_struct *ipoib_workqueue;
 
 /* functions */
+struct list_head *ipoib_get_dev_list(struct ib_device *dev);
 
 int ipoib_poll(struct napi_struct *napi, int budget);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
@@ -467,6 +477,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah)
 int ipoib_open(struct net_device *dev);
 int ipoib_add_pkey_attr(struct net_device *dev);
 int ipoib_add_umcast_attr(struct net_device *dev);
+int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 void ipoib_send(struct net_device *dev, struct sk_buff *skb,
 		struct ipoib_ah *address, u32 qpn);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c
new file mode 100644
index 0000000..124d545
--- /dev/null
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015 Oracle Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <net/arp.h>
+#include <linux/jhash.h>
+#include <net/inet_sock.h>
+#include <net/route.h>
+
+#include "ipoib.h"
+
+static int ipoib_get_sguid(struct net_device *dev, int fd, u64 *sgid,
+			   u64 *subnet_prefix)
+{
+	struct socket *sock;
+	struct inet_sock *inetsock;
+	struct neighbour *neigh;
+	int rc = 0;
+	union ib_gid *gid;
+	struct list_head *dev_list = 0;
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	u16 pkey_index = priv->pkey_index;
+	struct ipoib_dev_priv *child_priv;
+
+	sock = sockfd_lookup(fd, &rc);
+	if (IS_ERR_OR_NULL(sock))
+		return -EINVAL;
+
+	inetsock = inet_sk(sock->sk);
+
+	neigh = neigh_lookup(&arp_tbl, &inetsock->inet_daddr, dev);
+	if (!IS_ERR_OR_NULL(neigh))
+		goto found;
+
+	/* If not found try in all other ipoib devices */
+	dev_list = ipoib_get_dev_list(priv->ca);
+	if (!dev_list)
+		return -EINVAL;
+
+	list_for_each_entry(priv, dev_list, list) {
+		if (priv->pkey_index == pkey_index) {
+			neigh = neigh_lookup(&arp_tbl, &inetsock->inet_daddr,
+					     priv->dev);
+			if (!IS_ERR_OR_NULL(neigh))
+				goto found;
+		}
+		list_for_each_entry(child_priv, &priv->child_intfs, list) {
+			if (child_priv->pkey_index == pkey_index) {
+				neigh = neigh_lookup(&arp_tbl,
+						     &inetsock->inet_daddr,
+						     child_priv->dev);
+				if (!IS_ERR_OR_NULL(neigh))
+					goto found;
+			}
+		}
+	}
+
+	return -ENODEV;
+
+found:
+	if (!(neigh->nud_state & NUD_VALID))
+		return -EINVAL;
+
+	gid = (union ib_gid *)(neigh->ha + 4);
+	*sgid = be64_to_cpu(gid->global.interface_id);
+	*subnet_prefix = be64_to_cpu(gid->global.subnet_prefix);
+
+	neigh_release(neigh);
+
+	return 0;
+}
+
+static int ipoib_ioctl_getsguid(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ipoib_ioctl_getsgid_data req_data;
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int rc;
+
+	rc = copy_from_user(&req_data, ifr->ifr_data,
+			    sizeof(struct ipoib_ioctl_getsgid_data));
+	if (rc != 0) {
+		ipoib_warn(priv, "ioctl fail to copy request data\n");
+		return -EINVAL;
+	}
+	rc = ipoib_get_sguid(dev, req_data.fd, &req_data.gid,
+			     &req_data.subnet_prefix);
+	if (rc) {
+		ipoib_warn(priv, "Invalid fd %d (err=%d)\n",
+			   req_data.fd, rc);
+		return rc;
+	}
+	ipoib_dbg(priv, "ioctl_getsgid: subnet_prefix=0x%llx\n",
+		  req_data.subnet_prefix);
+	ipoib_dbg(priv, "ioctl_getsgid: src_gid=0x%llx\n", req_data.gid);
+	rc = copy_to_user(ifr->ifr_data, &req_data,
+			  sizeof(struct ipoib_ioctl_getsgid_data));
+	if (rc != 0) {
+		ipoib_warn(priv,
+			   "ioctl fail to copy back request data\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int rc = -EINVAL;
+
+	switch (cmd) {
+	case IPOIBGETSGUID:
+		rc = ipoib_ioctl_getsguid(dev, ifr);
+		if (rc != 0)
+			return -EINVAL;
+		break;
+	default:
+		ipoib_warn(priv, "invalid ioctl opcode 0x%x\n", cmd);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index babba05..15665af 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1619,6 +1619,7 @@ static const struct net_device_ops ipoib_netdev_ops = {
 	.ndo_tx_timeout		 = ipoib_timeout,
 	.ndo_set_rx_mode	 = ipoib_set_mcast_list,
 	.ndo_get_iflink		 = ipoib_get_iflink,
+	.ndo_do_ioctl		 = ipoib_do_ioctl,
 };
 
 void ipoib_setup(struct net_device *dev)
@@ -1962,6 +1963,11 @@ static void ipoib_add_one(struct ib_device *device)
 	ib_set_client_data(device, &ipoib_client, dev_list);
 }
 
+struct list_head *ipoib_get_dev_list(struct ib_device *dev)
+{
+	return ib_get_client_data(dev, &ipoib_client);
+}
+
 static void ipoib_remove_one(struct ib_device *device, void *client_data)
 {
 	struct ipoib_dev_priv *priv, *tmp;
