Skip to content

Commit

Permalink
net: rtnetlink: add linkprop commands to add and delete alternative i…
Browse files Browse the repository at this point in the history
…fnames

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>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Oct 1, 2019
1 parent ff92741 commit 36fbf1e
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 2 deletions.
4 changes: 4 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -927,10 +927,14 @@ struct tlsdev_ops;

struct netdev_name_node {
struct hlist_node hlist;
struct list_head list;
struct net_device *dev;
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.
* The following hooks can be defined; unless noted otherwise, they are
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/if.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define IFNAMSIZ 16
#endif /* __UAPI_DEF_IF_IFNAMSIZ */
#define IFALIASZ 256
#define ALTIFNAMSIZ 128
#include <linux/hdlc/ioctl.h>

/* For glibc compatibility. An empty enum does not compile. */
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ enum {
IFLA_NEW_IFINDEX,
IFLA_MIN_MTU,
IFLA_MAX_MTU,
IFLA_PROP_LIST,
IFLA_ALT_IFNAME, /* Alternative ifname */
__IFLA_MAX
};

Expand Down
7 changes: 7 additions & 0 deletions include/uapi/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ enum {
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,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
Expand Down
58 changes: 57 additions & 1 deletion net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,13 @@ static struct netdev_name_node *netdev_name_node_alloc(struct net_device *dev,
static struct netdev_name_node *
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)
Expand Down Expand Up @@ -289,6 +295,55 @@ static struct netdev_name_node *netdev_name_node_lookup_rcu(struct net *net,
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 */
static void list_netdevice(struct net_device *dev)
{
Expand Down Expand Up @@ -8317,6 +8372,7 @@ static void rollback_registered_many(struct list_head *head)
dev_uc_flush(dev);
dev_mc_flush(dev);

netdev_name_node_alt_flush(dev);
netdev_name_node_free(dev->name_node);

if (dev->netdev_ops->ndo_uninit)
Expand Down
103 changes: 103 additions & 0 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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] = {
Expand Down Expand Up @@ -3373,6 +3376,103 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
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);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion security/selinux/nlmsgtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ 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[] =
Expand Down Expand Up @@ -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
* 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,
sizeof(nlmsg_route_perms));
break;
Expand Down

0 comments on commit 36fbf1e

Please sign in to comment.