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:
parent
ff92741270
commit
36fbf1e52b
7 changed files with 177 additions and 2 deletions
|
@ -927,10 +927,14 @@ struct tlsdev_ops;
|
||||||
|
|
||||||
struct netdev_name_node {
|
struct netdev_name_node {
|
||||||
struct hlist_node hlist;
|
struct hlist_node hlist;
|
||||||
|
struct list_head list;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int netdev_name_node_alt_create(struct net_device *dev, const char *name);
|
||||||
|
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This structure defines the management hooks for network devices.
|
* This structure defines the management hooks for network devices.
|
||||||
* The following hooks can be defined; unless noted otherwise, they are
|
* The following hooks can be defined; unless noted otherwise, they are
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#define IFNAMSIZ 16
|
#define IFNAMSIZ 16
|
||||||
#endif /* __UAPI_DEF_IF_IFNAMSIZ */
|
#endif /* __UAPI_DEF_IF_IFNAMSIZ */
|
||||||
#define IFALIASZ 256
|
#define IFALIASZ 256
|
||||||
|
#define ALTIFNAMSIZ 128
|
||||||
#include <linux/hdlc/ioctl.h>
|
#include <linux/hdlc/ioctl.h>
|
||||||
|
|
||||||
/* For glibc compatibility. An empty enum does not compile. */
|
/* For glibc compatibility. An empty enum does not compile. */
|
||||||
|
|
|
@ -167,6 +167,8 @@ enum {
|
||||||
IFLA_NEW_IFINDEX,
|
IFLA_NEW_IFINDEX,
|
||||||
IFLA_MIN_MTU,
|
IFLA_MIN_MTU,
|
||||||
IFLA_MAX_MTU,
|
IFLA_MAX_MTU,
|
||||||
|
IFLA_PROP_LIST,
|
||||||
|
IFLA_ALT_IFNAME, /* Alternative ifname */
|
||||||
__IFLA_MAX
|
__IFLA_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,13 @@ enum {
|
||||||
RTM_GETNEXTHOP,
|
RTM_GETNEXTHOP,
|
||||||
#define RTM_GETNEXTHOP RTM_GETNEXTHOP
|
#define RTM_GETNEXTHOP RTM_GETNEXTHOP
|
||||||
|
|
||||||
|
RTM_NEWLINKPROP = 108,
|
||||||
|
#define RTM_NEWLINKPROP RTM_NEWLINKPROP
|
||||||
|
RTM_DELLINKPROP,
|
||||||
|
#define RTM_DELLINKPROP RTM_DELLINKPROP
|
||||||
|
RTM_GETLINKPROP,
|
||||||
|
#define RTM_GETLINKPROP RTM_GETLINKPROP
|
||||||
|
|
||||||
__RTM_MAX,
|
__RTM_MAX,
|
||||||
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
|
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
|
||||||
};
|
};
|
||||||
|
|
|
@ -245,7 +245,13 @@ static struct netdev_name_node *netdev_name_node_alloc(struct net_device *dev,
|
||||||
static struct netdev_name_node *
|
static struct netdev_name_node *
|
||||||
netdev_name_node_head_alloc(struct net_device *dev)
|
netdev_name_node_head_alloc(struct net_device *dev)
|
||||||
{
|
{
|
||||||
return netdev_name_node_alloc(dev, dev->name);
|
struct netdev_name_node *name_node;
|
||||||
|
|
||||||
|
name_node = netdev_name_node_alloc(dev, dev->name);
|
||||||
|
if (!name_node)
|
||||||
|
return NULL;
|
||||||
|
INIT_LIST_HEAD(&name_node->list);
|
||||||
|
return name_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_name_node_free(struct netdev_name_node *name_node)
|
static void netdev_name_node_free(struct netdev_name_node *name_node)
|
||||||
|
@ -289,6 +295,55 @@ static struct netdev_name_node *netdev_name_node_lookup_rcu(struct net *net,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int netdev_name_node_alt_create(struct net_device *dev, const char *name)
|
||||||
|
{
|
||||||
|
struct netdev_name_node *name_node;
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
|
||||||
|
name_node = netdev_name_node_lookup(net, name);
|
||||||
|
if (name_node)
|
||||||
|
return -EEXIST;
|
||||||
|
name_node = netdev_name_node_alloc(dev, name);
|
||||||
|
if (!name_node)
|
||||||
|
return -ENOMEM;
|
||||||
|
netdev_name_node_add(net, name_node);
|
||||||
|
/* The node that holds dev->name acts as a head of per-device list. */
|
||||||
|
list_add_tail(&name_node->list, &dev->name_node->list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(netdev_name_node_alt_create);
|
||||||
|
|
||||||
|
static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node)
|
||||||
|
{
|
||||||
|
list_del(&name_node->list);
|
||||||
|
netdev_name_node_del(name_node);
|
||||||
|
kfree(name_node->name);
|
||||||
|
netdev_name_node_free(name_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name)
|
||||||
|
{
|
||||||
|
struct netdev_name_node *name_node;
|
||||||
|
struct net *net = dev_net(dev);
|
||||||
|
|
||||||
|
name_node = netdev_name_node_lookup(net, name);
|
||||||
|
if (!name_node)
|
||||||
|
return -ENOENT;
|
||||||
|
__netdev_name_node_alt_destroy(name_node);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(netdev_name_node_alt_destroy);
|
||||||
|
|
||||||
|
static void netdev_name_node_alt_flush(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct netdev_name_node *name_node, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(name_node, tmp, &dev->name_node->list, list)
|
||||||
|
__netdev_name_node_alt_destroy(name_node);
|
||||||
|
}
|
||||||
|
|
||||||
/* Device list insertion */
|
/* Device list insertion */
|
||||||
static void list_netdevice(struct net_device *dev)
|
static void list_netdevice(struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -8317,6 +8372,7 @@ static void rollback_registered_many(struct list_head *head)
|
||||||
dev_uc_flush(dev);
|
dev_uc_flush(dev);
|
||||||
dev_mc_flush(dev);
|
dev_mc_flush(dev);
|
||||||
|
|
||||||
|
netdev_name_node_alt_flush(dev);
|
||||||
netdev_name_node_free(dev->name_node);
|
netdev_name_node_free(dev->name_node);
|
||||||
|
|
||||||
if (dev->netdev_ops->ndo_uninit)
|
if (dev->netdev_ops->ndo_uninit)
|
||||||
|
|
|
@ -1750,6 +1750,9 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
|
||||||
[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
|
[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
|
||||||
[IFLA_MIN_MTU] = { .type = NLA_U32 },
|
[IFLA_MIN_MTU] = { .type = NLA_U32 },
|
||||||
[IFLA_MAX_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] = {
|
static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
|
||||||
|
@ -3373,6 +3376,103 @@ out:
|
||||||
return err;
|
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)
|
static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||||
{
|
{
|
||||||
struct net *net = sock_net(skb->sk);
|
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_GETROUTE, NULL, rtnl_dump_all, 0);
|
||||||
rtnl_register(PF_UNSPEC, RTM_GETNETCONF, 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_NEWNEIGH, rtnl_fdb_add, NULL, 0);
|
||||||
rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, 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);
|
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, rtnl_fdb_get, rtnl_fdb_dump, 0);
|
||||||
|
|
|
@ -83,6 +83,8 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
|
||||||
{ RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
{ RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||||
{ RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
{ RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||||
{ RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
|
{ RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
|
||||||
|
{ RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||||
|
{ RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
|
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
|
||||||
|
@ -166,7 +168,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
|
||||||
* structures at the top of this file with the new mappings
|
* structures at the top of this file with the new mappings
|
||||||
* before updating the BUILD_BUG_ON() macro!
|
* before updating the BUILD_BUG_ON() macro!
|
||||||
*/
|
*/
|
||||||
BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOP + 3));
|
BUILD_BUG_ON(RTM_MAX != (RTM_NEWLINKPROP + 3));
|
||||||
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
|
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
|
||||||
sizeof(nlmsg_route_perms));
|
sizeof(nlmsg_route_perms));
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue