]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
ib/ipoib: support multiple devices on the same partition
authorRolf Manderscheid <rvm@obsidianresearch.com>
Tue, 11 Dec 2007 17:12:03 +0000 (09:12 -0800)
committerSean Hefty <sean.hefty@intel.com>
Tue, 11 Dec 2007 17:12:03 +0000 (09:12 -0800)
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@obsidianresearch.com>
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_vlan.c

index eb7edab0e836041f444061889ddf3acf4ad7786c..2802ad2af421cd655e6fefa90e6ba4b605ac5e54 100644 (file)
@@ -446,13 +446,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
index 83a8f177a1d911a145100b0f650abce40528779f..6ce0a8865ce4c786e93652cd238f0fb251305008 100644 (file)
@@ -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;
@@ -1056,9 +1058,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,
@@ -1071,21 +1084,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);
@@ -1095,21 +1103,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;
 }
@@ -1120,21 +1132,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);
index 293f5b892e3f5f20d33ababa2a50f1688254f891..280556f22ada3f4247a917008dd81deec5e26571 100644 (file)
@@ -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);