aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOr Gerlitz <ogerlitz@mellanox.com>2012-09-13 01:56:36 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-20 16:49:17 -0400
commit9baa0b0364103dd726384c71db30b74044754743 (patch)
tree5e59fb1bab816eb57e55e6811a3c8642ac91d355
parentb85c715c2e6fabdd18c90df878ed2c6e6cd50fc2 (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.txt3
-rw-r--r--drivers/infiniband/ulp/ipoib/Makefile3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h13
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c25
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_netlink.c114
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c102
-rw-r--r--include/linux/if_link.h11
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
27Datagram vs Connected modes 30Datagram 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
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 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,
509int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); 514int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey);
510int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); 515int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey);
511 516
517int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
518 u16 pkey, int child_type);
519
520int __init ipoib_netlink_init(void);
521void __exit ipoib_netlink_fini(void);
522
523void ipoib_setup(struct net_device *dev);
524
512void ipoib_pkey_poll(struct work_struct *work); 525void ipoib_pkey_poll(struct work_struct *work);
513int ipoib_pkey_dev_delay_open(struct net_device *dev); 526int ipoib_pkey_dev_delay_open(struct net_device *dev);
514void ipoib_drain_cq(struct net_device *dev); 527void 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
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);
@@ -1262,6 +1267,9 @@ out:
1262void ipoib_dev_cleanup(struct net_device *dev) 1267void 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
1293static const struct net_device_ops ipoib_netdev_ops = { 1300static 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
1303static void ipoib_setup(struct net_device *dev) 1311void 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
1730err_client:
1731 ib_unregister_client(&ipoib_client);
1732
1719err_sa: 1733err_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
1729static void __exit ipoib_cleanup_module(void) 1743static 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
38static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = {
39 [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
40};
41
42static 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
75static 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
88static size_t ipoib_get_size(const struct net_device *dev)
89{
90 return nla_total_size(2); /* IFLA_IPOIB_PKEY */
91}
92
93static 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
104int __init ipoib_netlink_init(void)
105{
106 return rtnl_link_register(&ipoib_link_ops);
107}
108
109void __exit ipoib_netlink_fini(void)
110{
111 rtnl_link_unregister(&ipoib_link_ops);
112}
113
114MODULE_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}
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);
@@ -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
144sysfs_failed: 106sysfs_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
151err: 114err:
115 return result;
116}
117
118int 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
161out:
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
404enum {
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 */