aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/ipoib
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/ulp/ipoib')
-rw-r--r--drivers/infiniband/ulp/ipoib/Makefile3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h16
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c34
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c41
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_netlink.c172
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c124
6 files changed, 315 insertions, 75 deletions
diff --git a/drivers/infiniband/ulp/ipoib/Makefile b/drivers/infiniband/ulp/ipoib/Makefile
index 3090100f0de7..e5430dd50764 100644
--- a/drivers/infiniband/ulp/ipoib/Makefile
+++ b/drivers/infiniband/ulp/ipoib/Makefile
@@ -5,7 +5,8 @@ ib_ipoib-y := ipoib_main.o \
5 ipoib_multicast.o \ 5 ipoib_multicast.o \
6 ipoib_verbs.o \ 6 ipoib_verbs.o \
7 ipoib_vlan.o \ 7 ipoib_vlan.o \
8 ipoib_ethtool.o 8 ipoib_ethtool.o \
9 ipoib_netlink.o
9ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o 10ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o
10ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o 11ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o
11 12
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 0af216d21f87..196eb52f0035 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -104,6 +104,10 @@ enum {
104 104
105 MAX_SEND_CQE = 16, 105 MAX_SEND_CQE = 16,
106 IPOIB_CM_COPYBREAK = 256, 106 IPOIB_CM_COPYBREAK = 256,
107
108 IPOIB_NON_CHILD = 0,
109 IPOIB_LEGACY_CHILD = 1,
110 IPOIB_RTNL_CHILD = 2,
107}; 111};
108 112
109#define IPOIB_OP_RECV (1ul << 31) 113#define IPOIB_OP_RECV (1ul << 31)
@@ -353,6 +357,7 @@ struct ipoib_dev_priv {
353 struct net_device *parent; 357 struct net_device *parent;
354 struct list_head child_intfs; 358 struct list_head child_intfs;
355 struct list_head list; 359 struct list_head list;
360 int child_type;
356 361
357#ifdef CONFIG_INFINIBAND_IPOIB_CM 362#ifdef CONFIG_INFINIBAND_IPOIB_CM
358 struct ipoib_cm_dev_priv cm; 363 struct ipoib_cm_dev_priv cm;
@@ -512,6 +517,17 @@ void ipoib_event(struct ib_event_handler *handler,
512int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); 517int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey);
513int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); 518int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey);
514 519
520int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
521 u16 pkey, int child_type);
522
523int __init ipoib_netlink_init(void);
524void __exit ipoib_netlink_fini(void);
525
526void ipoib_set_umcast(struct net_device *ndev, int umcast_val);
527int ipoib_set_mode(struct net_device *dev, const char *buf);
528
529void ipoib_setup(struct net_device *dev);
530
515void ipoib_pkey_poll(struct work_struct *work); 531void ipoib_pkey_poll(struct work_struct *work);
516int ipoib_pkey_dev_delay_open(struct net_device *dev); 532int ipoib_pkey_dev_delay_open(struct net_device *dev);
517void ipoib_drain_cq(struct net_device *dev); 533void ipoib_drain_cq(struct net_device *dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 24683fda8e21..175581cf478c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1448,15 +1448,10 @@ static ssize_t show_mode(struct device *d, struct device_attribute *attr,
1448 return sprintf(buf, "datagram\n"); 1448 return sprintf(buf, "datagram\n");
1449} 1449}
1450 1450
1451static ssize_t set_mode(struct device *d, struct device_attribute *attr, 1451int ipoib_set_mode(struct net_device *dev, const char *buf)
1452 const char *buf, size_t count)
1453{ 1452{
1454 struct net_device *dev = to_net_dev(d);
1455 struct ipoib_dev_priv *priv = netdev_priv(dev); 1453 struct ipoib_dev_priv *priv = netdev_priv(dev);
1456 1454
1457 if (!rtnl_trylock())
1458 return restart_syscall();
1459
1460 /* flush paths if we switch modes so that connections are restarted */ 1455 /* flush paths if we switch modes so that connections are restarted */
1461 if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { 1456 if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) {
1462 set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 1457 set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
@@ -1467,7 +1462,8 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
1467 priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; 1462 priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
1468 1463
1469 ipoib_flush_paths(dev); 1464 ipoib_flush_paths(dev);
1470 return count; 1465 rtnl_lock();
1466 return 0;
1471 } 1467 }
1472 1468
1473 if (!strcmp(buf, "datagram\n")) { 1469 if (!strcmp(buf, "datagram\n")) {
@@ -1476,14 +1472,32 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
1476 dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); 1472 dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu));
1477 rtnl_unlock(); 1473 rtnl_unlock();
1478 ipoib_flush_paths(dev); 1474 ipoib_flush_paths(dev);
1479 1475 rtnl_lock();
1480 return count; 1476 return 0;
1481 } 1477 }
1482 rtnl_unlock();
1483 1478
1484 return -EINVAL; 1479 return -EINVAL;
1485} 1480}
1486 1481
1482static ssize_t set_mode(struct device *d, struct device_attribute *attr,
1483 const char *buf, size_t count)
1484{
1485 struct net_device *dev = to_net_dev(d);
1486 int ret;
1487
1488 if (!rtnl_trylock())
1489 return restart_syscall();
1490
1491 ret = ipoib_set_mode(dev, buf);
1492
1493 rtnl_unlock();
1494
1495 if (!ret)
1496 return count;
1497
1498 return ret;
1499}
1500
1487static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); 1501static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
1488 1502
1489int ipoib_cm_add_mode_attr(struct net_device *dev) 1503int ipoib_cm_add_mode_attr(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 1e19b5ae7c47..3f9a9ba2f9ec 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -173,6 +173,11 @@ static int ipoib_stop(struct net_device *dev)
173 return 0; 173 return 0;
174} 174}
175 175
176static void ipoib_uninit(struct net_device *dev)
177{
178 ipoib_dev_cleanup(dev);
179}
180
176static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features) 181static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features)
177{ 182{
178 struct ipoib_dev_priv *priv = netdev_priv(dev); 183 struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -1257,6 +1262,9 @@ out:
1257void ipoib_dev_cleanup(struct net_device *dev) 1262void ipoib_dev_cleanup(struct net_device *dev)
1258{ 1263{
1259 struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; 1264 struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv;
1265 LIST_HEAD(head);
1266
1267 ASSERT_RTNL();
1260 1268
1261 ipoib_delete_debug_files(dev); 1269 ipoib_delete_debug_files(dev);
1262 1270
@@ -1265,10 +1273,9 @@ void ipoib_dev_cleanup(struct net_device *dev)
1265 /* Stop GC on child */ 1273 /* Stop GC on child */
1266 set_bit(IPOIB_STOP_NEIGH_GC, &cpriv->flags); 1274 set_bit(IPOIB_STOP_NEIGH_GC, &cpriv->flags);
1267 cancel_delayed_work(&cpriv->neigh_reap_task); 1275 cancel_delayed_work(&cpriv->neigh_reap_task);
1268 unregister_netdev(cpriv->dev); 1276 unregister_netdevice_queue(cpriv->dev, &head);
1269 ipoib_dev_cleanup(cpriv->dev);
1270 free_netdev(cpriv->dev);
1271 } 1277 }
1278 unregister_netdevice_many(&head);
1272 1279
1273 ipoib_ib_dev_cleanup(dev); 1280 ipoib_ib_dev_cleanup(dev);
1274 1281
@@ -1286,6 +1293,7 @@ static const struct header_ops ipoib_header_ops = {
1286}; 1293};
1287 1294
1288static const struct net_device_ops ipoib_netdev_ops = { 1295static const struct net_device_ops ipoib_netdev_ops = {
1296 .ndo_uninit = ipoib_uninit,
1289 .ndo_open = ipoib_open, 1297 .ndo_open = ipoib_open,
1290 .ndo_stop = ipoib_stop, 1298 .ndo_stop = ipoib_stop,
1291 .ndo_change_mtu = ipoib_change_mtu, 1299 .ndo_change_mtu = ipoib_change_mtu,
@@ -1295,7 +1303,7 @@ static const struct net_device_ops ipoib_netdev_ops = {
1295 .ndo_set_rx_mode = ipoib_set_mcast_list, 1303 .ndo_set_rx_mode = ipoib_set_mcast_list,
1296}; 1304};
1297 1305
1298static void ipoib_setup(struct net_device *dev) 1306void ipoib_setup(struct net_device *dev)
1299{ 1307{
1300 struct ipoib_dev_priv *priv = netdev_priv(dev); 1308 struct ipoib_dev_priv *priv = netdev_priv(dev);
1301 1309
@@ -1373,12 +1381,9 @@ static ssize_t show_umcast(struct device *dev,
1373 return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); 1381 return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags));
1374} 1382}
1375 1383
1376static ssize_t set_umcast(struct device *dev, 1384void ipoib_set_umcast(struct net_device *ndev, int umcast_val)
1377 struct device_attribute *attr,
1378 const char *buf, size_t count)
1379{ 1385{
1380 struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 1386 struct ipoib_dev_priv *priv = netdev_priv(ndev);
1381 unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
1382 1387
1383 if (umcast_val > 0) { 1388 if (umcast_val > 0) {
1384 set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1389 set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
@@ -1386,6 +1391,15 @@ static ssize_t set_umcast(struct device *dev,
1386 "by userspace\n"); 1391 "by userspace\n");
1387 } else 1392 } else
1388 clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1393 clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
1394}
1395
1396static ssize_t set_umcast(struct device *dev,
1397 struct device_attribute *attr,
1398 const char *buf, size_t count)
1399{
1400 unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
1401
1402 ipoib_set_umcast(to_net_dev(dev), umcast_val);
1389 1403
1390 return count; 1404 return count;
1391} 1405}
@@ -1657,7 +1671,6 @@ static void ipoib_remove_one(struct ib_device *device)
1657 flush_workqueue(ipoib_workqueue); 1671 flush_workqueue(ipoib_workqueue);
1658 1672
1659 unregister_netdev(priv->dev); 1673 unregister_netdev(priv->dev);
1660 ipoib_dev_cleanup(priv->dev);
1661 free_netdev(priv->dev); 1674 free_netdev(priv->dev);
1662 } 1675 }
1663 1676
@@ -1709,8 +1722,15 @@ static int __init ipoib_init_module(void)
1709 if (ret) 1722 if (ret)
1710 goto err_sa; 1723 goto err_sa;
1711 1724
1725 ret = ipoib_netlink_init();
1726 if (ret)
1727 goto err_client;
1728
1712 return 0; 1729 return 0;
1713 1730
1731err_client:
1732 ib_unregister_client(&ipoib_client);
1733
1714err_sa: 1734err_sa:
1715 ib_sa_unregister_client(&ipoib_sa_client); 1735 ib_sa_unregister_client(&ipoib_sa_client);
1716 destroy_workqueue(ipoib_workqueue); 1736 destroy_workqueue(ipoib_workqueue);
@@ -1723,6 +1743,7 @@ err_fs:
1723 1743
1724static void __exit ipoib_cleanup_module(void) 1744static void __exit ipoib_cleanup_module(void)
1725{ 1745{
1746 ipoib_netlink_fini();
1726 ib_unregister_client(&ipoib_client); 1747 ib_unregister_client(&ipoib_client);
1727 ib_sa_unregister_client(&ipoib_sa_client); 1748 ib_sa_unregister_client(&ipoib_sa_client);
1728 ipoib_unregister_debugfs(); 1749 ipoib_unregister_debugfs();
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
new file mode 100644
index 000000000000..74685936c948
--- /dev/null
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -0,0 +1,172 @@
1/*
2 * Copyright (c) 2012 Mellanox Technologies. - 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/netdevice.h>
34#include <linux/module.h>
35#include <net/rtnetlink.h>
36#include "ipoib.h"
37
38static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = {
39 [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
40 [IFLA_IPOIB_MODE] = { .type = NLA_U16 },
41 [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
42};
43
44static int ipoib_fill_info(struct sk_buff *skb, const struct net_device *dev)
45{
46 struct ipoib_dev_priv *priv = netdev_priv(dev);
47 u16 val;
48
49 if (nla_put_u16(skb, IFLA_IPOIB_PKEY, priv->pkey))
50 goto nla_put_failure;
51
52 val = test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
53 if (nla_put_u16(skb, IFLA_IPOIB_MODE, val))
54 goto nla_put_failure;
55
56 val = test_bit(IPOIB_FLAG_UMCAST, &priv->flags);
57 if (nla_put_u16(skb, IFLA_IPOIB_UMCAST, val))
58 goto nla_put_failure;
59
60 return 0;
61
62nla_put_failure:
63 return -EMSGSIZE;
64}
65
66static int ipoib_changelink(struct net_device *dev,
67 struct nlattr *tb[], struct nlattr *data[])
68{
69 u16 mode, umcast;
70 int ret = 0;
71
72 if (data[IFLA_IPOIB_MODE]) {
73 mode = nla_get_u16(data[IFLA_IPOIB_MODE]);
74 if (mode == IPOIB_MODE_DATAGRAM)
75 ret = ipoib_set_mode(dev, "datagram\n");
76 else if (mode == IPOIB_MODE_CONNECTED)
77 ret = ipoib_set_mode(dev, "connected\n");
78 else
79 ret = -EINVAL;
80
81 if (ret < 0)
82 goto out_err;
83 }
84
85 if (data[IFLA_IPOIB_UMCAST]) {
86 umcast = nla_get_u16(data[IFLA_IPOIB_UMCAST]);
87 ipoib_set_umcast(dev, umcast);
88 }
89
90out_err:
91 return ret;
92}
93
94static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
95 struct nlattr *tb[], struct nlattr *data[])
96{
97 struct net_device *pdev;
98 struct ipoib_dev_priv *ppriv;
99 u16 child_pkey;
100 int err;
101
102 if (!tb[IFLA_LINK])
103 return -EINVAL;
104
105 pdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
106 if (!pdev)
107 return -ENODEV;
108
109 ppriv = netdev_priv(pdev);
110
111 if (test_bit(IPOIB_FLAG_SUBINTERFACE, &ppriv->flags)) {
112 ipoib_warn(ppriv, "child creation disallowed for child devices\n");
113 return -EINVAL;
114 }
115
116 if (!data || !data[IFLA_IPOIB_PKEY]) {
117 ipoib_dbg(ppriv, "no pkey specified, using parent pkey\n");
118 child_pkey = ppriv->pkey;
119 } else
120 child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]);
121
122 err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
123
124 if (!err && data)
125 err = ipoib_changelink(dev, tb, data);
126 return err;
127}
128
129static void ipoib_unregister_child_dev(struct net_device *dev, struct list_head *head)
130{
131 struct ipoib_dev_priv *priv, *ppriv;
132
133 priv = netdev_priv(dev);
134 ppriv = netdev_priv(priv->parent);
135
136 mutex_lock(&ppriv->vlan_mutex);
137 unregister_netdevice_queue(dev, head);
138 list_del(&priv->list);
139 mutex_unlock(&ppriv->vlan_mutex);
140}
141
142static size_t ipoib_get_size(const struct net_device *dev)
143{
144 return nla_total_size(2) + /* IFLA_IPOIB_PKEY */
145 nla_total_size(2) + /* IFLA_IPOIB_MODE */
146 nla_total_size(2); /* IFLA_IPOIB_UMCAST */
147}
148
149static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
150 .kind = "ipoib",
151 .maxtype = IFLA_IPOIB_MAX,
152 .policy = ipoib_policy,
153 .priv_size = sizeof(struct ipoib_dev_priv),
154 .setup = ipoib_setup,
155 .newlink = ipoib_new_child_link,
156 .changelink = ipoib_changelink,
157 .dellink = ipoib_unregister_child_dev,
158 .get_size = ipoib_get_size,
159 .fill_info = ipoib_fill_info,
160};
161
162int __init ipoib_netlink_init(void)
163{
164 return rtnl_link_register(&ipoib_link_ops);
165}
166
167void __exit ipoib_netlink_fini(void)
168{
169 rtnl_link_unregister(&ipoib_link_ops);
170}
171
172MODULE_ALIAS_RTNL_LINK("ipoib");
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index d7e9740c7248..8292554bccb5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -49,47 +49,11 @@ static ssize_t show_parent(struct device *d, struct device_attribute *attr,
49} 49}
50static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); 50static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
51 51
52int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) 52int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
53 u16 pkey, int type)
53{ 54{
54 struct ipoib_dev_priv *ppriv, *priv;
55 char intf_name[IFNAMSIZ];
56 int result; 55 int result;
57 56
58 if (!capable(CAP_NET_ADMIN))
59 return -EPERM;
60
61 ppriv = netdev_priv(pdev);
62
63 if (!rtnl_trylock())
64 return restart_syscall();
65 mutex_lock(&ppriv->vlan_mutex);
66
67 /*
68 * First ensure this isn't a duplicate. We check the parent device and
69 * then all of the child interfaces to make sure the Pkey doesn't match.
70 */
71 if (ppriv->pkey == pkey) {
72 result = -ENOTUNIQ;
73 priv = NULL;
74 goto err;
75 }
76
77 list_for_each_entry(priv, &ppriv->child_intfs, list) {
78 if (priv->pkey == pkey) {
79 result = -ENOTUNIQ;
80 priv = NULL;
81 goto err;
82 }
83 }
84
85 snprintf(intf_name, sizeof intf_name, "%s.%04x",
86 ppriv->dev->name, pkey);
87 priv = ipoib_intf_alloc(intf_name);
88 if (!priv) {
89 result = -ENOMEM;
90 goto err;
91 }
92
93 priv->max_ib_mtu = ppriv->max_ib_mtu; 57 priv->max_ib_mtu = ppriv->max_ib_mtu;
94 /* MTU will be reset when mcast join happens */ 58 /* MTU will be reset when mcast join happens */
95 priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 59 priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
@@ -124,24 +88,27 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
124 88
125 ipoib_create_debug_files(priv->dev); 89 ipoib_create_debug_files(priv->dev);
126 90
127 if (ipoib_cm_add_mode_attr(priv->dev)) 91 /* RTNL childs don't need proprietary sysfs entries */
128 goto sysfs_failed; 92 if (type == IPOIB_LEGACY_CHILD) {
129 if (ipoib_add_pkey_attr(priv->dev)) 93 if (ipoib_cm_add_mode_attr(priv->dev))
130 goto sysfs_failed; 94 goto sysfs_failed;
131 if (ipoib_add_umcast_attr(priv->dev)) 95 if (ipoib_add_pkey_attr(priv->dev))
132 goto sysfs_failed; 96 goto sysfs_failed;
133 97 if (ipoib_add_umcast_attr(priv->dev))
134 if (device_create_file(&priv->dev->dev, &dev_attr_parent)) 98 goto sysfs_failed;
135 goto sysfs_failed; 99
100 if (device_create_file(&priv->dev->dev, &dev_attr_parent))
101 goto sysfs_failed;
102 }
136 103
104 priv->child_type = type;
105 priv->dev->iflink = ppriv->dev->ifindex;
137 list_add_tail(&priv->list, &ppriv->child_intfs); 106 list_add_tail(&priv->list, &ppriv->child_intfs);
138 107
139 mutex_unlock(&ppriv->vlan_mutex);
140 rtnl_unlock();
141
142 return 0; 108 return 0;
143 109
144sysfs_failed: 110sysfs_failed:
111 result = -ENOMEM;
145 ipoib_delete_debug_files(priv->dev); 112 ipoib_delete_debug_files(priv->dev);
146 unregister_netdevice(priv->dev); 113 unregister_netdevice(priv->dev);
147 114
@@ -149,11 +116,60 @@ register_failed:
149 ipoib_dev_cleanup(priv->dev); 116 ipoib_dev_cleanup(priv->dev);
150 117
151err: 118err:
119 return result;
120}
121
122int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
123{
124 struct ipoib_dev_priv *ppriv, *priv;
125 char intf_name[IFNAMSIZ];
126 struct ipoib_dev_priv *tpriv;
127 int result;
128
129 if (!capable(CAP_NET_ADMIN))
130 return -EPERM;
131
132 ppriv = netdev_priv(pdev);
133
134 snprintf(intf_name, sizeof intf_name, "%s.%04x",
135 ppriv->dev->name, pkey);
136 priv = ipoib_intf_alloc(intf_name);
137 if (!priv)
138 return -ENOMEM;
139
140 if (!rtnl_trylock())
141 return restart_syscall();
142
143 mutex_lock(&ppriv->vlan_mutex);
144
145 /*
146 * First ensure this isn't a duplicate. We check the parent device and
147 * then all of the legacy child interfaces to make sure the Pkey
148 * doesn't match.
149 */
150 if (ppriv->pkey == pkey) {
151 result = -ENOTUNIQ;
152 goto out;
153 }
154
155 list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
156 if (tpriv->pkey == pkey &&
157 tpriv->child_type == IPOIB_LEGACY_CHILD) {
158 result = -ENOTUNIQ;
159 goto out;
160 }
161 }
162
163 result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
164
165out:
152 mutex_unlock(&ppriv->vlan_mutex); 166 mutex_unlock(&ppriv->vlan_mutex);
153 rtnl_unlock(); 167
154 if (priv) 168 if (result)
155 free_netdev(priv->dev); 169 free_netdev(priv->dev);
156 170
171 rtnl_unlock();
172
157 return result; 173 return result;
158} 174}
159 175
@@ -171,9 +187,9 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
171 return restart_syscall(); 187 return restart_syscall();
172 mutex_lock(&ppriv->vlan_mutex); 188 mutex_lock(&ppriv->vlan_mutex);
173 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { 189 list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
174 if (priv->pkey == pkey) { 190 if (priv->pkey == pkey &&
191 priv->child_type == IPOIB_LEGACY_CHILD) {
175 unregister_netdevice(priv->dev); 192 unregister_netdevice(priv->dev);
176 ipoib_dev_cleanup(priv->dev);
177 list_del(&priv->list); 193 list_del(&priv->list);
178 dev = priv->dev; 194 dev = priv->dev;
179 break; 195 break;