xref: /openbmc/linux/drivers/infiniband/ulp/ipoib/ipoib_netlink.c (revision cd565b4b51e5fe258d6ce9ddc167ee51f3044ba5)
19baa0b03SOr Gerlitz /*
29baa0b03SOr Gerlitz  * Copyright (c) 2012 Mellanox Technologies. -  All rights reserved.
39baa0b03SOr Gerlitz  *
49baa0b03SOr Gerlitz  * This software is available to you under a choice of one of two
59baa0b03SOr Gerlitz  * licenses.  You may choose to be licensed under the terms of the GNU
69baa0b03SOr Gerlitz  * General Public License (GPL) Version 2, available from the file
79baa0b03SOr Gerlitz  * COPYING in the main directory of this source tree, or the
89baa0b03SOr Gerlitz  * OpenIB.org BSD license below:
99baa0b03SOr Gerlitz  *
109baa0b03SOr Gerlitz  *     Redistribution and use in source and binary forms, with or
119baa0b03SOr Gerlitz  *     without modification, are permitted provided that the following
129baa0b03SOr Gerlitz  *     conditions are met:
139baa0b03SOr Gerlitz  *
149baa0b03SOr Gerlitz  *      - Redistributions of source code must retain the above
159baa0b03SOr Gerlitz  *        copyright notice, this list of conditions and the following
169baa0b03SOr Gerlitz  *        disclaimer.
179baa0b03SOr Gerlitz  *
189baa0b03SOr Gerlitz  *      - Redistributions in binary form must reproduce the above
199baa0b03SOr Gerlitz  *        copyright notice, this list of conditions and the following
209baa0b03SOr Gerlitz  *        disclaimer in the documentation and/or other materials
219baa0b03SOr Gerlitz  *        provided with the distribution.
229baa0b03SOr Gerlitz  *
239baa0b03SOr Gerlitz  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
249baa0b03SOr Gerlitz  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
259baa0b03SOr Gerlitz  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
269baa0b03SOr Gerlitz  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
279baa0b03SOr Gerlitz  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
289baa0b03SOr Gerlitz  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
299baa0b03SOr Gerlitz  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
309baa0b03SOr Gerlitz  * SOFTWARE.
319baa0b03SOr Gerlitz  */
329baa0b03SOr Gerlitz 
339baa0b03SOr Gerlitz #include <linux/netdevice.h>
340d68fc4fSHangbin Liu #include <linux/if_arp.h>      /* For ARPHRD_xxx */
359baa0b03SOr Gerlitz #include <linux/module.h>
369baa0b03SOr Gerlitz #include <net/rtnetlink.h>
379baa0b03SOr Gerlitz #include "ipoib.h"
389baa0b03SOr Gerlitz 
399baa0b03SOr Gerlitz static const struct nla_policy ipoib_policy[IFLA_IPOIB_MAX + 1] = {
409baa0b03SOr Gerlitz 	[IFLA_IPOIB_PKEY]	= { .type = NLA_U16 },
41862096a8SOr Gerlitz 	[IFLA_IPOIB_MODE]	= { .type = NLA_U16 },
42862096a8SOr Gerlitz 	[IFLA_IPOIB_UMCAST]	= { .type = NLA_U16 },
439baa0b03SOr Gerlitz };
449baa0b03SOr Gerlitz 
45862096a8SOr Gerlitz static int ipoib_fill_info(struct sk_buff *skb, const struct net_device *dev)
46862096a8SOr Gerlitz {
47c1048affSErez Shitrit 	struct ipoib_dev_priv *priv = ipoib_priv(dev);
48862096a8SOr Gerlitz 	u16 val;
49862096a8SOr Gerlitz 
50862096a8SOr Gerlitz 	if (nla_put_u16(skb, IFLA_IPOIB_PKEY, priv->pkey))
51862096a8SOr Gerlitz 		goto nla_put_failure;
52862096a8SOr Gerlitz 
53862096a8SOr Gerlitz 	val = test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
54862096a8SOr Gerlitz 	if (nla_put_u16(skb, IFLA_IPOIB_MODE, val))
55862096a8SOr Gerlitz 		goto nla_put_failure;
56862096a8SOr Gerlitz 
57862096a8SOr Gerlitz 	val = test_bit(IPOIB_FLAG_UMCAST, &priv->flags);
58862096a8SOr Gerlitz 	if (nla_put_u16(skb, IFLA_IPOIB_UMCAST, val))
59862096a8SOr Gerlitz 		goto nla_put_failure;
60862096a8SOr Gerlitz 
61862096a8SOr Gerlitz 	return 0;
62862096a8SOr Gerlitz 
63862096a8SOr Gerlitz nla_put_failure:
64862096a8SOr Gerlitz 	return -EMSGSIZE;
65862096a8SOr Gerlitz }
66862096a8SOr Gerlitz 
67862096a8SOr Gerlitz static int ipoib_changelink(struct net_device *dev,
68862096a8SOr Gerlitz 			    struct nlattr *tb[], struct nlattr *data[])
69862096a8SOr Gerlitz {
70862096a8SOr Gerlitz 	u16 mode, umcast;
71862096a8SOr Gerlitz 	int ret = 0;
72862096a8SOr Gerlitz 
73862096a8SOr Gerlitz 	if (data[IFLA_IPOIB_MODE]) {
74862096a8SOr Gerlitz 		mode  = nla_get_u16(data[IFLA_IPOIB_MODE]);
75862096a8SOr Gerlitz 		if (mode == IPOIB_MODE_DATAGRAM)
76862096a8SOr Gerlitz 			ret = ipoib_set_mode(dev, "datagram\n");
77862096a8SOr Gerlitz 		else if (mode == IPOIB_MODE_CONNECTED)
78862096a8SOr Gerlitz 			ret = ipoib_set_mode(dev, "connected\n");
79862096a8SOr Gerlitz 		else
80862096a8SOr Gerlitz 			ret = -EINVAL;
81862096a8SOr Gerlitz 
82862096a8SOr Gerlitz 		if (ret < 0)
83862096a8SOr Gerlitz 			goto out_err;
84862096a8SOr Gerlitz 	}
85862096a8SOr Gerlitz 
86862096a8SOr Gerlitz 	if (data[IFLA_IPOIB_UMCAST]) {
87862096a8SOr Gerlitz 		umcast = nla_get_u16(data[IFLA_IPOIB_UMCAST]);
88862096a8SOr Gerlitz 		ipoib_set_umcast(dev, umcast);
89862096a8SOr Gerlitz 	}
90862096a8SOr Gerlitz 
91862096a8SOr Gerlitz out_err:
92862096a8SOr Gerlitz 	return ret;
93862096a8SOr Gerlitz }
94862096a8SOr Gerlitz 
959baa0b03SOr Gerlitz static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
969baa0b03SOr Gerlitz 			       struct nlattr *tb[], struct nlattr *data[])
979baa0b03SOr Gerlitz {
989baa0b03SOr Gerlitz 	struct net_device *pdev;
999baa0b03SOr Gerlitz 	struct ipoib_dev_priv *ppriv;
1009baa0b03SOr Gerlitz 	u16 child_pkey;
1019baa0b03SOr Gerlitz 	int err;
1029baa0b03SOr Gerlitz 
1039baa0b03SOr Gerlitz 	if (!tb[IFLA_LINK])
1049baa0b03SOr Gerlitz 		return -EINVAL;
1059baa0b03SOr Gerlitz 
1069baa0b03SOr Gerlitz 	pdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
1070d68fc4fSHangbin Liu 	if (!pdev || pdev->type != ARPHRD_INFINIBAND)
1089baa0b03SOr Gerlitz 		return -ENODEV;
1099baa0b03SOr Gerlitz 
110c1048affSErez Shitrit 	ppriv = ipoib_priv(pdev);
1119baa0b03SOr Gerlitz 
1129baa0b03SOr Gerlitz 	if (test_bit(IPOIB_FLAG_SUBINTERFACE, &ppriv->flags)) {
1139baa0b03SOr Gerlitz 		ipoib_warn(ppriv, "child creation disallowed for child devices\n");
1149baa0b03SOr Gerlitz 		return -EINVAL;
1159baa0b03SOr Gerlitz 	}
1169baa0b03SOr Gerlitz 
1179baa0b03SOr Gerlitz 	if (!data || !data[IFLA_IPOIB_PKEY]) {
1189baa0b03SOr Gerlitz 		ipoib_dbg(ppriv, "no pkey specified, using parent pkey\n");
1199baa0b03SOr Gerlitz 		child_pkey  = ppriv->pkey;
1209baa0b03SOr Gerlitz 	} else
1219baa0b03SOr Gerlitz 		child_pkey  = nla_get_u16(data[IFLA_IPOIB_PKEY]);
1229baa0b03SOr Gerlitz 
1233d790a4cSOr Gerlitz 	if (child_pkey == 0 || child_pkey == 0x8000)
1243d790a4cSOr Gerlitz 		return -EINVAL;
1253d790a4cSOr Gerlitz 
1263d790a4cSOr Gerlitz 	/*
1273d790a4cSOr Gerlitz 	 * Set the full membership bit, so that we join the right
1283d790a4cSOr Gerlitz 	 * broadcast group, etc.
1293d790a4cSOr Gerlitz 	 */
1303d790a4cSOr Gerlitz 	child_pkey |= 0x8000;
1313d790a4cSOr Gerlitz 
132c1048affSErez Shitrit 	err = __ipoib_vlan_add(ppriv, ipoib_priv(dev),
133c1048affSErez Shitrit 			       child_pkey, IPOIB_RTNL_CHILD);
1349baa0b03SOr Gerlitz 
135862096a8SOr Gerlitz 	if (!err && data)
136862096a8SOr Gerlitz 		err = ipoib_changelink(dev, tb, data);
1379baa0b03SOr Gerlitz 	return err;
1389baa0b03SOr Gerlitz }
1399baa0b03SOr Gerlitz 
1409baa0b03SOr Gerlitz static void ipoib_unregister_child_dev(struct net_device *dev, struct list_head *head)
1419baa0b03SOr Gerlitz {
1429baa0b03SOr Gerlitz 	struct ipoib_dev_priv *priv, *ppriv;
1439baa0b03SOr Gerlitz 
144c1048affSErez Shitrit 	priv = ipoib_priv(dev);
145c1048affSErez Shitrit 	ppriv = ipoib_priv(priv->parent);
1469baa0b03SOr Gerlitz 
147f47944ccSErez Shitrit 	down_write(&ppriv->vlan_rwsem);
1489baa0b03SOr Gerlitz 	unregister_netdevice_queue(dev, head);
1499baa0b03SOr Gerlitz 	list_del(&priv->list);
150f47944ccSErez Shitrit 	up_write(&ppriv->vlan_rwsem);
1519baa0b03SOr Gerlitz }
1529baa0b03SOr Gerlitz 
1539baa0b03SOr Gerlitz static size_t ipoib_get_size(const struct net_device *dev)
1549baa0b03SOr Gerlitz {
155862096a8SOr Gerlitz 	return nla_total_size(2) +	/* IFLA_IPOIB_PKEY   */
156862096a8SOr Gerlitz 		nla_total_size(2) +	/* IFLA_IPOIB_MODE   */
157862096a8SOr Gerlitz 		nla_total_size(2);	/* IFLA_IPOIB_UMCAST */
1589baa0b03SOr Gerlitz }
1599baa0b03SOr Gerlitz 
1609baa0b03SOr Gerlitz static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
1619baa0b03SOr Gerlitz 	.kind		= "ipoib",
1629baa0b03SOr Gerlitz 	.maxtype	= IFLA_IPOIB_MAX,
1639baa0b03SOr Gerlitz 	.policy		= ipoib_policy,
1649baa0b03SOr Gerlitz 	.priv_size	= sizeof(struct ipoib_dev_priv),
165*cd565b4bSErez Shitrit 	.setup		= ipoib_setup_common,
1669baa0b03SOr Gerlitz 	.newlink	= ipoib_new_child_link,
167862096a8SOr Gerlitz 	.changelink	= ipoib_changelink,
1689baa0b03SOr Gerlitz 	.dellink	= ipoib_unregister_child_dev,
1699baa0b03SOr Gerlitz 	.get_size	= ipoib_get_size,
170862096a8SOr Gerlitz 	.fill_info	= ipoib_fill_info,
1719baa0b03SOr Gerlitz };
1729baa0b03SOr Gerlitz 
1739baa0b03SOr Gerlitz int __init ipoib_netlink_init(void)
1749baa0b03SOr Gerlitz {
1759baa0b03SOr Gerlitz 	return rtnl_link_register(&ipoib_link_ops);
1769baa0b03SOr Gerlitz }
1779baa0b03SOr Gerlitz 
1789baa0b03SOr Gerlitz void __exit ipoib_netlink_fini(void)
1799baa0b03SOr Gerlitz {
1809baa0b03SOr Gerlitz 	rtnl_link_unregister(&ipoib_link_ops);
1819baa0b03SOr Gerlitz }
1829baa0b03SOr Gerlitz 
1839baa0b03SOr Gerlitz MODULE_ALIAS_RTNL_LINK("ipoib");
184