aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorOr Gerlitz <ogerlitz@mellanox.com>2012-09-27 08:06:02 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-01 17:12:22 -0400
commit862096a8bbf8f992f6d0a1a8786ffd3fc7437e48 (patch)
tree6126e2ac9400db959b1a9c075092565401d91db5 /drivers/infiniband
parentd7559982701ac500662b2e8e150ff34f7faf0281 (diff)
IB/ipoib: Add more rtnl_link_ops callbacks
Add the rtnl_link_ops changelink and fill_info callbacks, through which the admin can now set/get the driver mode, etc policies. Maintain the proprietary sysfs entries only for legacy childs. For child devices, set dev->iflink to point to the parent device ifindex, such that user space tools can now correctly show the uplink relation as done for vlan, macvlan, etc devices. Pointed out by Patrick McHardy <kaber@trash.net> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c34
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c16
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_netlink.c60
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c24
5 files changed, 111 insertions, 26 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index ac48f86f2384..196eb52f0035 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -523,6 +523,9 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
523int __init ipoib_netlink_init(void); 523int __init ipoib_netlink_init(void);
524void __exit ipoib_netlink_fini(void); 524void __exit ipoib_netlink_fini(void);
525 525
526void ipoib_set_umcast(struct net_device *ndev, int umcast_val);
527int ipoib_set_mode(struct net_device *dev, const char *buf);
528
526void ipoib_setup(struct net_device *dev); 529void ipoib_setup(struct net_device *dev);
527 530
528void ipoib_pkey_poll(struct work_struct *work); 531void ipoib_pkey_poll(struct work_struct *work);
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 128fab102054..3f9a9ba2f9ec 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1381,12 +1381,9 @@ static ssize_t show_umcast(struct device *dev,
1381 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));
1382} 1382}
1383 1383
1384static ssize_t set_umcast(struct device *dev, 1384void ipoib_set_umcast(struct net_device *ndev, int umcast_val)
1385 struct device_attribute *attr,
1386 const char *buf, size_t count)
1387{ 1385{
1388 struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 1386 struct ipoib_dev_priv *priv = netdev_priv(ndev);
1389 unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
1390 1387
1391 if (umcast_val > 0) { 1388 if (umcast_val > 0) {
1392 set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1389 set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
@@ -1394,6 +1391,15 @@ static ssize_t set_umcast(struct device *dev,
1394 "by userspace\n"); 1391 "by userspace\n");
1395 } else 1392 } else
1396 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);
1397 1403
1398 return count; 1404 return count;
1399} 1405}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
index a7dc5ea8370e..74685936c948 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -37,8 +37,60 @@
37 37
38static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = { 38static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = {
39 [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, 39 [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
40 [IFLA_IPOIB_MODE] = { .type = NLA_U16 },
41 [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
40}; 42};
41 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
42static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, 94static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
43 struct nlattr *tb[], struct nlattr *data[]) 95 struct nlattr *tb[], struct nlattr *data[])
44{ 96{
@@ -69,6 +121,8 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
69 121
70 err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD); 122 err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
71 123
124 if (!err && data)
125 err = ipoib_changelink(dev, tb, data);
72 return err; 126 return err;
73} 127}
74 128
@@ -87,7 +141,9 @@ static void ipoib_unregister_child_dev(struct net_device *dev, struct list_head
87 141
88static size_t ipoib_get_size(const struct net_device *dev) 142static size_t ipoib_get_size(const struct net_device *dev)
89{ 143{
90 return nla_total_size(2); /* IFLA_IPOIB_PKEY */ 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 */
91} 147}
92 148
93static struct rtnl_link_ops ipoib_link_ops __read_mostly = { 149static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
@@ -97,8 +153,10 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
97 .priv_size = sizeof(struct ipoib_dev_priv), 153 .priv_size = sizeof(struct ipoib_dev_priv),
98 .setup = ipoib_setup, 154 .setup = ipoib_setup,
99 .newlink = ipoib_new_child_link, 155 .newlink = ipoib_new_child_link,
156 .changelink = ipoib_changelink,
100 .dellink = ipoib_unregister_child_dev, 157 .dellink = ipoib_unregister_child_dev,
101 .get_size = ipoib_get_size, 158 .get_size = ipoib_get_size,
159 .fill_info = ipoib_fill_info,
102}; 160};
103 161
104int __init ipoib_netlink_init(void) 162int __init ipoib_netlink_init(void)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 238bbf9b2bea..8292554bccb5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -88,17 +88,21 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
88 88
89 ipoib_create_debug_files(priv->dev); 89 ipoib_create_debug_files(priv->dev);
90 90
91 if (ipoib_cm_add_mode_attr(priv->dev)) 91 /* RTNL childs don't need proprietary sysfs entries */
92 goto sysfs_failed; 92 if (type == IPOIB_LEGACY_CHILD) {
93 if (ipoib_add_pkey_attr(priv->dev)) 93 if (ipoib_cm_add_mode_attr(priv->dev))
94 goto sysfs_failed; 94 goto sysfs_failed;
95 if (ipoib_add_umcast_attr(priv->dev)) 95 if (ipoib_add_pkey_attr(priv->dev))
96 goto sysfs_failed; 96 goto sysfs_failed;
97 97 if (ipoib_add_umcast_attr(priv->dev))
98 if (device_create_file(&priv->dev->dev, &dev_attr_parent)) 98 goto sysfs_failed;
99 goto sysfs_failed; 99
100 if (device_create_file(&priv->dev->dev, &dev_attr_parent))
101 goto sysfs_failed;
102 }
100 103
101 priv->child_type = type; 104 priv->child_type = type;
105 priv->dev->iflink = ppriv->dev->ifindex;
102 list_add_tail(&priv->list, &ppriv->child_intfs); 106 list_add_tail(&priv->list, &ppriv->child_intfs);
103 107
104 return 0; 108 return 0;