diff options
author | Or Gerlitz <ogerlitz@mellanox.com> | 2012-09-13 01:56:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-20 16:49:17 -0400 |
commit | 9baa0b0364103dd726384c71db30b74044754743 (patch) | |
tree | 5e59fb1bab816eb57e55e6811a3c8642ac91d355 | |
parent | b85c715c2e6fabdd18c90df878ed2c6e6cd50fc2 (diff) |
IB/ipoib: Add rtnl_link_ops support
Add rtnl_link_ops to IPoIB, with the first usage being child device
create/delete through them. Childs devices are now either legacy ones,
created/deleted through the ipoib sysfs entries, or RTNL ones.
Adding support for RTNL childs involved refactoring of ipoib_vlan_add
which is now used by both the sysfs and the link_ops code.
Also, added ndo_uninit entry to support calling unregister_netdevice_queue
from the rtnl dellink entry. This required removal of calls to
ipoib_dev_cleanup from the driver in flows which use unregister_netdevice,
since the networking core will invoke ipoib_uninit which does exactly that.
Signed-off-by: Erez Shitrit <erezsh@mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/infiniband/ipoib.txt | 3 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/Makefile | 3 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 13 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 25 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 114 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 102 | ||||
-rw-r--r-- | include/linux/if_link.h | 11 |
7 files changed, 220 insertions, 51 deletions
diff --git a/Documentation/infiniband/ipoib.txt b/Documentation/infiniband/ipoib.txt index 64eeb55d0c09..f2cfe265e836 100644 --- a/Documentation/infiniband/ipoib.txt +++ b/Documentation/infiniband/ipoib.txt | |||
@@ -24,6 +24,9 @@ Partitions and P_Keys | |||
24 | The P_Key for any interface is given by the "pkey" file, and the | 24 | The P_Key for any interface is given by the "pkey" file, and the |
25 | main interface for a subinterface is in "parent." | 25 | main interface for a subinterface is in "parent." |
26 | 26 | ||
27 | Child interface create/delete can also be done using IPoIB's | ||
28 | rtnl_link_ops, where childs created using either way behave the same. | ||
29 | |||
27 | Datagram vs Connected modes | 30 | Datagram vs Connected modes |
28 | 31 | ||
29 | The IPoIB driver supports two modes of operation: datagram and | 32 | The IPoIB driver supports two modes of operation: datagram and |
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 | ||
9 | ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o | 10 | ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o |
10 | ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o | 11 | ib_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 ca43901ed861..381f51b2ed61 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) |
@@ -350,6 +354,7 @@ struct ipoib_dev_priv { | |||
350 | struct net_device *parent; | 354 | struct net_device *parent; |
351 | struct list_head child_intfs; | 355 | struct list_head child_intfs; |
352 | struct list_head list; | 356 | struct list_head list; |
357 | int child_type; | ||
353 | 358 | ||
354 | #ifdef CONFIG_INFINIBAND_IPOIB_CM | 359 | #ifdef CONFIG_INFINIBAND_IPOIB_CM |
355 | struct ipoib_cm_dev_priv cm; | 360 | struct ipoib_cm_dev_priv cm; |
@@ -509,6 +514,14 @@ void ipoib_event(struct ib_event_handler *handler, | |||
509 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); | 514 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); |
510 | int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); | 515 | int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); |
511 | 516 | ||
517 | int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, | ||
518 | u16 pkey, int child_type); | ||
519 | |||
520 | int __init ipoib_netlink_init(void); | ||
521 | void __exit ipoib_netlink_fini(void); | ||
522 | |||
523 | void ipoib_setup(struct net_device *dev); | ||
524 | |||
512 | void ipoib_pkey_poll(struct work_struct *work); | 525 | void ipoib_pkey_poll(struct work_struct *work); |
513 | int ipoib_pkey_dev_delay_open(struct net_device *dev); | 526 | int ipoib_pkey_dev_delay_open(struct net_device *dev); |
514 | void ipoib_drain_cq(struct net_device *dev); | 527 | void ipoib_drain_cq(struct net_device *dev); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 3e2085a3ee47..b3e97096c446 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 | ||
176 | static void ipoib_uninit(struct net_device *dev) | ||
177 | { | ||
178 | ipoib_dev_cleanup(dev); | ||
179 | } | ||
180 | |||
176 | static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features) | 181 | static 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); |
@@ -1262,6 +1267,9 @@ out: | |||
1262 | void ipoib_dev_cleanup(struct net_device *dev) | 1267 | void ipoib_dev_cleanup(struct net_device *dev) |
1263 | { | 1268 | { |
1264 | struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; | 1269 | struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; |
1270 | LIST_HEAD(head); | ||
1271 | |||
1272 | ASSERT_RTNL(); | ||
1265 | 1273 | ||
1266 | ipoib_delete_debug_files(dev); | 1274 | ipoib_delete_debug_files(dev); |
1267 | 1275 | ||
@@ -1270,10 +1278,9 @@ void ipoib_dev_cleanup(struct net_device *dev) | |||
1270 | /* Stop GC on child */ | 1278 | /* Stop GC on child */ |
1271 | set_bit(IPOIB_STOP_NEIGH_GC, &cpriv->flags); | 1279 | set_bit(IPOIB_STOP_NEIGH_GC, &cpriv->flags); |
1272 | cancel_delayed_work(&cpriv->neigh_reap_task); | 1280 | cancel_delayed_work(&cpriv->neigh_reap_task); |
1273 | unregister_netdev(cpriv->dev); | 1281 | unregister_netdevice_queue(cpriv->dev, &head); |
1274 | ipoib_dev_cleanup(cpriv->dev); | ||
1275 | free_netdev(cpriv->dev); | ||
1276 | } | 1282 | } |
1283 | unregister_netdevice_many(&head); | ||
1277 | 1284 | ||
1278 | ipoib_ib_dev_cleanup(dev); | 1285 | ipoib_ib_dev_cleanup(dev); |
1279 | 1286 | ||
@@ -1291,6 +1298,7 @@ static const struct header_ops ipoib_header_ops = { | |||
1291 | }; | 1298 | }; |
1292 | 1299 | ||
1293 | static const struct net_device_ops ipoib_netdev_ops = { | 1300 | static const struct net_device_ops ipoib_netdev_ops = { |
1301 | .ndo_uninit = ipoib_uninit, | ||
1294 | .ndo_open = ipoib_open, | 1302 | .ndo_open = ipoib_open, |
1295 | .ndo_stop = ipoib_stop, | 1303 | .ndo_stop = ipoib_stop, |
1296 | .ndo_change_mtu = ipoib_change_mtu, | 1304 | .ndo_change_mtu = ipoib_change_mtu, |
@@ -1300,7 +1308,7 @@ static const struct net_device_ops ipoib_netdev_ops = { | |||
1300 | .ndo_set_rx_mode = ipoib_set_mcast_list, | 1308 | .ndo_set_rx_mode = ipoib_set_mcast_list, |
1301 | }; | 1309 | }; |
1302 | 1310 | ||
1303 | static void ipoib_setup(struct net_device *dev) | 1311 | void ipoib_setup(struct net_device *dev) |
1304 | { | 1312 | { |
1305 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 1313 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
1306 | 1314 | ||
@@ -1662,7 +1670,6 @@ static void ipoib_remove_one(struct ib_device *device) | |||
1662 | flush_workqueue(ipoib_workqueue); | 1670 | flush_workqueue(ipoib_workqueue); |
1663 | 1671 | ||
1664 | unregister_netdev(priv->dev); | 1672 | unregister_netdev(priv->dev); |
1665 | ipoib_dev_cleanup(priv->dev); | ||
1666 | free_netdev(priv->dev); | 1673 | free_netdev(priv->dev); |
1667 | } | 1674 | } |
1668 | 1675 | ||
@@ -1714,8 +1721,15 @@ static int __init ipoib_init_module(void) | |||
1714 | if (ret) | 1721 | if (ret) |
1715 | goto err_sa; | 1722 | goto err_sa; |
1716 | 1723 | ||
1724 | ret = ipoib_netlink_init(); | ||
1725 | if (ret) | ||
1726 | goto err_client; | ||
1727 | |||
1717 | return 0; | 1728 | return 0; |
1718 | 1729 | ||
1730 | err_client: | ||
1731 | ib_unregister_client(&ipoib_client); | ||
1732 | |||
1719 | err_sa: | 1733 | err_sa: |
1720 | ib_sa_unregister_client(&ipoib_sa_client); | 1734 | ib_sa_unregister_client(&ipoib_sa_client); |
1721 | destroy_workqueue(ipoib_workqueue); | 1735 | destroy_workqueue(ipoib_workqueue); |
@@ -1728,6 +1742,7 @@ err_fs: | |||
1728 | 1742 | ||
1729 | static void __exit ipoib_cleanup_module(void) | 1743 | static void __exit ipoib_cleanup_module(void) |
1730 | { | 1744 | { |
1745 | ipoib_netlink_fini(); | ||
1731 | ib_unregister_client(&ipoib_client); | 1746 | ib_unregister_client(&ipoib_client); |
1732 | ib_sa_unregister_client(&ipoib_sa_client); | 1747 | ib_sa_unregister_client(&ipoib_sa_client); |
1733 | ipoib_unregister_debugfs(); | 1748 | 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..a7dc5ea8370e --- /dev/null +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c | |||
@@ -0,0 +1,114 @@ | |||
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 | |||
38 | static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = { | ||
39 | [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, | ||
40 | }; | ||
41 | |||
42 | static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, | ||
43 | struct nlattr *tb[], struct nlattr *data[]) | ||
44 | { | ||
45 | struct net_device *pdev; | ||
46 | struct ipoib_dev_priv *ppriv; | ||
47 | u16 child_pkey; | ||
48 | int err; | ||
49 | |||
50 | if (!tb[IFLA_LINK]) | ||
51 | return -EINVAL; | ||
52 | |||
53 | pdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); | ||
54 | if (!pdev) | ||
55 | return -ENODEV; | ||
56 | |||
57 | ppriv = netdev_priv(pdev); | ||
58 | |||
59 | if (test_bit(IPOIB_FLAG_SUBINTERFACE, &ppriv->flags)) { | ||
60 | ipoib_warn(ppriv, "child creation disallowed for child devices\n"); | ||
61 | return -EINVAL; | ||
62 | } | ||
63 | |||
64 | if (!data || !data[IFLA_IPOIB_PKEY]) { | ||
65 | ipoib_dbg(ppriv, "no pkey specified, using parent pkey\n"); | ||
66 | child_pkey = ppriv->pkey; | ||
67 | } else | ||
68 | child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]); | ||
69 | |||
70 | err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD); | ||
71 | |||
72 | return err; | ||
73 | } | ||
74 | |||
75 | static void ipoib_unregister_child_dev(struct net_device *dev, struct list_head *head) | ||
76 | { | ||
77 | struct ipoib_dev_priv *priv, *ppriv; | ||
78 | |||
79 | priv = netdev_priv(dev); | ||
80 | ppriv = netdev_priv(priv->parent); | ||
81 | |||
82 | mutex_lock(&ppriv->vlan_mutex); | ||
83 | unregister_netdevice_queue(dev, head); | ||
84 | list_del(&priv->list); | ||
85 | mutex_unlock(&ppriv->vlan_mutex); | ||
86 | } | ||
87 | |||
88 | static size_t ipoib_get_size(const struct net_device *dev) | ||
89 | { | ||
90 | return nla_total_size(2); /* IFLA_IPOIB_PKEY */ | ||
91 | } | ||
92 | |||
93 | static struct rtnl_link_ops ipoib_link_ops __read_mostly = { | ||
94 | .kind = "ipoib", | ||
95 | .maxtype = IFLA_IPOIB_MAX, | ||
96 | .policy = ipoib_policy, | ||
97 | .priv_size = sizeof(struct ipoib_dev_priv), | ||
98 | .setup = ipoib_setup, | ||
99 | .newlink = ipoib_new_child_link, | ||
100 | .dellink = ipoib_unregister_child_dev, | ||
101 | .get_size = ipoib_get_size, | ||
102 | }; | ||
103 | |||
104 | int __init ipoib_netlink_init(void) | ||
105 | { | ||
106 | return rtnl_link_register(&ipoib_link_ops); | ||
107 | } | ||
108 | |||
109 | void __exit ipoib_netlink_fini(void) | ||
110 | { | ||
111 | rtnl_link_unregister(&ipoib_link_ops); | ||
112 | } | ||
113 | |||
114 | MODULE_ALIAS_RTNL_LINK("ipoib"); | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index d7e9740c7248..238bbf9b2bea 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 | } |
50 | static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); | 50 | static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); |
51 | 51 | ||
52 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | 52 | int __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); |
@@ -134,14 +98,13 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | |||
134 | if (device_create_file(&priv->dev->dev, &dev_attr_parent)) | 98 | if (device_create_file(&priv->dev->dev, &dev_attr_parent)) |
135 | goto sysfs_failed; | 99 | goto sysfs_failed; |
136 | 100 | ||
101 | priv->child_type = type; | ||
137 | list_add_tail(&priv->list, &ppriv->child_intfs); | 102 | list_add_tail(&priv->list, &ppriv->child_intfs); |
138 | 103 | ||
139 | mutex_unlock(&ppriv->vlan_mutex); | ||
140 | rtnl_unlock(); | ||
141 | |||
142 | return 0; | 104 | return 0; |
143 | 105 | ||
144 | sysfs_failed: | 106 | sysfs_failed: |
107 | result = -ENOMEM; | ||
145 | ipoib_delete_debug_files(priv->dev); | 108 | ipoib_delete_debug_files(priv->dev); |
146 | unregister_netdevice(priv->dev); | 109 | unregister_netdevice(priv->dev); |
147 | 110 | ||
@@ -149,11 +112,60 @@ register_failed: | |||
149 | ipoib_dev_cleanup(priv->dev); | 112 | ipoib_dev_cleanup(priv->dev); |
150 | 113 | ||
151 | err: | 114 | err: |
115 | return result; | ||
116 | } | ||
117 | |||
118 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) | ||
119 | { | ||
120 | struct ipoib_dev_priv *ppriv, *priv; | ||
121 | char intf_name[IFNAMSIZ]; | ||
122 | struct ipoib_dev_priv *tpriv; | ||
123 | int result; | ||
124 | |||
125 | if (!capable(CAP_NET_ADMIN)) | ||
126 | return -EPERM; | ||
127 | |||
128 | ppriv = netdev_priv(pdev); | ||
129 | |||
130 | snprintf(intf_name, sizeof intf_name, "%s.%04x", | ||
131 | ppriv->dev->name, pkey); | ||
132 | priv = ipoib_intf_alloc(intf_name); | ||
133 | if (!priv) | ||
134 | return -ENOMEM; | ||
135 | |||
136 | if (!rtnl_trylock()) | ||
137 | return restart_syscall(); | ||
138 | |||
139 | mutex_lock(&ppriv->vlan_mutex); | ||
140 | |||
141 | /* | ||
142 | * First ensure this isn't a duplicate. We check the parent device and | ||
143 | * then all of the legacy child interfaces to make sure the Pkey | ||
144 | * doesn't match. | ||
145 | */ | ||
146 | if (ppriv->pkey == pkey) { | ||
147 | result = -ENOTUNIQ; | ||
148 | goto out; | ||
149 | } | ||
150 | |||
151 | list_for_each_entry(tpriv, &ppriv->child_intfs, list) { | ||
152 | if (tpriv->pkey == pkey && | ||
153 | tpriv->child_type == IPOIB_LEGACY_CHILD) { | ||
154 | result = -ENOTUNIQ; | ||
155 | goto out; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD); | ||
160 | |||
161 | out: | ||
152 | mutex_unlock(&ppriv->vlan_mutex); | 162 | mutex_unlock(&ppriv->vlan_mutex); |
153 | rtnl_unlock(); | 163 | |
154 | if (priv) | 164 | if (result) |
155 | free_netdev(priv->dev); | 165 | free_netdev(priv->dev); |
156 | 166 | ||
167 | rtnl_unlock(); | ||
168 | |||
157 | return result; | 169 | return result; |
158 | } | 170 | } |
159 | 171 | ||
@@ -171,9 +183,9 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) | |||
171 | return restart_syscall(); | 183 | return restart_syscall(); |
172 | mutex_lock(&ppriv->vlan_mutex); | 184 | mutex_lock(&ppriv->vlan_mutex); |
173 | list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { | 185 | list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { |
174 | if (priv->pkey == pkey) { | 186 | if (priv->pkey == pkey && |
187 | priv->child_type == IPOIB_LEGACY_CHILD) { | ||
175 | unregister_netdevice(priv->dev); | 188 | unregister_netdevice(priv->dev); |
176 | ipoib_dev_cleanup(priv->dev); | ||
177 | list_del(&priv->list); | 189 | list_del(&priv->list); |
178 | dev = priv->dev; | 190 | dev = priv->dev; |
179 | break; | 191 | break; |
diff --git a/include/linux/if_link.h b/include/linux/if_link.h index ac173bd2ab65..24c0dd09af54 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h | |||
@@ -398,4 +398,15 @@ struct ifla_port_vsi { | |||
398 | __u8 pad[3]; | 398 | __u8 pad[3]; |
399 | }; | 399 | }; |
400 | 400 | ||
401 | |||
402 | /* IPoIB section */ | ||
403 | |||
404 | enum { | ||
405 | IFLA_IPOIB_UNSPEC, | ||
406 | IFLA_IPOIB_PKEY, | ||
407 | __IFLA_IPOIB_MAX | ||
408 | }; | ||
409 | |||
410 | #define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) | ||
411 | |||
401 | #endif /* _LINUX_IF_LINK_H */ | 412 | #endif /* _LINUX_IF_LINK_H */ |