2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Topspin Communications. 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 <linux/module.h>
|
2017-02-03 02:15:33 +08:00
|
|
|
#include <linux/sched/signal.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include "ipoib.h"
|
|
|
|
|
2002-04-10 03:14:34 +08:00
|
|
|
static ssize_t show_parent(struct device *d, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2002-04-10 03:14:34 +08:00
|
|
|
struct net_device *dev = to_net_dev(d);
|
2017-04-10 16:22:29 +08:00
|
|
|
struct ipoib_dev_priv *priv = ipoib_priv(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return sprintf(buf, "%s\n", priv->parent->name);
|
|
|
|
}
|
2002-04-10 03:14:34 +08:00
|
|
|
static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-09-13 13:56:36 +08:00
|
|
|
int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
|
|
|
|
u16 pkey, int type)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2008-04-24 02:55:45 +08:00
|
|
|
priv->max_ib_mtu = ppriv->max_ib_mtu;
|
2008-04-30 04:46:53 +08:00
|
|
|
/* MTU will be reset when mcast join happens */
|
|
|
|
priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
|
|
|
|
priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu;
|
2015-04-16 21:34:34 +08:00
|
|
|
priv->parent = ppriv->dev;
|
2005-04-17 06:20:36 +08:00
|
|
|
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
|
|
|
|
|
2017-01-05 16:56:08 +08:00
|
|
|
ipoib_set_dev_features(priv, ppriv->ca);
|
2008-10-23 06:49:49 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
priv->pkey = pkey;
|
|
|
|
|
|
|
|
memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN);
|
IB/IPoIB: Allow setting the device address
In IB networks, and specifically in IPoIB/rdmacm traffic, the device
address of an IPoIB interface is used as a means to exchange information
between nodes needed for communication.
Currently an IPoIB interface will always be created with a device
address based on its node GUID without a way to change that.
This change adds the ability to set the device address of an IPoIB
interface by value. We use the set mac address ndo to do that.
The flow should be broken down to two:
1) The GID value is already in the GID table,
in this case the interface will be able to set carrier up.
2) The GID value is not yet in the GID table,
in this case the interface won't try to join the multicast group
and will wait (listen on GID_CHANGE event) until the GID is inserted.
In order to track those changes, we add a new flag:
* IPOIB_FLAG_DEV_ADDR_SET.
When set, it means the dev_addr is a based on a value in the gid
table. this bit will be cleared upon a dev_addr change triggered
by the user and set after validation.
Per IB spec the port GUID can't change if the module is loaded.
port GUID is the basis for GID at index 0 which is the basis for
the default device address of a ipoib interface.
The issue is that there are devices that don't follow the spec,
they change the port GUID while HCA is powered on, so in order
not to break userspace applications. We need to check if the
user wanted to control the device address and we assume that
if he sets the device address back to be based on GID index 0,
he no longer wishs to control it.
In order to track this, we add an additional flag:
* IPOIB_FLAG_DEV_ADDR_CTRL
When setting the device address, there is no validation of the upper
twelve bytes of the device address (flags, qpn, subnet prefix) as those
bytes are not under the control of the user.
Signed-off-by: Mark Bloch <markb@mellanox.com>
Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2016-05-18 21:42:43 +08:00
|
|
|
memcpy(&priv->local_gid, &ppriv->local_gid, sizeof(priv->local_gid));
|
|
|
|
set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
priv->dev->broadcast[8] = pkey >> 8;
|
|
|
|
priv->dev->broadcast[9] = pkey & 0xff;
|
|
|
|
|
|
|
|
result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port);
|
|
|
|
if (result < 0) {
|
|
|
|
ipoib_warn(ppriv, "failed to initialize subinterface: "
|
|
|
|
"device %s, port %d",
|
|
|
|
ppriv->ca->name, ppriv->port);
|
2009-04-01 01:22:32 +08:00
|
|
|
goto err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-01-15 13:44:39 +08:00
|
|
|
result = register_netdevice(priv->dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (result) {
|
|
|
|
ipoib_warn(priv, "failed to initialize; error %i", result);
|
|
|
|
goto register_failed;
|
|
|
|
}
|
|
|
|
|
2012-09-27 20:06:02 +08:00
|
|
|
/* RTNL childs don't need proprietary sysfs entries */
|
|
|
|
if (type == IPOIB_LEGACY_CHILD) {
|
|
|
|
if (ipoib_cm_add_mode_attr(priv->dev))
|
|
|
|
goto sysfs_failed;
|
|
|
|
if (ipoib_add_pkey_attr(priv->dev))
|
|
|
|
goto sysfs_failed;
|
|
|
|
if (ipoib_add_umcast_attr(priv->dev))
|
|
|
|
goto sysfs_failed;
|
|
|
|
|
|
|
|
if (device_create_file(&priv->dev->dev, &dev_attr_parent))
|
|
|
|
goto sysfs_failed;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-09-27 20:06:02 +08:00
|
|
|
priv->child_type = type;
|
2005-04-17 06:20:36 +08:00
|
|
|
list_add_tail(&priv->list, &ppriv->child_intfs);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sysfs_failed:
|
2012-09-13 13:56:36 +08:00
|
|
|
result = -ENOMEM;
|
2009-01-15 13:44:39 +08:00
|
|
|
unregister_netdevice(priv->dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
register_failed:
|
|
|
|
ipoib_dev_cleanup(priv->dev);
|
|
|
|
|
|
|
|
err:
|
2012-09-13 13:56:36 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
|
|
|
|
{
|
|
|
|
struct ipoib_dev_priv *ppriv, *priv;
|
|
|
|
char intf_name[IFNAMSIZ];
|
|
|
|
struct ipoib_dev_priv *tpriv;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2017-04-10 16:22:30 +08:00
|
|
|
ppriv = ipoib_priv(pdev);
|
2012-09-13 13:56:36 +08:00
|
|
|
|
2016-06-04 20:15:20 +08:00
|
|
|
if (test_bit(IPOIB_FLAG_GOING_DOWN, &ppriv->flags))
|
|
|
|
return -EPERM;
|
|
|
|
|
2012-09-13 13:56:36 +08:00
|
|
|
snprintf(intf_name, sizeof intf_name, "%s.%04x",
|
|
|
|
ppriv->dev->name, pkey);
|
2017-04-10 16:22:30 +08:00
|
|
|
|
2017-08-17 20:50:50 +08:00
|
|
|
if (!mutex_trylock(&ppriv->sysfs_mutex))
|
2017-06-14 14:59:09 +08:00
|
|
|
return restart_syscall();
|
|
|
|
|
2017-08-17 20:50:50 +08:00
|
|
|
if (!rtnl_trylock()) {
|
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
|
|
|
return restart_syscall();
|
|
|
|
}
|
|
|
|
|
2017-09-25 02:46:32 +08:00
|
|
|
if (!down_write_trylock(&ppriv->vlan_rwsem)) {
|
2017-08-17 20:50:50 +08:00
|
|
|
rtnl_unlock();
|
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
2017-09-25 02:46:32 +08:00
|
|
|
return restart_syscall();
|
2017-08-17 20:50:50 +08:00
|
|
|
}
|
2012-09-13 13:56:36 +08:00
|
|
|
|
2017-09-25 02:46:32 +08:00
|
|
|
priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
|
|
|
|
if (!priv) {
|
|
|
|
result = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-09-13 13:56:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First ensure this isn't a duplicate. We check the parent device and
|
|
|
|
* then all of the legacy child interfaces to make sure the Pkey
|
|
|
|
* doesn't match.
|
|
|
|
*/
|
|
|
|
if (ppriv->pkey == pkey) {
|
|
|
|
result = -ENOTUNIQ;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
|
|
|
|
if (tpriv->pkey == pkey &&
|
|
|
|
tpriv->child_type == IPOIB_LEGACY_CHILD) {
|
|
|
|
result = -ENOTUNIQ;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
|
|
|
|
|
|
|
|
out:
|
2013-10-16 22:37:49 +08:00
|
|
|
up_write(&ppriv->vlan_rwsem);
|
2016-12-28 20:47:24 +08:00
|
|
|
rtnl_unlock();
|
2017-08-17 20:50:50 +08:00
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
2016-12-28 20:47:24 +08:00
|
|
|
|
2017-09-25 02:46:32 +08:00
|
|
|
if (result && priv) {
|
2017-09-25 02:46:33 +08:00
|
|
|
struct rdma_netdev *rn;
|
|
|
|
|
|
|
|
rn = netdev_priv(priv->dev);
|
|
|
|
rn->free_rdma_netdev(priv->dev);
|
2017-06-14 14:59:05 +08:00
|
|
|
kfree(priv);
|
|
|
|
}
|
2009-04-01 01:22:32 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
|
|
|
|
{
|
|
|
|
struct ipoib_dev_priv *ppriv, *priv, *tpriv;
|
2009-04-01 01:22:32 +08:00
|
|
|
struct net_device *dev = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!capable(CAP_NET_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2017-04-10 16:22:29 +08:00
|
|
|
ppriv = ipoib_priv(pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-06-04 20:15:20 +08:00
|
|
|
if (test_bit(IPOIB_FLAG_GOING_DOWN, &ppriv->flags))
|
|
|
|
return -EPERM;
|
|
|
|
|
2017-08-17 20:50:50 +08:00
|
|
|
if (!mutex_trylock(&ppriv->sysfs_mutex))
|
|
|
|
return restart_syscall();
|
|
|
|
|
|
|
|
if (!rtnl_trylock()) {
|
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
2009-05-14 01:01:51 +08:00
|
|
|
return restart_syscall();
|
2017-08-17 20:50:50 +08:00
|
|
|
}
|
2013-10-16 22:37:49 +08:00
|
|
|
|
2017-09-25 02:46:32 +08:00
|
|
|
if (!down_write_trylock(&ppriv->vlan_rwsem)) {
|
|
|
|
rtnl_unlock();
|
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
|
|
|
return restart_syscall();
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
|
2012-09-13 13:56:36 +08:00
|
|
|
if (priv->pkey == pkey &&
|
|
|
|
priv->child_type == IPOIB_LEGACY_CHILD) {
|
2005-04-17 06:20:36 +08:00
|
|
|
list_del(&priv->list);
|
2009-04-01 01:22:32 +08:00
|
|
|
dev = priv->dev;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-10-16 22:37:49 +08:00
|
|
|
up_write(&ppriv->vlan_rwsem);
|
|
|
|
|
2016-12-28 20:47:22 +08:00
|
|
|
if (dev) {
|
|
|
|
ipoib_dbg(ppriv, "delete child vlan %s\n", dev->name);
|
|
|
|
unregister_netdevice(dev);
|
|
|
|
}
|
|
|
|
|
2009-01-15 13:44:39 +08:00
|
|
|
rtnl_unlock();
|
2017-08-17 20:50:50 +08:00
|
|
|
mutex_unlock(&ppriv->sysfs_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-04-01 01:22:32 +08:00
|
|
|
if (dev) {
|
2017-09-25 02:46:33 +08:00
|
|
|
struct rdma_netdev *rn;
|
|
|
|
|
|
|
|
rn = netdev_priv(dev);
|
|
|
|
rn->free_rdma_netdev(priv->dev);
|
2017-06-14 14:59:05 +08:00
|
|
|
kfree(priv);
|
2009-04-01 01:22:32 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODEV;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|