[ofa-general] [PATCH 3/4] ipoib: support multiple devices on the same partition

Rolf Manderscheid rvm at obsidianresearch.com
Mon Dec 10 12:41:16 PST 2007


Multiple devices can coexist in a partition provided they have different scopes.
This patch adds an optional scope argument to the create_child / delete_child
attributes.  Created child devices are still named the same way as before, so
in order to create multiple child devices in the same partition, an interface
name change will be necessary to make room for subsequent children, eg:
	echo 0xffff 0xe > /sys/class/net/ib0/create_child
	ip link set ib0.ffff name ib0.global

Signed-off-by: Rolf Manderscheid <rvm at obsidianresearch.com>

---

diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index d35025f..a1834d8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -450,13 +450,29 @@ void ipoib_transport_dev_cleanup(struct net_device *dev);
 void ipoib_event(struct ib_event_handler *handler,
 		 struct ib_event *record);
 
-int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey);
-int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey);
+int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey,
+		   unsigned char scope);
+int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey,
+		      unsigned char scope);
 
 void ipoib_pkey_poll(struct work_struct *work);
 int ipoib_pkey_dev_delay_open(struct net_device *dev);
 void ipoib_drain_cq(struct net_device *dev);
 
+int ipoib_pkey_scope_in_use(struct net_device *dev, unsigned short pkey,
+			    unsigned char scope);
+
+static inline unsigned char ipoib_get_scope(struct net_device *dev)
+{
+	return dev->broadcast[5] & 0xF;
+}
+
+static inline void ipoib_set_scope(struct net_device *dev, unsigned char scope)
+{
+	dev->broadcast[5] &= ~0xF;
+	dev->broadcast[5] |= scope;
+}
+
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
 
 #define IPOIB_FLAGS_RC		0x80
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7b6627f..07cce7f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -79,6 +79,8 @@ static const u8 ipv4_bcast_addr[] = {
 	0x00, 0x00, 0x00, 0x00,	0xff, 0xff, 0xff, 0xff
 };
 
+static const u8 default_scope = 2; /* link local */
+
 struct workqueue_struct *ipoib_workqueue;
 
 struct ib_sa_client ipoib_sa_client;
@@ -1059,9 +1061,20 @@ int ipoib_add_umcast_attr(struct net_device *dev)
 static ssize_t show_bcast_scope(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+	return sprintf(buf, "0x%x\n", (int) ipoib_get_scope(to_net_dev(dev)));
+}
 
-	return sprintf(buf, "0x%x\n", priv->dev->broadcast[5] & 0xF);
+static int valid_scope(unsigned char scope)
+{
+	switch (scope) {
+	case 0x2: /* link-local */
+	case 0x5: /* site-local */
+	case 0x8: /* organization-local */
+	case 0xE: /* global */
+		return 1;
+	default:
+		return 0;
+	}
 }
 
 static ssize_t set_bcast_scope(struct device *dev,
@@ -1074,21 +1087,16 @@ static ssize_t set_bcast_scope(struct device *dev,
 	if (priv->dev->flags & IFF_UP)
 		return -EBUSY;
 
-	if (sscanf(buf, "%i", &scope) != 1)
+	if (sscanf(buf, "%i", &scope) != 1 || !valid_scope(scope))
 		return -EINVAL;
 
-	switch (scope) {
-	case 0x2: /* link-local */
-	case 0x5: /* site-local */
-	case 0x8: /* organization-local */
-	case 0xE: /* global */
-		break;
-	default:
-		return -EINVAL;
-	}
+	if (ipoib_get_scope(priv->dev) == scope) /* no change */
+		return count;
 
-	priv->dev->broadcast[5] &= ~0xF;
-	priv->dev->broadcast[5] |= scope;
+	if (ipoib_pkey_scope_in_use(priv->dev, priv->pkey, scope))
+		return -ENOTUNIQ;
+
+	ipoib_set_scope(priv->dev, scope);
 	return count;
 }
 static DEVICE_ATTR(broadcast_scope, S_IWUSR | S_IRUGO, show_bcast_scope, set_bcast_scope);
@@ -1098,21 +1106,25 @@ static ssize_t create_child(struct device *dev,
 			    const char *buf, size_t count)
 {
 	int pkey;
+	int scope = default_scope;
 	int ret;
 
-	if (sscanf(buf, "%i", &pkey) != 1)
+	if (sscanf(buf, "%i %i", &pkey, &scope) < 1)
 		return -EINVAL;
 
 	if (pkey < 0 || pkey > 0xffff)
 		return -EINVAL;
 
+	if (!valid_scope(scope))
+		return -EINVAL;
+
 	/*
 	 * Set the full membership bit, so that we join the right
 	 * broadcast group, etc.
 	 */
 	pkey |= 0x8000;
 
-	ret = ipoib_vlan_add(to_net_dev(dev), pkey);
+	ret = ipoib_vlan_add(to_net_dev(dev), pkey, scope);
 
 	return ret ? ret : count;
 }
@@ -1123,21 +1135,44 @@ static ssize_t delete_child(struct device *dev,
 			    const char *buf, size_t count)
 {
 	int pkey;
+	int scope = default_scope;
 	int ret;
 
-	if (sscanf(buf, "%i", &pkey) != 1)
+	if (sscanf(buf, "%i %i", &pkey, &scope) < 1)
 		return -EINVAL;
 
 	if (pkey < 0 || pkey > 0xffff)
 		return -EINVAL;
 
-	ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
+	if (!valid_scope(scope))
+		return -EINVAL;
+
+	ret = ipoib_vlan_delete(to_net_dev(dev), pkey, scope);
 
 	return ret ? ret : count;
 
 }
 static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
 
+int ipoib_pkey_scope_in_use(struct net_device *dev, unsigned short pkey, unsigned char scope)
+{
+	struct ipoib_dev_priv *ppriv, *priv;
+
+	ppriv = netdev_priv(dev);
+	/*
+	 * We check the parent device and then all of the child interfaces to make sure
+	 * the Pkey and scope don't match.
+	 */
+	if (ppriv->pkey == pkey && ipoib_get_scope(dev) == scope)
+		return 1;
+
+	list_for_each_entry(priv, &ppriv->child_intfs, list)
+		if (priv->pkey == pkey && ipoib_get_scope(priv->dev) == scope)
+			return 1;
+
+	return 0;
+}
+
 int ipoib_add_pkey_attr(struct net_device *dev)
 {
 	return device_create_file(&dev->dev, &dev_attr_pkey);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 293f5b8..280556f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -52,7 +52,8 @@ static ssize_t show_parent(struct device *d, struct device_attribute *attr,
 }
 static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
 
-int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
+int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey,
+		   unsigned char scope)
 {
 	struct ipoib_dev_priv *ppriv, *priv;
 	char intf_name[IFNAMSIZ];
@@ -65,22 +66,11 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 
 	mutex_lock(&ppriv->vlan_mutex);
 
-	/*
-	 * First ensure this isn't a duplicate. We check the parent device and
-	 * then all of the child interfaces to make sure the Pkey doesn't match.
-	 */
-	if (ppriv->pkey == pkey) {
+	if (ipoib_pkey_scope_in_use(pdev, pkey, scope)) {
 		result = -ENOTUNIQ;
 		goto err;
 	}
 
-	list_for_each_entry(priv, &ppriv->child_intfs, list) {
-		if (priv->pkey == pkey) {
-			result = -ENOTUNIQ;
-			goto err;
-		}
-	}
-
 	snprintf(intf_name, sizeof intf_name, "%s.%04x",
 		 ppriv->dev->name, pkey);
 	priv = ipoib_intf_alloc(intf_name);
@@ -97,6 +87,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 	priv->dev->broadcast[8] = pkey >> 8;
 	priv->dev->broadcast[9] = pkey & 0xff;
 
+	ipoib_set_scope(priv->dev, scope);
+
 	result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port);
 	if (result < 0) {
 		ipoib_warn(ppriv, "failed to initialize subinterface: "
@@ -146,7 +138,8 @@ err:
 	return result;
 }
 
-int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
+int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey,
+		      unsigned char scope)
 {
 	struct ipoib_dev_priv *ppriv, *priv, *tpriv;
 	int ret = -ENOENT;
@@ -158,7 +151,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
 
 	mutex_lock(&ppriv->vlan_mutex);
 	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
-		if (priv->pkey == pkey) {
+		if (priv->pkey == pkey && ipoib_get_scope(priv->dev) == scope) {
 			unregister_netdev(priv->dev);
 			ipoib_dev_cleanup(priv->dev);
 			list_del(&priv->list);



More information about the general mailing list