[PATCH net-next 1/1] rtnetlink: request RTM_GETLINK by pid or fd

From: Christian Brauner
Date: Thu Jan 18 2018 - 15:22:10 EST


This makes it possible to identify the target network namespace of a
RTM_GETLINK message by pid or fd.
Often userspace tools that make heavy use of network namespaces need a
simple and cheap way of querying network devices and network device
properties. This becomes even more crucial when the network namespaces in
question are transient. In such scenarios setting a netns id property is
not really wanted and it is preferable to avoid the hit of (possibly
multiple) setns() syscalls (e.g. attaching to the target network namespace
and back to the original network namespace.). This commit lets userspace
set the IFLA_NET_NS_{FD,PID} property to identify a target network
namespace where the device in question is to be queried.

Signed-off-by: Christian Brauner <christian.brauner@xxxxxxxxxx>
---
net/core/rtnetlink.c | 63 +++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 50 insertions(+), 13 deletions(-)

diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 16d644a4f974..5210448dcf1f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1509,7 +1509,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
struct net_device *dev, struct net *src_net,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags, u32 ext_filter_mask,
- u32 event, int *new_nsid, int tgt_netnsid)
+ u32 event, int *new_nsid, int tgt_netnsid,
+ int tgt_netnsid_type)
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
@@ -1527,8 +1528,23 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
ifm->ifi_flags = dev_get_flags(dev);
ifm->ifi_change = change;

- if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid))
- goto nla_put_failure;
+ if (tgt_netnsid >= 0) {
+ u32 err = -1;
+
+ switch (tgt_netnsid_type) {
+ case IFLA_IF_NETNSID:
+ err = nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid);
+ break;
+ case IFLA_NET_NS_PID:
+ err = nla_put_s32(skb, IFLA_NET_NS_PID, tgt_netnsid);
+ break;
+ case IFLA_NET_NS_FD:
+ err = nla_put_s32(skb, IFLA_NET_NS_FD, tgt_netnsid);
+ break;
+ }
+ if (err)
+ goto nla_put_failure;
+ }

if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) ||
@@ -1791,6 +1807,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
unsigned int flags = NLM_F_MULTI;
int master_idx = 0;
int netnsid = -1;
+ int netnsid_type = -1;
int err;
int hdrlen;

@@ -1810,12 +1827,22 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX,
ifla_policy, NULL) >= 0) {
if (tb[IFLA_IF_NETNSID]) {
+ netnsid_type = IFLA_IF_NETNSID;
netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]);
tgt_net = get_target_net(skb->sk, netnsid);
- if (IS_ERR(tgt_net)) {
- tgt_net = net;
- netnsid = -1;
- }
+ } else if (tb[IFLA_NET_NS_PID]) {
+ netnsid_type = IFLA_NET_NS_PID;
+ netnsid = nla_get_s32(tb[IFLA_NET_NS_PID]);
+ tgt_net = get_net_ns_by_pid(netnsid);
+ } else if (tb[IFLA_NET_NS_FD]) {
+ netnsid_type = IFLA_NET_NS_FD;
+ netnsid = nla_get_s32(tb[IFLA_NET_NS_FD]);
+ tgt_net = get_net_ns_by_fd(netnsid);
+ }
+ if (IS_ERR(tgt_net)) {
+ tgt_net = net;
+ netnsid = -1;
+ netnsid_type = -1;
}

if (tb[IFLA_EXT_MASK])
@@ -1845,7 +1872,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq, 0,
flags,
ext_filter_mask, 0, NULL,
- netnsid);
+ netnsid, netnsid_type);

if (err < 0) {
if (likely(skb->len))
@@ -2984,6 +3011,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net_device *dev = NULL;
struct sk_buff *nskb;
int netnsid = -1;
+ int netnsid_type = -1;
int err;
u32 ext_filter_mask = 0;

@@ -2992,11 +3020,20 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;

if (tb[IFLA_IF_NETNSID]) {
+ netnsid_type = IFLA_IF_NETNSID;
netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]);
tgt_net = get_target_net(NETLINK_CB(skb).sk, netnsid);
- if (IS_ERR(tgt_net))
- return PTR_ERR(tgt_net);
- }
+ } else if (tb[IFLA_NET_NS_PID]) {
+ netnsid_type = IFLA_NET_NS_PID;
+ netnsid = nla_get_s32(tb[IFLA_NET_NS_PID]);
+ tgt_net = get_net_ns_by_pid(netnsid);
+ } else if (tb[IFLA_NET_NS_FD]) {
+ netnsid_type = IFLA_NET_NS_FD;
+ netnsid = nla_get_s32(tb[IFLA_NET_NS_FD]);
+ tgt_net = get_net_ns_by_fd(netnsid);
+ }
+ if (IS_ERR(tgt_net))
+ return PTR_ERR(tgt_net);

if (tb[IFLA_IFNAME])
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
@@ -3025,7 +3062,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
err = rtnl_fill_ifinfo(nskb, dev, net,
RTM_NEWLINK, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, 0, 0, ext_filter_mask,
- 0, NULL, netnsid);
+ 0, NULL, netnsid, netnsid_type);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size */
WARN_ON(err == -EMSGSIZE);
@@ -3134,7 +3171,7 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,

err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
type, 0, 0, change, 0, 0, event,
- new_nsid, -1);
+ new_nsid, -1, -1);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
--
2.14.1