rtnetlink: implement setting of master device
This patch allows userspace to enslave/release slave devices via netlink interface using IFLA_MASTER. This introduces generic way to add/remove underling devices. Signed-off-by: Jiri Pirko <jpirko@redhat.com> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f45437efff
commit
fbaec0ea54
|
@ -783,6 +783,14 @@ struct netdev_tc_txq {
|
|||
* Set hardware filter for RFS. rxq_index is the target queue index;
|
||||
* flow_id is a flow ID to be passed to rps_may_expire_flow() later.
|
||||
* Return the filter ID on success, or a negative error code.
|
||||
*
|
||||
* Slave management functions (for bridge, bonding, etc). User should
|
||||
* call netdev_set_master() to set dev->master properly.
|
||||
* int (*ndo_add_slave)(struct net_device *dev, struct net_device *slave_dev);
|
||||
* Called to make another netdev an underling.
|
||||
*
|
||||
* int (*ndo_del_slave)(struct net_device *dev, struct net_device *slave_dev);
|
||||
* Called to release previously enslaved netdev.
|
||||
*/
|
||||
#define HAVE_NET_DEVICE_OPS
|
||||
struct net_device_ops {
|
||||
|
@ -862,6 +870,10 @@ struct net_device_ops {
|
|||
u16 rxq_index,
|
||||
u32 flow_id);
|
||||
#endif
|
||||
int (*ndo_add_slave)(struct net_device *dev,
|
||||
struct net_device *slave_dev);
|
||||
int (*ndo_del_slave)(struct net_device *dev,
|
||||
struct net_device *slave_dev);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1036,6 +1036,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
|
|||
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
|
||||
[IFLA_MTU] = { .type = NLA_U32 },
|
||||
[IFLA_LINK] = { .type = NLA_U32 },
|
||||
[IFLA_MASTER] = { .type = NLA_U32 },
|
||||
[IFLA_TXQLEN] = { .type = NLA_U32 },
|
||||
[IFLA_WEIGHT] = { .type = NLA_U32 },
|
||||
[IFLA_OPERSTATE] = { .type = NLA_U8 },
|
||||
|
@ -1178,6 +1179,41 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int do_set_master(struct net_device *dev, int ifindex)
|
||||
{
|
||||
struct net_device *master_dev;
|
||||
const struct net_device_ops *ops;
|
||||
int err;
|
||||
|
||||
if (dev->master) {
|
||||
if (dev->master->ifindex == ifindex)
|
||||
return 0;
|
||||
ops = dev->master->netdev_ops;
|
||||
if (ops->ndo_del_slave) {
|
||||
err = ops->ndo_del_slave(dev->master, dev);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifindex) {
|
||||
master_dev = __dev_get_by_index(dev_net(dev), ifindex);
|
||||
if (!master_dev)
|
||||
return -EINVAL;
|
||||
ops = master_dev->netdev_ops;
|
||||
if (ops->ndo_add_slave) {
|
||||
err = ops->ndo_add_slave(master_dev, dev);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
||||
struct nlattr **tb, char *ifname, int modified)
|
||||
{
|
||||
|
@ -1301,6 +1337,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
if (tb[IFLA_MASTER]) {
|
||||
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
|
||||
if (err)
|
||||
goto errout;
|
||||
modified = 1;
|
||||
}
|
||||
|
||||
if (tb[IFLA_TXQLEN])
|
||||
dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue