net: rtnetlink: add linkprop commands to add and delete alternative ifnames

Add two commands to add and delete list of link properties. Implement
the first property type along - alternative ifnames.
Each net device can have multiple alternative names.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiri Pirko
2019-09-30 11:48:16 +02:00
committed by David S. Miller
parent ff92741270
commit 36fbf1e52b
7 changed files with 177 additions and 2 deletions

View File

@@ -1750,6 +1750,9 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
[IFLA_MIN_MTU] = { .type = NLA_U32 },
[IFLA_MAX_MTU] = { .type = NLA_U32 },
[IFLA_PROP_LIST] = { .type = NLA_NESTED },
[IFLA_ALT_IFNAME] = { .type = NLA_STRING,
.len = ALTIFNAMSIZ - 1 },
};
static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -3373,6 +3376,103 @@ out:
return err;
}
static int rtnl_alt_ifname(int cmd, struct net_device *dev, struct nlattr *attr,
bool *changed, struct netlink_ext_ack *extack)
{
char *alt_ifname;
int err;
err = nla_validate(attr, attr->nla_len, IFLA_MAX, ifla_policy, extack);
if (err)
return err;
alt_ifname = nla_data(attr);
if (cmd == RTM_NEWLINKPROP) {
alt_ifname = kstrdup(alt_ifname, GFP_KERNEL);
if (!alt_ifname)
return -ENOMEM;
err = netdev_name_node_alt_create(dev, alt_ifname);
if (err) {
kfree(alt_ifname);
return err;
}
} else if (cmd == RTM_DELLINKPROP) {
err = netdev_name_node_alt_destroy(dev, alt_ifname);
if (err)
return err;
} else {
WARN_ON(1);
return 0;
}
*changed = true;
return 0;
}
static int rtnl_linkprop(int cmd, struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFLA_MAX + 1];
struct net_device *dev;
struct ifinfomsg *ifm;
bool changed = false;
struct nlattr *attr;
int err, rem;
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
if (err)
return err;
err = rtnl_ensure_unique_netns(tb, extack, true);
if (err)
return err;
ifm = nlmsg_data(nlh);
if (ifm->ifi_index > 0) {
dev = __dev_get_by_index(net, ifm->ifi_index);
} else if (tb[IFLA_IFNAME]) {
char ifname[IFNAMSIZ];
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
dev = __dev_get_by_name(net, ifname);
} else {
return -EINVAL;
}
if (!dev)
return -ENODEV;
if (!tb[IFLA_PROP_LIST])
return 0;
nla_for_each_nested(attr, tb[IFLA_PROP_LIST], rem) {
switch (nla_type(attr)) {
case IFLA_ALT_IFNAME:
err = rtnl_alt_ifname(cmd, dev, attr, &changed, extack);
if (err)
return err;
break;
}
}
if (changed)
netdev_state_change(dev);
return 0;
}
static int rtnl_newlinkprop(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
return rtnl_linkprop(RTM_NEWLINKPROP, skb, nlh, extack);
}
static int rtnl_dellinkprop(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
return rtnl_linkprop(RTM_DELLINKPROP, skb, nlh, extack);
}
static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
@@ -5331,6 +5431,9 @@ void __init rtnetlink_init(void)
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, 0);
rtnl_register(PF_UNSPEC, RTM_GETNETCONF, NULL, rtnl_dump_all, 0);
rtnl_register(PF_UNSPEC, RTM_NEWLINKPROP, rtnl_newlinkprop, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_DELLINKPROP, rtnl_dellinkprop, NULL, 0);
rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, 0);
rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, 0);
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, rtnl_fdb_get, rtnl_fdb_dump, 0);