Skip to content

Commit 36fbf1e

Browse files
jpirkodavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ff92741 commit 36fbf1e

File tree

7 files changed

+177
-2
lines changed

7 files changed

+177
-2
lines changed

include/linux/netdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,10 +927,14 @@ struct tlsdev_ops;
927927

928928
struct netdev_name_node {
929929
struct hlist_node hlist;
930+
struct list_head list;
930931
struct net_device *dev;
931932
const char *name;
932933
};
933934

935+
int netdev_name_node_alt_create(struct net_device *dev, const char *name);
936+
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name);
937+
934938
/*
935939
* This structure defines the management hooks for network devices.
936940
* The following hooks can be defined; unless noted otherwise, they are

include/uapi/linux/if.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#define IFNAMSIZ 16
3434
#endif /* __UAPI_DEF_IF_IFNAMSIZ */
3535
#define IFALIASZ 256
36+
#define ALTIFNAMSIZ 128
3637
#include <linux/hdlc/ioctl.h>
3738

3839
/* For glibc compatibility. An empty enum does not compile. */

include/uapi/linux/if_link.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ enum {
167167
IFLA_NEW_IFINDEX,
168168
IFLA_MIN_MTU,
169169
IFLA_MAX_MTU,
170+
IFLA_PROP_LIST,
171+
IFLA_ALT_IFNAME, /* Alternative ifname */
170172
__IFLA_MAX
171173
};
172174

include/uapi/linux/rtnetlink.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ enum {
164164
RTM_GETNEXTHOP,
165165
#define RTM_GETNEXTHOP RTM_GETNEXTHOP
166166

167+
RTM_NEWLINKPROP = 108,
168+
#define RTM_NEWLINKPROP RTM_NEWLINKPROP
169+
RTM_DELLINKPROP,
170+
#define RTM_DELLINKPROP RTM_DELLINKPROP
171+
RTM_GETLINKPROP,
172+
#define RTM_GETLINKPROP RTM_GETLINKPROP
173+
167174
__RTM_MAX,
168175
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
169176
};

net/core/dev.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,13 @@ static struct netdev_name_node *netdev_name_node_alloc(struct net_device *dev,
245245
static struct netdev_name_node *
246246
netdev_name_node_head_alloc(struct net_device *dev)
247247
{
248-
return netdev_name_node_alloc(dev, dev->name);
248+
struct netdev_name_node *name_node;
249+
250+
name_node = netdev_name_node_alloc(dev, dev->name);
251+
if (!name_node)
252+
return NULL;
253+
INIT_LIST_HEAD(&name_node->list);
254+
return name_node;
249255
}
250256

251257
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,
289295
return NULL;
290296
}
291297

298+
int netdev_name_node_alt_create(struct net_device *dev, const char *name)
299+
{
300+
struct netdev_name_node *name_node;
301+
struct net *net = dev_net(dev);
302+
303+
name_node = netdev_name_node_lookup(net, name);
304+
if (name_node)
305+
return -EEXIST;
306+
name_node = netdev_name_node_alloc(dev, name);
307+
if (!name_node)
308+
return -ENOMEM;
309+
netdev_name_node_add(net, name_node);
310+
/* The node that holds dev->name acts as a head of per-device list. */
311+
list_add_tail(&name_node->list, &dev->name_node->list);
312+
313+
return 0;
314+
}
315+
EXPORT_SYMBOL(netdev_name_node_alt_create);
316+
317+
static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node)
318+
{
319+
list_del(&name_node->list);
320+
netdev_name_node_del(name_node);
321+
kfree(name_node->name);
322+
netdev_name_node_free(name_node);
323+
}
324+
325+
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name)
326+
{
327+
struct netdev_name_node *name_node;
328+
struct net *net = dev_net(dev);
329+
330+
name_node = netdev_name_node_lookup(net, name);
331+
if (!name_node)
332+
return -ENOENT;
333+
__netdev_name_node_alt_destroy(name_node);
334+
335+
return 0;
336+
}
337+
EXPORT_SYMBOL(netdev_name_node_alt_destroy);
338+
339+
static void netdev_name_node_alt_flush(struct net_device *dev)
340+
{
341+
struct netdev_name_node *name_node, *tmp;
342+
343+
list_for_each_entry_safe(name_node, tmp, &dev->name_node->list, list)
344+
__netdev_name_node_alt_destroy(name_node);
345+
}
346+
292347
/* Device list insertion */
293348
static void list_netdevice(struct net_device *dev)
294349
{
@@ -8317,6 +8372,7 @@ static void rollback_registered_many(struct list_head *head)
83178372
dev_uc_flush(dev);
83188373
dev_mc_flush(dev);
83198374

8375+
netdev_name_node_alt_flush(dev);
83208376
netdev_name_node_free(dev->name_node);
83218377

83228378
if (dev->netdev_ops->ndo_uninit)

net/core/rtnetlink.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,9 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
17501750
[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
17511751
[IFLA_MIN_MTU] = { .type = NLA_U32 },
17521752
[IFLA_MAX_MTU] = { .type = NLA_U32 },
1753+
[IFLA_PROP_LIST] = { .type = NLA_NESTED },
1754+
[IFLA_ALT_IFNAME] = { .type = NLA_STRING,
1755+
.len = ALTIFNAMSIZ - 1 },
17531756
};
17541757

17551758
static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -3373,6 +3376,103 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
33733376
return err;
33743377
}
33753378

3379+
static int rtnl_alt_ifname(int cmd, struct net_device *dev, struct nlattr *attr,
3380+
bool *changed, struct netlink_ext_ack *extack)
3381+
{
3382+
char *alt_ifname;
3383+
int err;
3384+
3385+
err = nla_validate(attr, attr->nla_len, IFLA_MAX, ifla_policy, extack);
3386+
if (err)
3387+
return err;
3388+
3389+
alt_ifname = nla_data(attr);
3390+
if (cmd == RTM_NEWLINKPROP) {
3391+
alt_ifname = kstrdup(alt_ifname, GFP_KERNEL);
3392+
if (!alt_ifname)
3393+
return -ENOMEM;
3394+
err = netdev_name_node_alt_create(dev, alt_ifname);
3395+
if (err) {
3396+
kfree(alt_ifname);
3397+
return err;
3398+
}
3399+
} else if (cmd == RTM_DELLINKPROP) {
3400+
err = netdev_name_node_alt_destroy(dev, alt_ifname);
3401+
if (err)
3402+
return err;
3403+
} else {
3404+
WARN_ON(1);
3405+
return 0;
3406+
}
3407+
3408+
*changed = true;
3409+
return 0;
3410+
}
3411+
3412+
static int rtnl_linkprop(int cmd, struct sk_buff *skb, struct nlmsghdr *nlh,
3413+
struct netlink_ext_ack *extack)
3414+
{
3415+
struct net *net = sock_net(skb->sk);
3416+
struct nlattr *tb[IFLA_MAX + 1];
3417+
struct net_device *dev;
3418+
struct ifinfomsg *ifm;
3419+
bool changed = false;
3420+
struct nlattr *attr;
3421+
int err, rem;
3422+
3423+
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
3424+
if (err)
3425+
return err;
3426+
3427+
err = rtnl_ensure_unique_netns(tb, extack, true);
3428+
if (err)
3429+
return err;
3430+
3431+
ifm = nlmsg_data(nlh);
3432+
if (ifm->ifi_index > 0) {
3433+
dev = __dev_get_by_index(net, ifm->ifi_index);
3434+
} else if (tb[IFLA_IFNAME]) {
3435+
char ifname[IFNAMSIZ];
3436+
3437+
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
3438+
dev = __dev_get_by_name(net, ifname);
3439+
} else {
3440+
return -EINVAL;
3441+
}
3442+
3443+
if (!dev)
3444+
return -ENODEV;
3445+
3446+
if (!tb[IFLA_PROP_LIST])
3447+
return 0;
3448+
3449+
nla_for_each_nested(attr, tb[IFLA_PROP_LIST], rem) {
3450+
switch (nla_type(attr)) {
3451+
case IFLA_ALT_IFNAME:
3452+
err = rtnl_alt_ifname(cmd, dev, attr, &changed, extack);
3453+
if (err)
3454+
return err;
3455+
break;
3456+
}
3457+
}
3458+
3459+
if (changed)
3460+
netdev_state_change(dev);
3461+
return 0;
3462+
}
3463+
3464+
static int rtnl_newlinkprop(struct sk_buff *skb, struct nlmsghdr *nlh,
3465+
struct netlink_ext_ack *extack)
3466+
{
3467+
return rtnl_linkprop(RTM_NEWLINKPROP, skb, nlh, extack);
3468+
}
3469+
3470+
static int rtnl_dellinkprop(struct sk_buff *skb, struct nlmsghdr *nlh,
3471+
struct netlink_ext_ack *extack)
3472+
{
3473+
return rtnl_linkprop(RTM_DELLINKPROP, skb, nlh, extack);
3474+
}
3475+
33763476
static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
33773477
{
33783478
struct net *net = sock_net(skb->sk);
@@ -5331,6 +5431,9 @@ void __init rtnetlink_init(void)
53315431
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, 0);
53325432
rtnl_register(PF_UNSPEC, RTM_GETNETCONF, NULL, rtnl_dump_all, 0);
53335433

5434+
rtnl_register(PF_UNSPEC, RTM_NEWLINKPROP, rtnl_newlinkprop, NULL, 0);
5435+
rtnl_register(PF_UNSPEC, RTM_DELLINKPROP, rtnl_dellinkprop, NULL, 0);
5436+
53345437
rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, 0);
53355438
rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, 0);
53365439
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, rtnl_fdb_get, rtnl_fdb_dump, 0);

security/selinux/nlmsgtab.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
8383
{ RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
8484
{ RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
8585
{ RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
86+
{ RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
87+
{ RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
8688
};
8789

8890
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
@@ -166,7 +168,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
166168
* structures at the top of this file with the new mappings
167169
* before updating the BUILD_BUG_ON() macro!
168170
*/
169-
BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOP + 3));
171+
BUILD_BUG_ON(RTM_MAX != (RTM_NEWLINKPROP + 3));
170172
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
171173
sizeof(nlmsg_route_perms));
172174
break;

0 commit comments

Comments
 (0)