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