diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/Makefile | 3 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 16 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_cm.c | 34 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 41 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 172 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 124 |
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 | ||
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 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, | |||
512 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); | 517 | int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey); |
513 | int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); | 518 | int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey); |
514 | 519 | ||
520 | int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, | ||
521 | u16 pkey, int child_type); | ||
522 | |||
523 | int __init ipoib_netlink_init(void); | ||
524 | void __exit ipoib_netlink_fini(void); | ||
525 | |||
526 | void ipoib_set_umcast(struct net_device *ndev, int umcast_val); | ||
527 | int ipoib_set_mode(struct net_device *dev, const char *buf); | ||
528 | |||
529 | void ipoib_setup(struct net_device *dev); | ||
530 | |||
515 | void ipoib_pkey_poll(struct work_struct *work); | 531 | void ipoib_pkey_poll(struct work_struct *work); |
516 | int ipoib_pkey_dev_delay_open(struct net_device *dev); | 532 | int ipoib_pkey_dev_delay_open(struct net_device *dev); |
517 | void ipoib_drain_cq(struct net_device *dev); | 533 | void 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 | ||
1451 | static ssize_t set_mode(struct device *d, struct device_attribute *attr, | 1451 | int 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 | ||
1482 | static 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 | |||
1487 | static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); | 1501 | static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode); |
1488 | 1502 | ||
1489 | int ipoib_cm_add_mode_attr(struct net_device *dev) | 1503 | int 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 | ||
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); |
@@ -1257,6 +1262,9 @@ out: | |||
1257 | void ipoib_dev_cleanup(struct net_device *dev) | 1262 | void 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 | ||
1288 | static const struct net_device_ops ipoib_netdev_ops = { | 1295 | static 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 | ||
1298 | static void ipoib_setup(struct net_device *dev) | 1306 | void 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 | ||
1376 | static ssize_t set_umcast(struct device *dev, | 1384 | void 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 | |||
1396 | static 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 | ||
1731 | err_client: | ||
1732 | ib_unregister_client(&ipoib_client); | ||
1733 | |||
1714 | err_sa: | 1734 | err_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 | ||
1724 | static void __exit ipoib_cleanup_module(void) | 1744 | static 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 | |||
38 | static 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 | |||
44 | static 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 | |||
62 | nla_put_failure: | ||
63 | return -EMSGSIZE; | ||
64 | } | ||
65 | |||
66 | static 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 | |||
90 | out_err: | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static 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 | |||
129 | static 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 | |||
142 | static 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 | |||
149 | static 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 | |||
162 | int __init ipoib_netlink_init(void) | ||
163 | { | ||
164 | return rtnl_link_register(&ipoib_link_ops); | ||
165 | } | ||
166 | |||
167 | void __exit ipoib_netlink_fini(void) | ||
168 | { | ||
169 | rtnl_link_unregister(&ipoib_link_ops); | ||
170 | } | ||
171 | |||
172 | 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..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 | } |
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); |
@@ -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 | ||
144 | sysfs_failed: | 110 | sysfs_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 | ||
151 | err: | 118 | err: |
119 | return result; | ||
120 | } | ||
121 | |||
122 | int 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 | |||
165 | out: | ||
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; |