linux/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <linux/module.h>
  34
  35#include <linux/init.h>
  36#include <linux/slab.h>
  37#include <linux/seq_file.h>
  38
  39#include <asm/uaccess.h>
  40
  41#include "ipoib.h"
  42
  43static ssize_t show_parent(struct device *d, struct device_attribute *attr,
  44                           char *buf)
  45{
  46        struct net_device *dev = to_net_dev(d);
  47        struct ipoib_dev_priv *priv = netdev_priv(dev);
  48
  49        return sprintf(buf, "%s\n", priv->parent->name);
  50}
  51static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
  52
  53int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
  54{
  55        struct ipoib_dev_priv *ppriv, *priv;
  56        char intf_name[IFNAMSIZ];
  57        int result;
  58
  59        if (!capable(CAP_NET_ADMIN))
  60                return -EPERM;
  61
  62        ppriv = netdev_priv(pdev);
  63
  64        if (!rtnl_trylock())
  65                return restart_syscall();
  66        mutex_lock(&ppriv->vlan_mutex);
  67
  68        /*
  69         * First ensure this isn't a duplicate. We check the parent device and
  70         * then all of the child interfaces to make sure the Pkey doesn't match.
  71         */
  72        if (ppriv->pkey == pkey) {
  73                result = -ENOTUNIQ;
  74                priv = NULL;
  75                goto err;
  76        }
  77
  78        list_for_each_entry(priv, &ppriv->child_intfs, list) {
  79                if (priv->pkey == pkey) {
  80                        result = -ENOTUNIQ;
  81                        priv = NULL;
  82                        goto err;
  83                }
  84        }
  85
  86        snprintf(intf_name, sizeof intf_name, "%s.%04x",
  87                 ppriv->dev->name, pkey);
  88        priv = ipoib_intf_alloc(intf_name);
  89        if (!priv) {
  90                result = -ENOMEM;
  91                goto err;
  92        }
  93
  94        priv->max_ib_mtu = ppriv->max_ib_mtu;
  95        /* MTU will be reset when mcast join happens */
  96        priv->dev->mtu   = IPOIB_UD_MTU(priv->max_ib_mtu);
  97        priv->mcast_mtu  = priv->admin_mtu = priv->dev->mtu;
  98        set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
  99
 100        result = ipoib_set_dev_features(priv, ppriv->ca);
 101        if (result)
 102                goto err;
 103
 104        priv->pkey = pkey;
 105
 106        memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN);
 107        priv->dev->broadcast[8] = pkey >> 8;
 108        priv->dev->broadcast[9] = pkey & 0xff;
 109
 110        result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port);
 111        if (result < 0) {
 112                ipoib_warn(ppriv, "failed to initialize subinterface: "
 113                           "device %s, port %d",
 114                           ppriv->ca->name, ppriv->port);
 115                goto err;
 116        }
 117
 118        result = register_netdevice(priv->dev);
 119        if (result) {
 120                ipoib_warn(priv, "failed to initialize; error %i", result);
 121                goto register_failed;
 122        }
 123
 124        priv->parent = ppriv->dev;
 125
 126        ipoib_create_debug_files(priv->dev);
 127
 128        if (ipoib_cm_add_mode_attr(priv->dev))
 129                goto sysfs_failed;
 130        if (ipoib_add_pkey_attr(priv->dev))
 131                goto sysfs_failed;
 132        if (ipoib_add_umcast_attr(priv->dev))
 133                goto sysfs_failed;
 134
 135        if (device_create_file(&priv->dev->dev, &dev_attr_parent))
 136                goto sysfs_failed;
 137
 138        list_add_tail(&priv->list, &ppriv->child_intfs);
 139
 140        mutex_unlock(&ppriv->vlan_mutex);
 141        rtnl_unlock();
 142
 143        return 0;
 144
 145sysfs_failed:
 146        ipoib_delete_debug_files(priv->dev);
 147        unregister_netdevice(priv->dev);
 148
 149register_failed:
 150        ipoib_dev_cleanup(priv->dev);
 151
 152err:
 153        mutex_unlock(&ppriv->vlan_mutex);
 154        rtnl_unlock();
 155        if (priv)
 156                free_netdev(priv->dev);
 157
 158        return result;
 159}
 160
 161int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
 162{
 163        struct ipoib_dev_priv *ppriv, *priv, *tpriv;
 164        struct net_device *dev = NULL;
 165
 166        if (!capable(CAP_NET_ADMIN))
 167                return -EPERM;
 168
 169        ppriv = netdev_priv(pdev);
 170
 171        if (!rtnl_trylock())
 172                return restart_syscall();
 173        mutex_lock(&ppriv->vlan_mutex);
 174        list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
 175                if (priv->pkey == pkey) {
 176                        unregister_netdevice(priv->dev);
 177                        ipoib_dev_cleanup(priv->dev);
 178                        list_del(&priv->list);
 179                        dev = priv->dev;
 180                        break;
 181                }
 182        }
 183        mutex_unlock(&ppriv->vlan_mutex);
 184        rtnl_unlock();
 185
 186        if (dev) {
 187                free_netdev(dev);
 188                return 0;
 189        }
 190
 191        return -ENODEV;
 192}
 193