All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] Ease to interpret net-nsid
@ 2018-11-21 11:01 Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
                   ` (4 more replies)
  0 siblings, 5 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev


The goal of this series is to ease the interpretation of nsid received in
netlink messages from other netns (when the user uses
NETLINK_F_LISTEN_ALL_NSID).

After this series, with a patched iproute2:

$ ip netns add foo
$ ip netns add bar
$ touch /var/run/netns/init_net
$ mount --bind /proc/1/ns/net /var/run/netns/init_net
$ ip netns set init_net 11
$ ip netns set foo 12
$ ip netns set bar 13
$ ip netns
init_net (id: 11)
bar (id: 13)
foo (id: 12)
$ ip -n foo netns set init_net 21
$ ip -n foo netns set foo 22
$ ip -n foo netns set bar 23
$ ip -n foo netns
init_net (id: 21)
bar (id: 23)
foo (id: 22)
$ ip -n bar netns set init_net 31
$ ip -n bar netns set foo 32
$ ip -n bar netns set bar 33
$ ip -n bar netns
init_net (id: 31)
bar (id: 33)
foo (id: 32)
$ ip netns list-id target-nsid 12
nsid 21 current-nsid 11 (iproute2 netns name: init_net)
nsid 22 current-nsid 12 (iproute2 netns name: foo)
nsid 23 current-nsid 13 (iproute2 netns name: bar)
$ ip -n bar netns list-id target-nsid 32 nsid 31
nsid 21 current-nsid 31 (iproute2 netns name: init_net)

 include/uapi/linux/net_namespace.h |   2 +
 net/core/net_namespace.c           | 132 ++++++++++++++++++++++++++++++-------
 2 files changed, 110 insertions(+), 24 deletions(-)

Comments are welcomed,
Regards,
Nicolas

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill()
  2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
@ 2018-11-21 11:01 ` Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel

This argument is not used anymore.

Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index fefe72774aeb..3e6af99bbe53 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -739,7 +739,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, struct net *net, int nsid)
+			 int cmd, int nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -801,7 +801,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(net, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, net, id);
+			    RTM_NEWNSID, id);
 	if (err < 0)
 		goto err_out;
 
@@ -833,7 +833,7 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, net_cb->net, id);
+			    RTM_NEWNSID, id);
 	if (ret < 0)
 		return ret;
 
@@ -876,7 +876,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
  2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
@ 2018-11-21 11:01 ` Nicolas Dichtel
  2018-11-21 18:05   ` David Ahern
  2018-11-21 11:01 ` [PATCH net-next 3/4] netns: enable to specify a nsid for a get request Nicolas Dichtel
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel

Like it was done for link and address, add the ability to perform get/dump
in another netns by specifying a target nsid attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 97 ++++++++++++++++++++++++------
 2 files changed, 80 insertions(+), 18 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0187c74d8889..0ed9dd61d32a 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
 	NETNSA_NSID,
 	NETNSA_PID,
 	NETNSA_FD,
+	NETNSA_TARGET_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3e6af99bbe53..3d02a742155f 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
 	[NETNSA_NSID]		= { .type = NLA_S32 },
 	[NETNSA_PID]		= { .type = NLA_U32 },
 	[NETNSA_FD]		= { .type = NLA_U32 },
+	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
 };
 
 static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -767,9 +768,9 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
+	struct net *peer, *target = net;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	struct net *peer;
 	int err, id;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -793,30 +794,47 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return PTR_ERR(peer);
 	}
 
+	if (tb[NETNSA_TARGET_NSID]) {
+		id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
+		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
+		if (IS_ERR(target)) {
+			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
+			NL_SET_ERR_MSG(extack,
+				       "Target netns reference is invalid");
+			err = PTR_ERR(target);
+			goto put_peer;
+		}
+	} else {
+		get_net(target);
+	}
+
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
 	if (!msg) {
 		err = -ENOMEM;
-		goto out;
+		goto put_target;
 	}
 
-	id = peernet2id(net, peer);
+	id = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
 			    RTM_NEWNSID, id);
 	if (err < 0)
-		goto err_out;
+		goto free_nlmsg;
 
 	err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid);
-	goto out;
+	goto put_target;
 
-err_out:
+free_nlmsg:
 	nlmsg_free(msg);
-out:
+put_target:
+	put_net(target);
+put_peer:
 	put_net(peer);
 	return err;
 }
 
 struct rtnl_net_dump_cb {
-	struct net *net;
+	struct net *tgt_net;
+	struct net *ref_net;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 	int idx;
@@ -842,29 +860,72 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	return 0;
 }
 
+static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
+				   struct rtnl_net_dump_cb *net_cb,
+				   struct netlink_callback *cb)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	struct nlattr *tb[NETNSA_MAX + 1];
+	int err, i;
+
+	err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
+				 rtnl_net_policy, extack);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i <= NETNSA_MAX; i++) {
+		if (!tb[i])
+			continue;
+
+		if (i == NETNSA_TARGET_NSID) {
+			struct net *net;
+
+			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
+			if (IS_ERR(net)) {
+				NL_SET_BAD_ATTR(extack, tb[i]);
+				NL_SET_ERR_MSG(extack,
+					       "Invalid target network namespace id");
+				return PTR_ERR(net);
+			}
+			net_cb->ref_net = net_cb->tgt_net;
+			net_cb->tgt_net = net;
+		} else {
+			NL_SET_BAD_ATTR(extack, tb[i]);
+			NL_SET_ERR_MSG(extack,
+				       "Unsupported attribute in dump request");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
-		.net = net,
+		.tgt_net = sock_net(skb->sk),
 		.skb = skb,
 		.cb = cb,
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
+	int err = 0;
 
-	if (cb->strict_check &&
-	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
-			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
-			return -EINVAL;
+	if (cb->strict_check) {
+		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
+		if (err < 0)
+			goto end;
 	}
 
-	spin_lock_bh(&net->nsid_lock);
-	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-	spin_unlock_bh(&net->nsid_lock);
+	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
-	return skb->len;
+end:
+	if (net_cb.ref_net)
+		put_net(net_cb.tgt_net);
+	return err < 0 ? err : skb->len;
 }
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next 3/4] netns: enable to specify a nsid for a get request
  2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-21 11:01 ` Nicolas Dichtel
  2018-11-21 11:01 ` [PATCH net-next 4/4] netns: enable to dump full nsid translation table Nicolas Dichtel
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
  4 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel

Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
netns to a nsid of another netns.
This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
user to interpret a nsid received from an other netns.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3d02a742155f..92730905886c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -783,6 +783,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	} else if (tb[NETNSA_FD]) {
 		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
 		nla = tb[NETNSA_FD];
+	} else if (tb[NETNSA_NSID]) {
+		peer = get_net_ns_by_id(net, nla_get_u32(tb[NETNSA_NSID]));
+		if (!peer)
+			peer = ERR_PTR(-ENOENT);
+		nla = tb[NETNSA_NSID];
 	} else {
 		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
 		return -EINVAL;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next 4/4] netns: enable to dump full nsid translation table
  2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
                   ` (2 preceding siblings ...)
  2018-11-21 11:01 ` [PATCH net-next 3/4] netns: enable to specify a nsid for a get request Nicolas Dichtel
@ 2018-11-21 11:01 ` Nicolas Dichtel
  2018-11-21 18:09   ` David Ahern
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
  4 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 11:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel

Like the previous patch, the goal is to ease to convert nsids from one
netns to another netns.
A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 30 ++++++++++++++++++++++++------
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0ed9dd61d32a..9f9956809565 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -17,6 +17,7 @@ enum {
 	NETNSA_PID,
 	NETNSA_FD,
 	NETNSA_TARGET_NSID,
+	NETNSA_CURRENT_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 92730905886c..fc568cd0b560 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -740,7 +740,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, int nsid)
+			 int cmd, int nsid, bool add_ref, int ref_nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -755,6 +755,9 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
 	if (nla_put_s32(skb, NETNSA_NSID, nsid))
 		goto nla_put_failure;
 
+	if (add_ref && nla_put_s32(skb, NETNSA_CURRENT_NSID, ref_nsid))
+		goto nla_put_failure;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
@@ -769,9 +772,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
 	struct net *peer, *target = net;
+	bool add_ref = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	int err, id;
+	int err, id, ref_id;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
 			  rtnl_net_policy, extack);
@@ -809,6 +813,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 			err = PTR_ERR(target);
 			goto put_peer;
 		}
+		ref_id = peernet2id(net, peer);
+		add_ref = true;
 	} else {
 		get_net(target);
 	}
@@ -821,7 +827,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, id);
+			    RTM_NEWNSID, id, add_ref, ref_id);
 	if (err < 0)
 		goto free_nlmsg;
 
@@ -849,14 +855,17 @@ struct rtnl_net_dump_cb {
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 {
 	struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
-	int ret;
+	int ref_id = 0, ret;
 
 	if (net_cb->idx < net_cb->s_idx)
 		goto cont;
 
+	if (net_cb->ref_net)
+		ref_id = __peernet2id(net_cb->ref_net, peer);
+
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, id);
+			    RTM_NEWNSID, id, net_cb->ref_net, ref_id);
 	if (ret < 0)
 		return ret;
 
@@ -923,7 +932,16 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	}
 
 	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	if (net_cb.ref_net &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
+	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
+		err = -EAGAIN;
+		goto end;
+	}
 	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	if (net_cb.ref_net &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
+		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
 	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
@@ -942,7 +960,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id, false, 0);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
  2018-11-21 11:01 ` [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-21 18:05   ` David Ahern
  2018-11-21 20:58     ` Nicolas Dichtel
  0 siblings, 1 reply; 39+ messages in thread
From: David Ahern @ 2018-11-21 18:05 UTC (permalink / raw)
  To: Nicolas Dichtel, davem; +Cc: netdev

On 11/21/18 4:01 AM, Nicolas Dichtel wrote:
>  static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
>  {
> -	struct net *net = sock_net(skb->sk);
>  	struct rtnl_net_dump_cb net_cb = {
> -		.net = net,
> +		.tgt_net = sock_net(skb->sk),
>  		.skb = skb,
>  		.cb = cb,
>  		.idx = 0,
>  		.s_idx = cb->args[0],
>  	};
> +	int err = 0;
>  
> -	if (cb->strict_check &&
> -	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
> -			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
> -			return -EINVAL;
> +	if (cb->strict_check) {
> +		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
> +		if (err < 0)
> +			goto end;
>  	}
>  
> -	spin_lock_bh(&net->nsid_lock);
> -	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
> -	spin_unlock_bh(&net->nsid_lock);
> +	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
> +	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
> +	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
>  
>  	cb->args[0] = net_cb.idx;
> -	return skb->len;
> +end:
> +	if (net_cb.ref_net)
> +		put_net(net_cb.tgt_net);

That is going to lead to confusion -- you check that ref_net is set put
do a put on tgt_net.  Other places using a target namespace use the nsid
as the key to whether a put_net is needed.


> +	return err < 0 ? err : skb->len;
>  }
>  
>  static void rtnl_net_notifyid(struct net *net, int cmd, int id)
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 4/4] netns: enable to dump full nsid translation table
  2018-11-21 11:01 ` [PATCH net-next 4/4] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-21 18:09   ` David Ahern
  2018-11-21 21:01     ` Nicolas Dichtel
  0 siblings, 1 reply; 39+ messages in thread
From: David Ahern @ 2018-11-21 18:09 UTC (permalink / raw)
  To: Nicolas Dichtel, davem; +Cc: netdev

On 11/21/18 4:01 AM, Nicolas Dichtel wrote:
> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
> index 92730905886c..fc568cd0b560 100644
> --- a/net/core/net_namespace.c
> +++ b/net/core/net_namespace.c
> @@ -740,7 +740,7 @@ static int rtnl_net_get_size(void)
>  }
>  
>  static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
> -			 int cmd, int nsid)
> +			 int cmd, int nsid, bool add_ref, int ref_nsid)
>  {
>  	struct nlmsghdr *nlh;
>  	struct rtgenmsg *rth;
> @@ -755,6 +755,9 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
>  	if (nla_put_s32(skb, NETNSA_NSID, nsid))
>  		goto nla_put_failure;
>  
> +	if (add_ref && nla_put_s32(skb, NETNSA_CURRENT_NSID, ref_nsid))
> +		goto nla_put_failure;

Why not use ref_nsid >= 0 and drop the add_ref argument?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
  2018-11-21 18:05   ` David Ahern
@ 2018-11-21 20:58     ` Nicolas Dichtel
  2018-11-21 21:07       ` David Ahern
  0 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 20:58 UTC (permalink / raw)
  To: David Ahern, davem; +Cc: netdev

Le 21/11/2018 à 19:05, David Ahern a écrit :
> On 11/21/18 4:01 AM, Nicolas Dichtel wrote:
>>  static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
>>  {
>> -	struct net *net = sock_net(skb->sk);
>>  	struct rtnl_net_dump_cb net_cb = {
>> -		.net = net,
>> +		.tgt_net = sock_net(skb->sk),
>>  		.skb = skb,
>>  		.cb = cb,
>>  		.idx = 0,
>>  		.s_idx = cb->args[0],
>>  	};
>> +	int err = 0;
>>  
>> -	if (cb->strict_check &&
>> -	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
>> -			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
>> -			return -EINVAL;
>> +	if (cb->strict_check) {
>> +		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
>> +		if (err < 0)
>> +			goto end;
>>  	}
>>  
>> -	spin_lock_bh(&net->nsid_lock);
>> -	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
>> -	spin_unlock_bh(&net->nsid_lock);
>> +	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
>> +	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
>> +	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
>>  
>>  	cb->args[0] = net_cb.idx;
>> -	return skb->len;
>> +end:
>> +	if (net_cb.ref_net)
>> +		put_net(net_cb.tgt_net);
> 
> That is going to lead to confusion -- you check that ref_net is set put
> do a put on tgt_net.  Other places using a target namespace use the nsid
> as the key to whether a put_net is needed.
The target-nsid is not stored in net_cb (not needed). ref_net is set only if
tgt_net comes from TARGET_NSID. I can add a comment.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 4/4] netns: enable to dump full nsid translation table
  2018-11-21 18:09   ` David Ahern
@ 2018-11-21 21:01     ` Nicolas Dichtel
  2018-11-21 21:08       ` David Ahern
  0 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-21 21:01 UTC (permalink / raw)
  To: David Ahern, davem; +Cc: netdev

Le 21/11/2018 à 19:09, David Ahern a écrit :
> On 11/21/18 4:01 AM, Nicolas Dichtel wrote:
>> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
>> index 92730905886c..fc568cd0b560 100644
>> --- a/net/core/net_namespace.c
>> +++ b/net/core/net_namespace.c
>> @@ -740,7 +740,7 @@ static int rtnl_net_get_size(void)
>>  }
>>  
>>  static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
>> -			 int cmd, int nsid)
>> +			 int cmd, int nsid, bool add_ref, int ref_nsid)
>>  {
>>  	struct nlmsghdr *nlh;
>>  	struct rtgenmsg *rth;
>> @@ -755,6 +755,9 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
>>  	if (nla_put_s32(skb, NETNSA_NSID, nsid))
>>  		goto nla_put_failure;
>>  
>> +	if (add_ref && nla_put_s32(skb, NETNSA_CURRENT_NSID, ref_nsid))
>> +		goto nla_put_failure;
> 
> Why not use ref_nsid >= 0 and drop the add_ref argument?
Because ref_nsid can be -1 (NETNSA_NSID_NOT_ASSIGNED) and I didn't want to add
another magic, I think it's clearer with an explicit bool.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
  2018-11-21 20:58     ` Nicolas Dichtel
@ 2018-11-21 21:07       ` David Ahern
  2018-11-22  8:06         ` Nicolas Dichtel
  0 siblings, 1 reply; 39+ messages in thread
From: David Ahern @ 2018-11-21 21:07 UTC (permalink / raw)
  To: nicolas.dichtel, davem; +Cc: netdev

On 11/21/18 1:58 PM, Nicolas Dichtel wrote:
> The target-nsid is not stored in net_cb (not needed). ref_net is set only if
> tgt_net comes from TARGET_NSID. I can add a comment.

ref_net is added by this patch and it is only used (unless I missed
something) to know if the put_net is needed. ie/, drop ref_net in place
of nsid

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 4/4] netns: enable to dump full nsid translation table
  2018-11-21 21:01     ` Nicolas Dichtel
@ 2018-11-21 21:08       ` David Ahern
  0 siblings, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-21 21:08 UTC (permalink / raw)
  To: nicolas.dichtel, davem; +Cc: netdev

On 11/21/18 2:01 PM, Nicolas Dichtel wrote:
> Le 21/11/2018 à 19:09, David Ahern a écrit :
>> On 11/21/18 4:01 AM, Nicolas Dichtel wrote:
>>> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
>>> index 92730905886c..fc568cd0b560 100644
>>> --- a/net/core/net_namespace.c
>>> +++ b/net/core/net_namespace.c
>>> @@ -740,7 +740,7 @@ static int rtnl_net_get_size(void)
>>>  }
>>>  
>>>  static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
>>> -			 int cmd, int nsid)
>>> +			 int cmd, int nsid, bool add_ref, int ref_nsid)
>>>  {
>>>  	struct nlmsghdr *nlh;
>>>  	struct rtgenmsg *rth;
>>> @@ -755,6 +755,9 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
>>>  	if (nla_put_s32(skb, NETNSA_NSID, nsid))
>>>  		goto nla_put_failure;
>>>  
>>> +	if (add_ref && nla_put_s32(skb, NETNSA_CURRENT_NSID, ref_nsid))
>>> +		goto nla_put_failure;
>>
>> Why not use ref_nsid >= 0 and drop the add_ref argument?
> Because ref_nsid can be -1 (NETNSA_NSID_NOT_ASSIGNED) and I didn't want to add
> another magic, I think it's clearer with an explicit bool.
> 

it pushes the input args to 8.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID
  2018-11-21 21:07       ` David Ahern
@ 2018-11-22  8:06         ` Nicolas Dichtel
  0 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22  8:06 UTC (permalink / raw)
  To: David Ahern, davem; +Cc: netdev

Le 21/11/2018 à 22:07, David Ahern a écrit :
> On 11/21/18 1:58 PM, Nicolas Dichtel wrote:
>> The target-nsid is not stored in net_cb (not needed). ref_net is set only if
>> tgt_net comes from TARGET_NSID. I can add a comment.
> 
> ref_net is added by this patch and it is only used (unless I missed
> something) to know if the put_net is needed. ie/, drop ref_net in place
> of nsid
It is used by a following patch (4/4) to get NETNSA_CURRENT_NSID.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 0/5] Ease to interpret net-nsid
  2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
                   ` (3 preceding siblings ...)
  2018-11-21 11:01 ` [PATCH net-next 4/4] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-22 15:50 ` Nicolas Dichtel
  2018-11-22 15:50   ` [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
                     ` (5 more replies)
  4 siblings, 6 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem

The goal of this series is to ease the interpretation of nsid received in
netlink messages from other netns (when the user uses
NETLINK_F_LISTEN_ALL_NSID).

After this series, with a patched iproute2:

$ ip netns add foo
$ ip netns add bar
$ touch /var/run/netns/init_net
$ mount --bind /proc/1/ns/net /var/run/netns/init_net
$ ip netns set init_net 11
$ ip netns set foo 12
$ ip netns set bar 13
$ ip netns
init_net (id: 11)
bar (id: 13)
foo (id: 12)
$ ip -n foo netns set init_net 21
$ ip -n foo netns set foo 22
$ ip -n foo netns set bar 23
$ ip -n foo netns
init_net (id: 21)
bar (id: 23)
foo (id: 22)
$ ip -n bar netns set init_net 31
$ ip -n bar netns set foo 32
$ ip -n bar netns set bar 33
$ ip -n bar netns
init_net (id: 31)
bar (id: 33)
foo (id: 32)
$ ip netns list-id target-nsid 12
nsid 21 current-nsid 11 (iproute2 netns name: init_net)
nsid 22 current-nsid 12 (iproute2 netns name: foo)
nsid 23 current-nsid 13 (iproute2 netns name: bar)
$ ip -n bar netns list-id target-nsid 32 nsid 31
nsid 21 current-nsid 31 (iproute2 netns name: init_net)

v1 -> v2:
  - patch 1/5: remove net from struct rtnl_net_dump_cb
  - patch 2/5: new in this version
  - patch 3/5: use a bool to know if rtnl_get_net_ns_capable() was called
  - patch 5/5: use struct net_fill_args

 include/uapi/linux/net_namespace.h |   2 +
 net/core/net_namespace.c           | 157 +++++++++++++++++++++++++++++++------
 2 files changed, 133 insertions(+), 26 deletions(-)

Comments are welcomed,
Regards,
Nicolas

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill()
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
@ 2018-11-22 15:50   ` Nicolas Dichtel
  2018-11-22 16:18     ` David Ahern
  2018-11-22 15:50   ` [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This argument is not used anymore.

Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index fefe72774aeb..52b9620e3457 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -739,7 +739,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, struct net *net, int nsid)
+			 int cmd, int nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -801,7 +801,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(net, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, net, id);
+			    RTM_NEWNSID, id);
 	if (err < 0)
 		goto err_out;
 
@@ -816,7 +816,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 struct rtnl_net_dump_cb {
-	struct net *net;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 	int idx;
@@ -833,7 +832,7 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, net_cb->net, id);
+			    RTM_NEWNSID, id);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +845,6 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
-		.net = net,
 		.skb = skb,
 		.cb = cb,
 		.idx = 0,
@@ -876,7 +874,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args'
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-22 15:50   ` [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
@ 2018-11-22 15:50   ` Nicolas Dichtel
  2018-11-22 16:23     ` David Ahern
  2018-11-22 15:50   ` [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This is a preparatory work. To avoid having to much arguments for the
function rtnl_net_fill(), a new structure is defined.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 48 ++++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 52b9620e3457..f8a5966b086c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -738,20 +738,28 @@ static int rtnl_net_get_size(void)
 	       ;
 }
 
-static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, int nsid)
+struct net_fill_args {
+	u32 portid;
+	u32 seq;
+	int flags;
+	int cmd;
+	int nsid;
+};
+
+static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
 
-	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rth), flags);
+	nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth),
+			args->flags);
 	if (!nlh)
 		return -EMSGSIZE;
 
 	rth = nlmsg_data(nlh);
 	rth->rtgen_family = AF_UNSPEC;
 
-	if (nla_put_s32(skb, NETNSA_NSID, nsid))
+	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
 	nlmsg_end(skb, nlh);
@@ -767,10 +775,15 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
+	struct net_fill_args fillargs = {
+		.portid = NETLINK_CB(skb).portid,
+		.seq = nlh->nlmsg_seq,
+		.cmd = RTM_NEWNSID,
+	};
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	struct net *peer;
-	int err, id;
+	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
 			  rtnl_net_policy, extack);
@@ -799,9 +812,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		goto out;
 	}
 
-	id = peernet2id(net, peer);
-	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, id);
+	fillargs.nsid = peernet2id(net, peer);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
@@ -817,7 +829,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct sk_buff *skb;
-	struct netlink_callback *cb;
+	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
 };
@@ -830,9 +842,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	if (net_cb->idx < net_cb->s_idx)
 		goto cont;
 
-	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
-			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, id);
+	net_cb->fillargs.nsid = id;
+	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +857,12 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
 		.skb = skb,
-		.cb = cb,
+		.fillargs = {
+			.portid = NETLINK_CB(cb->skb).portid,
+			.seq = cb->nlh->nlmsg_seq,
+			.flags = NLM_F_MULTI,
+			.cmd = RTM_NEWNSID,
+		},
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
@@ -867,6 +883,10 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 {
+	struct net_fill_args fillargs = {
+		.cmd = cmd,
+		.nsid = id,
+	};
 	struct sk_buff *msg;
 	int err = -ENOMEM;
 
@@ -874,7 +894,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-22 15:50   ` [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
  2018-11-22 15:50   ` [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
@ 2018-11-22 15:50   ` Nicolas Dichtel
  2018-11-22 16:32     ` David Ahern
  2018-11-22 15:50   ` [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like it was done for link and address, add the ability to perform get/dump
in another netns by specifying a target nsid attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 86 ++++++++++++++++++++++++++----
 2 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0187c74d8889..0ed9dd61d32a 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
 	NETNSA_NSID,
 	NETNSA_PID,
 	NETNSA_FD,
+	NETNSA_TARGET_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f8a5966b086c..885c54197e31 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
 	[NETNSA_NSID]		= { .type = NLA_S32 },
 	[NETNSA_PID]		= { .type = NLA_U32 },
 	[NETNSA_FD]		= { .type = NLA_U32 },
+	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
 };
 
 static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -780,9 +781,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.seq = nlh->nlmsg_seq,
 		.cmd = RTM_NEWNSID,
 	};
+	struct net *peer, *target = net;
+	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	struct net *peer;
 	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -806,13 +808,27 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return PTR_ERR(peer);
 	}
 
+	if (tb[NETNSA_TARGET_NSID]) {
+		int id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
+
+		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
+		if (IS_ERR(target)) {
+			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
+			NL_SET_ERR_MSG(extack,
+				       "Target netns reference is invalid");
+			err = PTR_ERR(target);
+			goto out;
+		}
+		put_target = true;
+	}
+
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
 	if (!msg) {
 		err = -ENOMEM;
 		goto out;
 	}
 
-	fillargs.nsid = peernet2id(net, peer);
+	fillargs.nsid = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
@@ -823,15 +839,19 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
+	if (put_target)
+		put_net(target);
 	put_net(peer);
 	return err;
 }
 
 struct rtnl_net_dump_cb {
+	struct net *tgt_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
+	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -852,10 +872,50 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	return 0;
 }
 
+static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
+				   struct rtnl_net_dump_cb *net_cb,
+				   struct netlink_callback *cb)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	struct nlattr *tb[NETNSA_MAX + 1];
+	int err, i;
+
+	err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
+				 rtnl_net_policy, extack);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i <= NETNSA_MAX; i++) {
+		if (!tb[i])
+			continue;
+
+		if (i == NETNSA_TARGET_NSID) {
+			struct net *net;
+
+			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
+			if (IS_ERR(net)) {
+				NL_SET_BAD_ATTR(extack, tb[i]);
+				NL_SET_ERR_MSG(extack,
+					       "Invalid target network namespace id");
+				return PTR_ERR(net);
+			}
+			net_cb->tgt_net = net;
+			net_cb->put_tgt_net = true;
+		} else {
+			NL_SET_BAD_ATTR(extack, tb[i]);
+			NL_SET_ERR_MSG(extack,
+				       "Unsupported attribute in dump request");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
+		.tgt_net = sock_net(skb->sk),
 		.skb = skb,
 		.fillargs = {
 			.portid = NETLINK_CB(cb->skb).portid,
@@ -866,19 +926,23 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
+	int err = 0;
 
-	if (cb->strict_check &&
-	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
-			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
-			return -EINVAL;
+	if (cb->strict_check) {
+		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
+		if (err < 0)
+			goto end;
 	}
 
-	spin_lock_bh(&net->nsid_lock);
-	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-	spin_unlock_bh(&net->nsid_lock);
+	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
-	return skb->len;
+end:
+	if (net_cb.put_tgt_net)
+		put_net(net_cb.tgt_net);
+	return err < 0 ? err : skb->len;
 }
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
                     ` (2 preceding siblings ...)
  2018-11-22 15:50   ` [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-22 15:50   ` Nicolas Dichtel
  2018-11-22 16:32     ` David Ahern
  2018-11-22 15:50   ` [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
  5 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
netns to a nsid of another netns.
This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
user to interpret a nsid received from an other netns.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/core/net_namespace.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 885c54197e31..dd25fb22ad45 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -797,6 +797,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	} else if (tb[NETNSA_FD]) {
 		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
 		nla = tb[NETNSA_FD];
+	} else if (tb[NETNSA_NSID]) {
+		peer = get_net_ns_by_id(net, nla_get_u32(tb[NETNSA_NSID]));
+		if (!peer)
+			peer = ERR_PTR(-ENOENT);
+		nla = tb[NETNSA_NSID];
 	} else {
 		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
 		return -EINVAL;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
                     ` (3 preceding siblings ...)
  2018-11-22 15:50   ` [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
@ 2018-11-22 15:50   ` Nicolas Dichtel
  2018-11-22 16:40     ` David Ahern
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
  5 siblings, 1 reply; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 15:50 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like the previous patch, the goal is to ease to convert nsids from one
netns to another netns.
A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 30 ++++++++++++++++++++++++------
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0ed9dd61d32a..9f9956809565 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -17,6 +17,7 @@ enum {
 	NETNSA_PID,
 	NETNSA_FD,
 	NETNSA_TARGET_NSID,
+	NETNSA_CURRENT_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index dd25fb22ad45..25030e0317a2 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -745,6 +745,8 @@ struct net_fill_args {
 	int flags;
 	int cmd;
 	int nsid;
+	bool add_ref;
+	int ref_nsid;
 };
 
 static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
@@ -763,6 +765,10 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
+	if (args->add_ref &&
+	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
+		goto nla_put_failure;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
@@ -782,7 +788,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.cmd = RTM_NEWNSID,
 	};
 	struct net *peer, *target = net;
-	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	int err;
@@ -824,7 +829,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 			err = PTR_ERR(target);
 			goto out;
 		}
-		put_target = true;
+		fillargs.add_ref = true;
+		fillargs.ref_nsid = peernet2id(net, peer);
 	}
 
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
@@ -844,7 +850,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
-	if (put_target)
+	if (fillargs.add_ref)
 		put_net(target);
 	put_net(peer);
 	return err;
@@ -852,11 +858,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct net *tgt_net;
+	struct net *ref_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
-	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -868,6 +874,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 		goto cont;
 
 	net_cb->fillargs.nsid = id;
+	if (net_cb->fillargs.add_ref)
+		net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer);
 	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
@@ -904,8 +912,9 @@ static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
 					       "Invalid target network namespace id");
 				return PTR_ERR(net);
 			}
+			net_cb->fillargs.add_ref = true;
+			net_cb->ref_net = net_cb->tgt_net;
 			net_cb->tgt_net = net;
-			net_cb->put_tgt_net = true;
 		} else {
 			NL_SET_BAD_ATTR(extack, tb[i]);
 			NL_SET_ERR_MSG(extack,
@@ -940,12 +949,21 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	}
 
 	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
+	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
+		err = -EAGAIN;
+		goto end;
+	}
 	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
+		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
 	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
 end:
-	if (net_cb.put_tgt_net)
+	if (net_cb.fillargs.add_ref)
 		put_net(net_cb.tgt_net);
 	return err < 0 ? err : skb->len;
 }
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill()
  2018-11-22 15:50   ` [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
@ 2018-11-22 16:18     ` David Ahern
  0 siblings, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-22 16:18 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
> This argument is not used anymore.
> 
> Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  net/core/net_namespace.c | 10 ++++------
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 

Reviewed-by: David Ahern <dsahern@gmail.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args'
  2018-11-22 15:50   ` [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
@ 2018-11-22 16:23     ` David Ahern
  0 siblings, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-22 16:23 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
> This is a preparatory work. To avoid having to much arguments for the
> function rtnl_net_fill(), a new structure is defined.
> 
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  net/core/net_namespace.c | 48 ++++++++++++++++++++++++++++------------
>  1 file changed, 34 insertions(+), 14 deletions(-)
> 

Reviewed-by: David Ahern <dsahern@gmail.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID
  2018-11-22 15:50   ` [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-22 16:32     ` David Ahern
  0 siblings, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-22 16:32 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
> Like it was done for link and address, add the ability to perform get/dump
> in another netns by specifying a target nsid attribute.
> 
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  include/uapi/linux/net_namespace.h |  1 +
>  net/core/net_namespace.c           | 86 ++++++++++++++++++++++++++----
>  2 files changed, 76 insertions(+), 11 deletions(-)

Reviewed-by: David Ahern <dsahern@gmail.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request
  2018-11-22 15:50   ` [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
@ 2018-11-22 16:32     ` David Ahern
  0 siblings, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-22 16:32 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
> Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
> netns to a nsid of another netns.
> This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
> user to interpret a nsid received from an other netns.
> 
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  net/core/net_namespace.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 

Reviewed-by: David Ahern <dsahern@gmail.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table
  2018-11-22 15:50   ` [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-22 16:40     ` David Ahern
  2018-11-22 16:42       ` Nicolas Dichtel
  0 siblings, 1 reply; 39+ messages in thread
From: David Ahern @ 2018-11-22 16:40 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
> index dd25fb22ad45..25030e0317a2 100644
> --- a/net/core/net_namespace.c
> +++ b/net/core/net_namespace.c
> @@ -745,6 +745,8 @@ struct net_fill_args {
>  	int flags;
>  	int cmd;
>  	int nsid;
> +	bool add_ref;
> +	int ref_nsid;
>  };
>  
>  static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
> @@ -763,6 +765,10 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
>  	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
>  		goto nla_put_failure;
>  
> +	if (args->add_ref &&
> +	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
> +		goto nla_put_failure;
> +

you need to add NETNSA_CURRENT_NSID to rtnl_net_get_size.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table
  2018-11-22 16:40     ` David Ahern
@ 2018-11-22 16:42       ` Nicolas Dichtel
  0 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 16:42 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, davem

Le 22/11/2018 à 17:40, David Ahern a écrit :
> On 11/22/18 8:50 AM, Nicolas Dichtel wrote:
>> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
>> index dd25fb22ad45..25030e0317a2 100644
>> --- a/net/core/net_namespace.c
>> +++ b/net/core/net_namespace.c
>> @@ -745,6 +745,8 @@ struct net_fill_args {
>>  	int flags;
>>  	int cmd;
>>  	int nsid;
>> +	bool add_ref;
>> +	int ref_nsid;
>>  };
>>  
>>  static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
>> @@ -763,6 +765,10 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
>>  	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
>>  		goto nla_put_failure;
>>  
>> +	if (args->add_ref &&
>> +	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
>> +		goto nla_put_failure;
>> +
> 
> you need to add NETNSA_CURRENT_NSID to rtnl_net_get_size.
> 
Good catch.
I thought to this and I forgot at the end :/

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 0/5] Ease to interpret net-nsid
  2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
                     ` (4 preceding siblings ...)
  2018-11-22 15:50   ` [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-22 22:22   ` Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
                       ` (5 more replies)
  5 siblings, 6 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem


The goal of this series is to ease the interpretation of nsid received in
netlink messages from other netns (when the user uses
NETLINK_F_LISTEN_ALL_NSID).

After this series, with a patched iproute2:

$ ip netns add foo
$ ip netns add bar
$ touch /var/run/netns/init_net
$ mount --bind /proc/1/ns/net /var/run/netns/init_net
$ ip netns set init_net 11
$ ip netns set foo 12
$ ip netns set bar 13
$ ip netns
init_net (id: 11)
bar (id: 13)
foo (id: 12)
$ ip -n foo netns set init_net 21
$ ip -n foo netns set foo 22
$ ip -n foo netns set bar 23
$ ip -n foo netns
init_net (id: 21)
bar (id: 23)
foo (id: 22)
$ ip -n bar netns set init_net 31
$ ip -n bar netns set foo 32
$ ip -n bar netns set bar 33
$ ip -n bar netns
init_net (id: 31)
bar (id: 33)
foo (id: 32)
$ ip netns list-id target-nsid 12
nsid 21 current-nsid 11 (iproute2 netns name: init_net)
nsid 22 current-nsid 12 (iproute2 netns name: foo)
nsid 23 current-nsid 13 (iproute2 netns name: bar)
$ ip -n bar netns list-id target-nsid 32 nsid 31
nsid 21 current-nsid 31 (iproute2 netns name: init_net)

v2 -> v3:
  - patch 5/5: account NETNSA_CURRENT_NSID in rtnl_net_get_size()

v1 -> v2:
  - patch 1/5: remove net from struct rtnl_net_dump_cb
  - patch 2/5: new in this version
  - patch 3/5: use a bool to know if rtnl_get_net_ns_capable() was called
  - patch 5/5: use struct net_fill_args

 include/uapi/linux/net_namespace.h |   2 +
 net/core/net_namespace.c           | 158 +++++++++++++++++++++++++++++++------
 2 files changed, 134 insertions(+), 26 deletions(-)

Comments are welcomed,
Regards,
Nicolas

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 1/5] netns: remove net arg from rtnl_net_fill()
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
@ 2018-11-22 22:22     ` Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This argument is not used anymore.

Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index fefe72774aeb..52b9620e3457 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -739,7 +739,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, struct net *net, int nsid)
+			 int cmd, int nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -801,7 +801,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(net, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, net, id);
+			    RTM_NEWNSID, id);
 	if (err < 0)
 		goto err_out;
 
@@ -816,7 +816,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 struct rtnl_net_dump_cb {
-	struct net *net;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 	int idx;
@@ -833,7 +832,7 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, net_cb->net, id);
+			    RTM_NEWNSID, id);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +845,6 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
-		.net = net,
 		.skb = skb,
 		.cb = cb,
 		.idx = 0,
@@ -876,7 +874,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 2/5] netns: introduce 'struct net_fill_args'
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
@ 2018-11-22 22:22     ` Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
                       ` (3 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This is a preparatory work. To avoid having to much arguments for the
function rtnl_net_fill(), a new structure is defined.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 48 ++++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 52b9620e3457..f8a5966b086c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -738,20 +738,28 @@ static int rtnl_net_get_size(void)
 	       ;
 }
 
-static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, int nsid)
+struct net_fill_args {
+	u32 portid;
+	u32 seq;
+	int flags;
+	int cmd;
+	int nsid;
+};
+
+static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
 
-	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rth), flags);
+	nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth),
+			args->flags);
 	if (!nlh)
 		return -EMSGSIZE;
 
 	rth = nlmsg_data(nlh);
 	rth->rtgen_family = AF_UNSPEC;
 
-	if (nla_put_s32(skb, NETNSA_NSID, nsid))
+	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
 	nlmsg_end(skb, nlh);
@@ -767,10 +775,15 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
+	struct net_fill_args fillargs = {
+		.portid = NETLINK_CB(skb).portid,
+		.seq = nlh->nlmsg_seq,
+		.cmd = RTM_NEWNSID,
+	};
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	struct net *peer;
-	int err, id;
+	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
 			  rtnl_net_policy, extack);
@@ -799,9 +812,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		goto out;
 	}
 
-	id = peernet2id(net, peer);
-	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, id);
+	fillargs.nsid = peernet2id(net, peer);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
@@ -817,7 +829,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct sk_buff *skb;
-	struct netlink_callback *cb;
+	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
 };
@@ -830,9 +842,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	if (net_cb->idx < net_cb->s_idx)
 		goto cont;
 
-	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
-			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, id);
+	net_cb->fillargs.nsid = id;
+	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +857,12 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
 		.skb = skb,
-		.cb = cb,
+		.fillargs = {
+			.portid = NETLINK_CB(cb->skb).portid,
+			.seq = cb->nlh->nlmsg_seq,
+			.flags = NLM_F_MULTI,
+			.cmd = RTM_NEWNSID,
+		},
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
@@ -867,6 +883,10 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 {
+	struct net_fill_args fillargs = {
+		.cmd = cmd,
+		.nsid = id,
+	};
 	struct sk_buff *msg;
 	int err = -ENOMEM;
 
@@ -874,7 +894,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 3/5] netns: add support of NETNSA_TARGET_NSID
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
@ 2018-11-22 22:22     ` Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like it was done for link and address, add the ability to perform get/dump
in another netns by specifying a target nsid attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 86 ++++++++++++++++++++++++++----
 2 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0187c74d8889..0ed9dd61d32a 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
 	NETNSA_NSID,
 	NETNSA_PID,
 	NETNSA_FD,
+	NETNSA_TARGET_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f8a5966b086c..885c54197e31 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
 	[NETNSA_NSID]		= { .type = NLA_S32 },
 	[NETNSA_PID]		= { .type = NLA_U32 },
 	[NETNSA_FD]		= { .type = NLA_U32 },
+	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
 };
 
 static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -780,9 +781,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.seq = nlh->nlmsg_seq,
 		.cmd = RTM_NEWNSID,
 	};
+	struct net *peer, *target = net;
+	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	struct net *peer;
 	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -806,13 +808,27 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return PTR_ERR(peer);
 	}
 
+	if (tb[NETNSA_TARGET_NSID]) {
+		int id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
+
+		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
+		if (IS_ERR(target)) {
+			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
+			NL_SET_ERR_MSG(extack,
+				       "Target netns reference is invalid");
+			err = PTR_ERR(target);
+			goto out;
+		}
+		put_target = true;
+	}
+
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
 	if (!msg) {
 		err = -ENOMEM;
 		goto out;
 	}
 
-	fillargs.nsid = peernet2id(net, peer);
+	fillargs.nsid = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
@@ -823,15 +839,19 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
+	if (put_target)
+		put_net(target);
 	put_net(peer);
 	return err;
 }
 
 struct rtnl_net_dump_cb {
+	struct net *tgt_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
+	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -852,10 +872,50 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	return 0;
 }
 
+static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
+				   struct rtnl_net_dump_cb *net_cb,
+				   struct netlink_callback *cb)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	struct nlattr *tb[NETNSA_MAX + 1];
+	int err, i;
+
+	err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
+				 rtnl_net_policy, extack);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i <= NETNSA_MAX; i++) {
+		if (!tb[i])
+			continue;
+
+		if (i == NETNSA_TARGET_NSID) {
+			struct net *net;
+
+			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
+			if (IS_ERR(net)) {
+				NL_SET_BAD_ATTR(extack, tb[i]);
+				NL_SET_ERR_MSG(extack,
+					       "Invalid target network namespace id");
+				return PTR_ERR(net);
+			}
+			net_cb->tgt_net = net;
+			net_cb->put_tgt_net = true;
+		} else {
+			NL_SET_BAD_ATTR(extack, tb[i]);
+			NL_SET_ERR_MSG(extack,
+				       "Unsupported attribute in dump request");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
+		.tgt_net = sock_net(skb->sk),
 		.skb = skb,
 		.fillargs = {
 			.portid = NETLINK_CB(cb->skb).portid,
@@ -866,19 +926,23 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
+	int err = 0;
 
-	if (cb->strict_check &&
-	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
-			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
-			return -EINVAL;
+	if (cb->strict_check) {
+		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
+		if (err < 0)
+			goto end;
 	}
 
-	spin_lock_bh(&net->nsid_lock);
-	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-	spin_unlock_bh(&net->nsid_lock);
+	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
-	return skb->len;
+end:
+	if (net_cb.put_tgt_net)
+		put_net(net_cb.tgt_net);
+	return err < 0 ? err : skb->len;
 }
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 4/5] netns: enable to specify a nsid for a get request
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
                       ` (2 preceding siblings ...)
  2018-11-22 22:22     ` [PATCH net-next v3 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-22 22:22     ` Nicolas Dichtel
  2018-11-22 22:22     ` [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
netns to a nsid of another netns.
This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
user to interpret a nsid received from an other netns.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 885c54197e31..dd25fb22ad45 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -797,6 +797,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	} else if (tb[NETNSA_FD]) {
 		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
 		nla = tb[NETNSA_FD];
+	} else if (tb[NETNSA_NSID]) {
+		peer = get_net_ns_by_id(net, nla_get_u32(tb[NETNSA_NSID]));
+		if (!peer)
+			peer = ERR_PTR(-ENOENT);
+		nla = tb[NETNSA_NSID];
 	} else {
 		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
 		return -EINVAL;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
                       ` (3 preceding siblings ...)
  2018-11-22 22:22     ` [PATCH net-next v3 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
@ 2018-11-22 22:22     ` Nicolas Dichtel
  2018-11-24 15:47       ` David Ahern
  2018-11-26 10:06       ` kbuild test robot
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
  5 siblings, 2 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-22 22:22 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like the previous patch, the goal is to ease to convert nsids from one
netns to another netns.
A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 31 ++++++++++++++++++++++++------
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0ed9dd61d32a..9f9956809565 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -17,6 +17,7 @@ enum {
 	NETNSA_PID,
 	NETNSA_FD,
 	NETNSA_TARGET_NSID,
+	NETNSA_CURRENT_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index dd25fb22ad45..2f25d7f2a43b 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -736,6 +736,7 @@ static int rtnl_net_get_size(void)
 {
 	return NLMSG_ALIGN(sizeof(struct rtgenmsg))
 	       + nla_total_size(sizeof(s32)) /* NETNSA_NSID */
+	       + nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */
 	       ;
 }
 
@@ -745,6 +746,8 @@ struct net_fill_args {
 	int flags;
 	int cmd;
 	int nsid;
+	bool add_ref;
+	int ref_nsid;
 };
 
 static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
@@ -763,6 +766,10 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
+	if (args->add_ref &&
+	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
+		goto nla_put_failure;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
@@ -782,7 +789,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.cmd = RTM_NEWNSID,
 	};
 	struct net *peer, *target = net;
-	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	int err;
@@ -824,7 +830,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 			err = PTR_ERR(target);
 			goto out;
 		}
-		put_target = true;
+		fillargs.add_ref = true;
+		fillargs.ref_nsid = peernet2id(net, peer);
 	}
 
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
@@ -844,7 +851,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
-	if (put_target)
+	if (fillargs.add_ref)
 		put_net(target);
 	put_net(peer);
 	return err;
@@ -852,11 +859,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct net *tgt_net;
+	struct net *ref_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
-	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -868,6 +875,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 		goto cont;
 
 	net_cb->fillargs.nsid = id;
+	if (net_cb->fillargs.add_ref)
+		net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer);
 	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
@@ -904,8 +913,9 @@ static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
 					       "Invalid target network namespace id");
 				return PTR_ERR(net);
 			}
+			net_cb->fillargs.add_ref = true;
+			net_cb->ref_net = net_cb->tgt_net;
 			net_cb->tgt_net = net;
-			net_cb->put_tgt_net = true;
 		} else {
 			NL_SET_BAD_ATTR(extack, tb[i]);
 			NL_SET_ERR_MSG(extack,
@@ -940,12 +950,21 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	}
 
 	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
+	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
+		err = -EAGAIN;
+		goto end;
+	}
 	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
+		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
 	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
 end:
-	if (net_cb.put_tgt_net)
+	if (net_cb.fillargs.add_ref)
 		put_net(net_cb.tgt_net);
 	return err < 0 ? err : skb->len;
 }
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table
  2018-11-22 22:22     ` [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-24 15:47       ` David Ahern
  2018-11-26 10:06       ` kbuild test robot
  1 sibling, 0 replies; 39+ messages in thread
From: David Ahern @ 2018-11-24 15:47 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: netdev, davem

On 11/22/18 3:22 PM, Nicolas Dichtel wrote:
> Like the previous patch, the goal is to ease to convert nsids from one
> netns to another netns.
> A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
> NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.
> 
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
>  include/uapi/linux/net_namespace.h |  1 +
>  net/core/net_namespace.c           | 31 ++++++++++++++++++++++++------
>  2 files changed, 26 insertions(+), 6 deletions(-)
> 


Reviewed-by: David Ahern <dsahern@gmail.com>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table
  2018-11-22 22:22     ` [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
  2018-11-24 15:47       ` David Ahern
@ 2018-11-26 10:06       ` kbuild test robot
  1 sibling, 0 replies; 39+ messages in thread
From: kbuild test robot @ 2018-11-26 10:06 UTC (permalink / raw)
  To: Nicolas Dichtel; +Cc: kbuild-all, dsahern, netdev, davem, Nicolas Dichtel

[-- Attachment #1: Type: text/plain, Size: 4062 bytes --]

Hi Nicolas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Nicolas-Dichtel/netns-remove-net-arg-from-rtnl_net_fill/20181126-035032
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   include/linux/slab.h:332:43: warning: dubious: x & !y
   include/linux/slab.h:332:43: warning: dubious: x & !y
>> net/core/net_namespace.c:963:23: warning: context imbalance in 'rtnl_net_dumpid' - different lock contexts for basic block

vim +/rtnl_net_dumpid +963 net/core/net_namespace.c

5589651eb Nicolas Dichtel 2018-11-22  929  
a143c40c3 Nicolas Dichtel 2015-04-07  930  static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
a143c40c3 Nicolas Dichtel 2015-04-07  931  {
a143c40c3 Nicolas Dichtel 2015-04-07  932  	struct rtnl_net_dump_cb net_cb = {
5589651eb Nicolas Dichtel 2018-11-22  933  		.tgt_net = sock_net(skb->sk),
a143c40c3 Nicolas Dichtel 2015-04-07  934  		.skb = skb,
70955fc94 Nicolas Dichtel 2018-11-22  935  		.fillargs = {
70955fc94 Nicolas Dichtel 2018-11-22  936  			.portid = NETLINK_CB(cb->skb).portid,
70955fc94 Nicolas Dichtel 2018-11-22  937  			.seq = cb->nlh->nlmsg_seq,
70955fc94 Nicolas Dichtel 2018-11-22  938  			.flags = NLM_F_MULTI,
70955fc94 Nicolas Dichtel 2018-11-22  939  			.cmd = RTM_NEWNSID,
70955fc94 Nicolas Dichtel 2018-11-22  940  		},
a143c40c3 Nicolas Dichtel 2015-04-07  941  		.idx = 0,
a143c40c3 Nicolas Dichtel 2015-04-07  942  		.s_idx = cb->args[0],
a143c40c3 Nicolas Dichtel 2015-04-07  943  	};
5589651eb Nicolas Dichtel 2018-11-22  944  	int err = 0;
a143c40c3 Nicolas Dichtel 2015-04-07  945  
5589651eb Nicolas Dichtel 2018-11-22  946  	if (cb->strict_check) {
5589651eb Nicolas Dichtel 2018-11-22  947  		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
5589651eb Nicolas Dichtel 2018-11-22  948  		if (err < 0)
5589651eb Nicolas Dichtel 2018-11-22  949  			goto end;
f80f14c36 David Ahern     2018-10-07  950  	}
f80f14c36 David Ahern     2018-10-07  951  
5589651eb Nicolas Dichtel 2018-11-22  952  	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
8a46e1ccc Nicolas Dichtel 2018-11-22  953  	if (net_cb.fillargs.add_ref &&
8a46e1ccc Nicolas Dichtel 2018-11-22  954  	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
8a46e1ccc Nicolas Dichtel 2018-11-22  955  	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
8a46e1ccc Nicolas Dichtel 2018-11-22  956  		err = -EAGAIN;
8a46e1ccc Nicolas Dichtel 2018-11-22  957  		goto end;
8a46e1ccc Nicolas Dichtel 2018-11-22  958  	}
5589651eb Nicolas Dichtel 2018-11-22  959  	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
8a46e1ccc Nicolas Dichtel 2018-11-22  960  	if (net_cb.fillargs.add_ref &&
8a46e1ccc Nicolas Dichtel 2018-11-22  961  	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
8a46e1ccc Nicolas Dichtel 2018-11-22  962  		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
5589651eb Nicolas Dichtel 2018-11-22 @963  	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
a143c40c3 Nicolas Dichtel 2015-04-07  964  
a143c40c3 Nicolas Dichtel 2015-04-07  965  	cb->args[0] = net_cb.idx;
5589651eb Nicolas Dichtel 2018-11-22  966  end:
8a46e1ccc Nicolas Dichtel 2018-11-22  967  	if (net_cb.fillargs.add_ref)
5589651eb Nicolas Dichtel 2018-11-22  968  		put_net(net_cb.tgt_net);
5589651eb Nicolas Dichtel 2018-11-22  969  	return err < 0 ? err : skb->len;
a143c40c3 Nicolas Dichtel 2015-04-07  970  }
a143c40c3 Nicolas Dichtel 2015-04-07  971  

:::::: The code at line 963 was first introduced by commit
:::::: 5589651eb5e06b32107a1d8830af4be67aa58b85 netns: add support of NETNSA_TARGET_NSID

:::::: TO: Nicolas Dichtel <nicolas.dichtel@6wind.com>
:::::: CC: 0day robot <lkp@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 66610 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 0/5] Ease to interpret net-nsid
  2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
                       ` (4 preceding siblings ...)
  2018-11-22 22:22     ` [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-26 14:42     ` Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
                         ` (5 more replies)
  5 siblings, 6 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem


The goal of this series is to ease the interpretation of nsid received in
netlink messages from other netns (when the user uses
NETLINK_F_LISTEN_ALL_NSID).

After this series, with a patched iproute2:

$ ip netns add foo
$ ip netns add bar
$ touch /var/run/netns/init_net
$ mount --bind /proc/1/ns/net /var/run/netns/init_net
$ ip netns set init_net 11
$ ip netns set foo 12
$ ip netns set bar 13
$ ip netns
init_net (id: 11)
bar (id: 13)
foo (id: 12)
$ ip -n foo netns set init_net 21
$ ip -n foo netns set foo 22
$ ip -n foo netns set bar 23
$ ip -n foo netns
init_net (id: 21)
bar (id: 23)
foo (id: 22)
$ ip -n bar netns set init_net 31
$ ip -n bar netns set foo 32
$ ip -n bar netns set bar 33
$ ip -n bar netns
init_net (id: 31)
bar (id: 33)
foo (id: 32)
$ ip netns list-id target-nsid 12
nsid 21 current-nsid 11 (iproute2 netns name: init_net)
nsid 22 current-nsid 12 (iproute2 netns name: foo)
nsid 23 current-nsid 13 (iproute2 netns name: bar)
$ ip -n bar netns list-id target-nsid 32 nsid 31
nsid 21 current-nsid 31 (iproute2 netns name: init_net)

v3 -> v4:
  - patch 5/5: fix imbalance lock in error path

v2 -> v3:
  - patch 5/5: account NETNSA_CURRENT_NSID in rtnl_net_get_size()

v1 -> v2:
  - patch 1/5: remove net from struct rtnl_net_dump_cb
  - patch 2/5: new in this version
  - patch 3/5: use a bool to know if rtnl_get_net_ns_capable() was called
  - patch 5/5: use struct net_fill_args

 include/uapi/linux/net_namespace.h |   2 +
 net/core/net_namespace.c           | 159 +++++++++++++++++++++++++++++++------
 2 files changed, 135 insertions(+), 26 deletions(-)

Comments are welcomed,
Regards,
Nicolas

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 1/5] netns: remove net arg from rtnl_net_fill()
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
@ 2018-11-26 14:42       ` Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
                         ` (4 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This argument is not used anymore.

Fixes: cab3c8ec8d57 ("netns: always provide the id to rtnl_net_fill()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index fefe72774aeb..52b9620e3457 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -739,7 +739,7 @@ static int rtnl_net_get_size(void)
 }
 
 static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, struct net *net, int nsid)
+			 int cmd, int nsid)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
@@ -801,7 +801,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	id = peernet2id(net, peer);
 	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, net, id);
+			    RTM_NEWNSID, id);
 	if (err < 0)
 		goto err_out;
 
@@ -816,7 +816,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 struct rtnl_net_dump_cb {
-	struct net *net;
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
 	int idx;
@@ -833,7 +832,7 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 
 	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
 			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, net_cb->net, id);
+			    RTM_NEWNSID, id);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +845,6 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
-		.net = net,
 		.skb = skb,
 		.cb = cb,
 		.idx = 0,
@@ -876,7 +874,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id);
+	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 2/5] netns: introduce 'struct net_fill_args'
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
@ 2018-11-26 14:42       ` Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
                         ` (3 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

This is a preparatory work. To avoid having to much arguments for the
function rtnl_net_fill(), a new structure is defined.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 48 ++++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 52b9620e3457..f8a5966b086c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -738,20 +738,28 @@ static int rtnl_net_get_size(void)
 	       ;
 }
 
-static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
-			 int cmd, int nsid)
+struct net_fill_args {
+	u32 portid;
+	u32 seq;
+	int flags;
+	int cmd;
+	int nsid;
+};
+
+static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 {
 	struct nlmsghdr *nlh;
 	struct rtgenmsg *rth;
 
-	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rth), flags);
+	nlh = nlmsg_put(skb, args->portid, args->seq, args->cmd, sizeof(*rth),
+			args->flags);
 	if (!nlh)
 		return -EMSGSIZE;
 
 	rth = nlmsg_data(nlh);
 	rth->rtgen_family = AF_UNSPEC;
 
-	if (nla_put_s32(skb, NETNSA_NSID, nsid))
+	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
 	nlmsg_end(skb, nlh);
@@ -767,10 +775,15 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[NETNSA_MAX + 1];
+	struct net_fill_args fillargs = {
+		.portid = NETLINK_CB(skb).portid,
+		.seq = nlh->nlmsg_seq,
+		.cmd = RTM_NEWNSID,
+	};
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	struct net *peer;
-	int err, id;
+	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
 			  rtnl_net_policy, extack);
@@ -799,9 +812,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		goto out;
 	}
 
-	id = peernet2id(net, peer);
-	err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
-			    RTM_NEWNSID, id);
+	fillargs.nsid = peernet2id(net, peer);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
@@ -817,7 +829,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct sk_buff *skb;
-	struct netlink_callback *cb;
+	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
 };
@@ -830,9 +842,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	if (net_cb->idx < net_cb->s_idx)
 		goto cont;
 
-	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
-			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-			    RTM_NEWNSID, id);
+	net_cb->fillargs.nsid = id;
+	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
 
@@ -846,7 +857,12 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
 		.skb = skb,
-		.cb = cb,
+		.fillargs = {
+			.portid = NETLINK_CB(cb->skb).portid,
+			.seq = cb->nlh->nlmsg_seq,
+			.flags = NLM_F_MULTI,
+			.cmd = RTM_NEWNSID,
+		},
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
@@ -867,6 +883,10 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 {
+	struct net_fill_args fillargs = {
+		.cmd = cmd,
+		.nsid = id,
+	};
 	struct sk_buff *msg;
 	int err = -ENOMEM;
 
@@ -874,7 +894,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id)
 	if (!msg)
 		goto out;
 
-	err = rtnl_net_fill(msg, 0, 0, 0, cmd, id);
+	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
 
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 3/5] netns: add support of NETNSA_TARGET_NSID
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
@ 2018-11-26 14:42       ` Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
                         ` (2 subsequent siblings)
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like it was done for link and address, add the ability to perform get/dump
in another netns by specifying a target nsid attribute.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 86 ++++++++++++++++++++++++++----
 2 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0187c74d8889..0ed9dd61d32a 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
 	NETNSA_NSID,
 	NETNSA_PID,
 	NETNSA_FD,
+	NETNSA_TARGET_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f8a5966b086c..885c54197e31 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
 	[NETNSA_NSID]		= { .type = NLA_S32 },
 	[NETNSA_PID]		= { .type = NLA_U32 },
 	[NETNSA_FD]		= { .type = NLA_U32 },
+	[NETNSA_TARGET_NSID]	= { .type = NLA_S32 },
 };
 
 static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -780,9 +781,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.seq = nlh->nlmsg_seq,
 		.cmd = RTM_NEWNSID,
 	};
+	struct net *peer, *target = net;
+	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
-	struct net *peer;
 	int err;
 
 	err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -806,13 +808,27 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return PTR_ERR(peer);
 	}
 
+	if (tb[NETNSA_TARGET_NSID]) {
+		int id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
+
+		target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
+		if (IS_ERR(target)) {
+			NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
+			NL_SET_ERR_MSG(extack,
+				       "Target netns reference is invalid");
+			err = PTR_ERR(target);
+			goto out;
+		}
+		put_target = true;
+	}
+
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
 	if (!msg) {
 		err = -ENOMEM;
 		goto out;
 	}
 
-	fillargs.nsid = peernet2id(net, peer);
+	fillargs.nsid = peernet2id(target, peer);
 	err = rtnl_net_fill(msg, &fillargs);
 	if (err < 0)
 		goto err_out;
@@ -823,15 +839,19 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
+	if (put_target)
+		put_net(target);
 	put_net(peer);
 	return err;
 }
 
 struct rtnl_net_dump_cb {
+	struct net *tgt_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
+	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -852,10 +872,50 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 	return 0;
 }
 
+static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
+				   struct rtnl_net_dump_cb *net_cb,
+				   struct netlink_callback *cb)
+{
+	struct netlink_ext_ack *extack = cb->extack;
+	struct nlattr *tb[NETNSA_MAX + 1];
+	int err, i;
+
+	err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
+				 rtnl_net_policy, extack);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i <= NETNSA_MAX; i++) {
+		if (!tb[i])
+			continue;
+
+		if (i == NETNSA_TARGET_NSID) {
+			struct net *net;
+
+			net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
+			if (IS_ERR(net)) {
+				NL_SET_BAD_ATTR(extack, tb[i]);
+				NL_SET_ERR_MSG(extack,
+					       "Invalid target network namespace id");
+				return PTR_ERR(net);
+			}
+			net_cb->tgt_net = net;
+			net_cb->put_tgt_net = true;
+		} else {
+			NL_SET_BAD_ATTR(extack, tb[i]);
+			NL_SET_ERR_MSG(extack,
+				       "Unsupported attribute in dump request");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = sock_net(skb->sk);
 	struct rtnl_net_dump_cb net_cb = {
+		.tgt_net = sock_net(skb->sk),
 		.skb = skb,
 		.fillargs = {
 			.portid = NETLINK_CB(cb->skb).portid,
@@ -866,19 +926,23 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 		.idx = 0,
 		.s_idx = cb->args[0],
 	};
+	int err = 0;
 
-	if (cb->strict_check &&
-	    nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) {
-			NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request");
-			return -EINVAL;
+	if (cb->strict_check) {
+		err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
+		if (err < 0)
+			goto end;
 	}
 
-	spin_lock_bh(&net->nsid_lock);
-	idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-	spin_unlock_bh(&net->nsid_lock);
+	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
-	return skb->len;
+end:
+	if (net_cb.put_tgt_net)
+		put_net(net_cb.tgt_net);
+	return err < 0 ? err : skb->len;
 }
 
 static void rtnl_net_notifyid(struct net *net, int cmd, int id)
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 4/5] netns: enable to specify a nsid for a get request
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
                         ` (2 preceding siblings ...)
  2018-11-26 14:42       ` [PATCH net-next v4 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
@ 2018-11-26 14:42       ` Nicolas Dichtel
  2018-11-26 14:42       ` [PATCH net-next v4 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
  2018-11-28  0:20       ` [PATCH net-next v4 0/5] Ease to interpret net-nsid David Miller
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Combined with NETNSA_TARGET_NSID, it enables to "translate" a nsid from one
netns to a nsid of another netns.
This is useful when using NETLINK_F_LISTEN_ALL_NSID because it helps the
user to interpret a nsid received from an other netns.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 net/core/net_namespace.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 885c54197e31..dd25fb22ad45 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -797,6 +797,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 	} else if (tb[NETNSA_FD]) {
 		peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
 		nla = tb[NETNSA_FD];
+	} else if (tb[NETNSA_NSID]) {
+		peer = get_net_ns_by_id(net, nla_get_u32(tb[NETNSA_NSID]));
+		if (!peer)
+			peer = ERR_PTR(-ENOENT);
+		nla = tb[NETNSA_NSID];
 	} else {
 		NL_SET_ERR_MSG(extack, "Peer netns reference is missing");
 		return -EINVAL;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH net-next v4 5/5] netns: enable to dump full nsid translation table
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
                         ` (3 preceding siblings ...)
  2018-11-26 14:42       ` [PATCH net-next v4 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
@ 2018-11-26 14:42       ` Nicolas Dichtel
  2018-11-28  0:20       ` [PATCH net-next v4 0/5] Ease to interpret net-nsid David Miller
  5 siblings, 0 replies; 39+ messages in thread
From: Nicolas Dichtel @ 2018-11-26 14:42 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, davem, Nicolas Dichtel

Like the previous patch, the goal is to ease to convert nsids from one
netns to another netns.
A new attribute (NETNSA_CURRENT_NSID) is added to the kernel answer when
NETNSA_TARGET_NSID is provided, thus the user can easily convert nsids.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
---
 include/uapi/linux/net_namespace.h |  1 +
 net/core/net_namespace.c           | 32 ++++++++++++++++++++++++------
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
index 0ed9dd61d32a..9f9956809565 100644
--- a/include/uapi/linux/net_namespace.h
+++ b/include/uapi/linux/net_namespace.h
@@ -17,6 +17,7 @@ enum {
 	NETNSA_PID,
 	NETNSA_FD,
 	NETNSA_TARGET_NSID,
+	NETNSA_CURRENT_NSID,
 	__NETNSA_MAX,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index dd25fb22ad45..05b23b285058 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -736,6 +736,7 @@ static int rtnl_net_get_size(void)
 {
 	return NLMSG_ALIGN(sizeof(struct rtgenmsg))
 	       + nla_total_size(sizeof(s32)) /* NETNSA_NSID */
+	       + nla_total_size(sizeof(s32)) /* NETNSA_CURRENT_NSID */
 	       ;
 }
 
@@ -745,6 +746,8 @@ struct net_fill_args {
 	int flags;
 	int cmd;
 	int nsid;
+	bool add_ref;
+	int ref_nsid;
 };
 
 static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
@@ -763,6 +766,10 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
 	if (nla_put_s32(skb, NETNSA_NSID, args->nsid))
 		goto nla_put_failure;
 
+	if (args->add_ref &&
+	    nla_put_s32(skb, NETNSA_CURRENT_NSID, args->ref_nsid))
+		goto nla_put_failure;
+
 	nlmsg_end(skb, nlh);
 	return 0;
 
@@ -782,7 +789,6 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 		.cmd = RTM_NEWNSID,
 	};
 	struct net *peer, *target = net;
-	bool put_target = false;
 	struct nlattr *nla;
 	struct sk_buff *msg;
 	int err;
@@ -824,7 +830,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 			err = PTR_ERR(target);
 			goto out;
 		}
-		put_target = true;
+		fillargs.add_ref = true;
+		fillargs.ref_nsid = peernet2id(net, peer);
 	}
 
 	msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
@@ -844,7 +851,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 err_out:
 	nlmsg_free(msg);
 out:
-	if (put_target)
+	if (fillargs.add_ref)
 		put_net(target);
 	put_net(peer);
 	return err;
@@ -852,11 +859,11 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 struct rtnl_net_dump_cb {
 	struct net *tgt_net;
+	struct net *ref_net;
 	struct sk_buff *skb;
 	struct net_fill_args fillargs;
 	int idx;
 	int s_idx;
-	bool put_tgt_net;
 };
 
 static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -868,6 +875,8 @@ static int rtnl_net_dumpid_one(int id, void *peer, void *data)
 		goto cont;
 
 	net_cb->fillargs.nsid = id;
+	if (net_cb->fillargs.add_ref)
+		net_cb->fillargs.ref_nsid = __peernet2id(net_cb->ref_net, peer);
 	ret = rtnl_net_fill(net_cb->skb, &net_cb->fillargs);
 	if (ret < 0)
 		return ret;
@@ -904,8 +913,9 @@ static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
 					       "Invalid target network namespace id");
 				return PTR_ERR(net);
 			}
+			net_cb->fillargs.add_ref = true;
+			net_cb->ref_net = net_cb->tgt_net;
 			net_cb->tgt_net = net;
-			net_cb->put_tgt_net = true;
 		} else {
 			NL_SET_BAD_ATTR(extack, tb[i]);
 			NL_SET_ERR_MSG(extack,
@@ -940,12 +950,22 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
 	}
 
 	spin_lock_bh(&net_cb.tgt_net->nsid_lock);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net) &&
+	    !spin_trylock_bh(&net_cb.ref_net->nsid_lock)) {
+		spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
+		err = -EAGAIN;
+		goto end;
+	}
 	idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+	if (net_cb.fillargs.add_ref &&
+	    !net_eq(net_cb.ref_net, net_cb.tgt_net))
+		spin_unlock_bh(&net_cb.ref_net->nsid_lock);
 	spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
 
 	cb->args[0] = net_cb.idx;
 end:
-	if (net_cb.put_tgt_net)
+	if (net_cb.fillargs.add_ref)
 		put_net(net_cb.tgt_net);
 	return err < 0 ? err : skb->len;
 }
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH net-next v4 0/5] Ease to interpret net-nsid
  2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
                         ` (4 preceding siblings ...)
  2018-11-26 14:42       ` [PATCH net-next v4 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
@ 2018-11-28  0:20       ` David Miller
  5 siblings, 0 replies; 39+ messages in thread
From: David Miller @ 2018-11-28  0:20 UTC (permalink / raw)
  To: nicolas.dichtel; +Cc: dsahern, netdev

From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Mon, 26 Nov 2018 15:42:01 +0100

> 
> The goal of this series is to ease the interpretation of nsid received in
> netlink messages from other netns (when the user uses
> NETLINK_F_LISTEN_ALL_NSID).
> 
> After this series, with a patched iproute2:
 ...
> v3 -> v4:
>   - patch 5/5: fix imbalance lock in error path
> 
> v2 -> v3:
>   - patch 5/5: account NETNSA_CURRENT_NSID in rtnl_net_get_size()
> 
> v1 -> v2:
>   - patch 1/5: remove net from struct rtnl_net_dump_cb
>   - patch 2/5: new in this version
>   - patch 3/5: use a bool to know if rtnl_get_net_ns_capable() was called
>   - patch 5/5: use struct net_fill_args

Series applied.

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2018-11-28 11:20 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-21 11:01 [PATCH net-next 0/4] Ease to interpret net-nsid Nicolas Dichtel
2018-11-21 11:01 ` [PATCH net-next 1/4] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
2018-11-21 11:01 ` [PATCH net-next 2/4] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
2018-11-21 18:05   ` David Ahern
2018-11-21 20:58     ` Nicolas Dichtel
2018-11-21 21:07       ` David Ahern
2018-11-22  8:06         ` Nicolas Dichtel
2018-11-21 11:01 ` [PATCH net-next 3/4] netns: enable to specify a nsid for a get request Nicolas Dichtel
2018-11-21 11:01 ` [PATCH net-next 4/4] netns: enable to dump full nsid translation table Nicolas Dichtel
2018-11-21 18:09   ` David Ahern
2018-11-21 21:01     ` Nicolas Dichtel
2018-11-21 21:08       ` David Ahern
2018-11-22 15:50 ` [PATCH net-next v2 0/5] Ease to interpret net-nsid Nicolas Dichtel
2018-11-22 15:50   ` [PATCH net-next v2 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
2018-11-22 16:18     ` David Ahern
2018-11-22 15:50   ` [PATCH net-next v2 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
2018-11-22 16:23     ` David Ahern
2018-11-22 15:50   ` [PATCH net-next v2 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
2018-11-22 16:32     ` David Ahern
2018-11-22 15:50   ` [PATCH net-next v2 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
2018-11-22 16:32     ` David Ahern
2018-11-22 15:50   ` [PATCH net-next v2 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
2018-11-22 16:40     ` David Ahern
2018-11-22 16:42       ` Nicolas Dichtel
2018-11-22 22:22   ` [PATCH net-next v3 0/5] Ease to interpret net-nsid Nicolas Dichtel
2018-11-22 22:22     ` [PATCH net-next v3 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
2018-11-22 22:22     ` [PATCH net-next v3 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
2018-11-22 22:22     ` [PATCH net-next v3 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
2018-11-22 22:22     ` [PATCH net-next v3 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
2018-11-22 22:22     ` [PATCH net-next v3 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
2018-11-24 15:47       ` David Ahern
2018-11-26 10:06       ` kbuild test robot
2018-11-26 14:42     ` [PATCH net-next v4 0/5] Ease to interpret net-nsid Nicolas Dichtel
2018-11-26 14:42       ` [PATCH net-next v4 1/5] netns: remove net arg from rtnl_net_fill() Nicolas Dichtel
2018-11-26 14:42       ` [PATCH net-next v4 2/5] netns: introduce 'struct net_fill_args' Nicolas Dichtel
2018-11-26 14:42       ` [PATCH net-next v4 3/5] netns: add support of NETNSA_TARGET_NSID Nicolas Dichtel
2018-11-26 14:42       ` [PATCH net-next v4 4/5] netns: enable to specify a nsid for a get request Nicolas Dichtel
2018-11-26 14:42       ` [PATCH net-next v4 5/5] netns: enable to dump full nsid translation table Nicolas Dichtel
2018-11-28  0:20       ` [PATCH net-next v4 0/5] Ease to interpret net-nsid David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.