Commit a0b63c64 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Paolo Abeni
Browse files

rtnetlink: Call rtnl_link_get_net_capable() in do_setlink().



We will push RTNL down to rtnl_setlink().

RTM_SETLINK could call rtnl_link_get_net_capable() in do_setlink()
to move a dev to a new netns, but the netns needs to be fetched before
holding rtnl_net_lock().

Let's move it to rtnl_setlink() and pass the netns to do_setlink().

Now, RTM_NEWLINK paths (rtnl_changelink() and rtnl_group_changelink())
can pass the prefetched netns to do_setlink().

Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 6e495fad
Loading
Loading
Loading
Loading
+16 −16
Original line number Diff line number Diff line
@@ -2881,8 +2881,8 @@ static int do_set_proto_down(struct net_device *dev,
#define DO_SETLINK_MODIFIED	0x01
/* notify flag means notify + modified. */
#define DO_SETLINK_NOTIFY	0x03
static int do_setlink(const struct sk_buff *skb,
		      struct net_device *dev, struct ifinfomsg *ifm,
static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
		      struct net *tgt_net, struct ifinfomsg *ifm,
		      struct netlink_ext_ack *extack,
		      struct nlattr **tb, int status)
{
@@ -2899,27 +2899,19 @@ static int do_setlink(const struct sk_buff *skb,
	else
		ifname[0] = '\0';

	if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) {
	if (!net_eq(tgt_net, dev_net(dev))) {
		const char *pat = ifname[0] ? ifname : NULL;
		struct net *net;
		int new_ifindex;

		net = rtnl_link_get_net_capable(skb, dev_net(dev),
						tb, CAP_NET_ADMIN);
		if (IS_ERR(net)) {
			err = PTR_ERR(net);
			goto errout;
		}

		if (tb[IFLA_NEW_IFINDEX])
			new_ifindex = nla_get_s32(tb[IFLA_NEW_IFINDEX]);
		else
			new_ifindex = 0;

		err = __dev_change_net_namespace(dev, net, pat, new_ifindex);
		put_net(net);
		err = __dev_change_net_namespace(dev, tgt_net, pat, new_ifindex);
		if (err)
			goto errout;

		status |= DO_SETLINK_MODIFIED;
	}

@@ -3283,6 +3275,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
	struct net *net = sock_net(skb->sk);
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct net *tgt_net;
	int err;

	err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX,
@@ -3294,6 +3287,12 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
	if (err < 0)
		goto errout;

	tgt_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN);
	if (IS_ERR(tgt_net)) {
		err = PTR_ERR(tgt_net);
		goto errout;
	}

	if (ifm->ifi_index > 0)
		dev = __dev_get_by_index(net, ifm->ifi_index);
	else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME])
@@ -3302,10 +3301,11 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
		err = -EINVAL;

	if (dev)
		err = do_setlink(skb, dev, ifm, extack, tb, 0);
		err = do_setlink(skb, dev, tgt_net, ifm, extack, tb, 0);
	else if (!err)
		err = -ENODEV;

	put_net(tgt_net);
errout:
	return err;
}
@@ -3599,7 +3599,7 @@ static int rtnl_changelink(const struct sk_buff *skb, struct nlmsghdr *nlh,
		status |= DO_SETLINK_NOTIFY;
	}

	return do_setlink(skb, dev, nlmsg_data(nlh), extack, tb, status);
	return do_setlink(skb, dev, tgt_net, nlmsg_data(nlh), extack, tb, status);
}

static int rtnl_group_changelink(const struct sk_buff *skb,
@@ -3613,7 +3613,7 @@ static int rtnl_group_changelink(const struct sk_buff *skb,

	for_each_netdev_safe(net, dev, aux) {
		if (dev->group == group) {
			err = do_setlink(skb, dev, ifm, extack, tb, 0);
			err = do_setlink(skb, dev, tgt_net, ifm, extack, tb, 0);
			if (err < 0)
				return err;
		}