From: Eric W. Biederman <hidden> Date: 2012-10-01 22:41:04
Stephen Hemminger [off-list ref] writes:
On Mon, 1 Oct 2012 14:16:09 -0700
Stephen Hemminger [off-list ref] wrote:
quoted
When testing VXLAN I noticed that the kernel bind seems to be a problem for
network tunnels. The init_net function is called repeatedly for the same
network namespace!
It definitely should not be.
quoted
1. Create vxlan device:
# ip li add vxlan0 type vxlan id 11 group 239.1.1.1 dev eth0
# dmesg | tail
[11580.671016] vxlan: vxlan_init_net in net 1
Net 1? What are you printing out? It isn't the net_id by any chance?
quoted
2. Start Chrome (or other application using namespaces)
dmesg | tail
[11587.371195] vxlan: vxlan_init_net in net 1
[11587.371211] vxlan: bind for UDP socket 0.0.0.0:8472 (-98)
Isn't init_net supposed to be unique. The current semantics also break
L2TP.
The init method should be called exactly once per network namespace.
The timing of the init methods you report seems correct.
The vxlan code isn't in net-next or I would take a look.
I took a quick look at l2tp and the code is doing some weird things.
There are a bunch of references to &init_net that I would expect
to references to either sk_net() or dev_net().
Adding support for multiple network namespaces and then reaching
out to the initial network namespace for things is definitely a recipe
for getting confused.
So my blind guess would be that someone half implemented network
namespace support for l2tp and vxlan copied the bugs.
Eric
quoted
This is with 3.6.0-rc7-net-next
Here is back trace from where duplicate network namespace init gets done.
From: Stephen Hemminger <hidden> Date: 2012-10-01 22:57:39
On Mon, 01 Oct 2012 15:40:56 -0700
ebiederm@xmission.com (Eric W. Biederman) wrote:
Stephen Hemminger [off-list ref] writes:
quoted
On Mon, 1 Oct 2012 14:16:09 -0700
Stephen Hemminger [off-list ref] wrote:
quoted
When testing VXLAN I noticed that the kernel bind seems to be a problem for
network tunnels. The init_net function is called repeatedly for the same
network namespace!
It definitely should not be.
quoted
quoted
1. Create vxlan device:
# ip li add vxlan0 type vxlan id 11 group 239.1.1.1 dev eth0
# dmesg | tail
[11580.671016] vxlan: vxlan_init_net in net 1
Net 1? What are you printing out? It isn't the net_id by any chance?
Yes it is the net_id which is passed to net_generic() to find the
per-namespace data structure.
quoted
quoted
2. Start Chrome (or other application using namespaces)
dmesg | tail
[11587.371195] vxlan: vxlan_init_net in net 1
[11587.371211] vxlan: bind for UDP socket 0.0.0.0:8472 (-98)
Isn't init_net supposed to be unique. The current semantics also break
L2TP.
The init method should be called exactly once per network namespace.
The timing of the init methods you report seems correct.
The vxlan code isn't in net-next or I would take a look.
I took a quick look at l2tp and the code is doing some weird things.
There are a bunch of references to &init_net that I would expect
to references to either sk_net() or dev_net().
Adding support for multiple network namespaces and then reaching
out to the initial network namespace for things is definitely a recipe
for getting confused.
So my blind guess would be that someone half implemented network
namespace support for l2tp and vxlan copied the bugs.
The vxlan driver has one UDP socket per namespace.
There are no references to init_net in it.
I think the problem is the call chain
copy_net_ns -> setup_net -> ops_init
There is nothing that nothing increments the id after register_pernet_operations.
Shouldn't there be an increment so each new namespace gets a unique id?
From: Eric W. Biederman <hidden> Date: 2012-10-01 23:11:15
Stephen Hemminger [off-list ref] writes:
On Mon, 01 Oct 2012 15:40:56 -0700
ebiederm@xmission.com (Eric W. Biederman) wrote:
quoted
Stephen Hemminger [off-list ref] writes:
quoted
On Mon, 1 Oct 2012 14:16:09 -0700
Stephen Hemminger [off-list ref] wrote:
quoted
When testing VXLAN I noticed that the kernel bind seems to be a problem for
network tunnels. The init_net function is called repeatedly for the same
network namespace!
It definitely should not be.
quoted
quoted
1. Create vxlan device:
# ip li add vxlan0 type vxlan id 11 group 239.1.1.1 dev eth0
# dmesg | tail
[11580.671016] vxlan: vxlan_init_net in net 1
Net 1? What are you printing out? It isn't the net_id by any chance?
Yes it is the net_id which is passed to net_generic() to find the
per-namespace data structure.
Yes. net_id is just an index and is the same in all network namespaces.
net_id should only be different for different instances of per_net
operations.
quoted
quoted
quoted
2. Start Chrome (or other application using namespaces)
dmesg | tail
[11587.371195] vxlan: vxlan_init_net in net 1
[11587.371211] vxlan: bind for UDP socket 0.0.0.0:8472 (-98)
Isn't init_net supposed to be unique. The current semantics also break
L2TP.
The init method should be called exactly once per network namespace.
The timing of the init methods you report seems correct.
The vxlan code isn't in net-next or I would take a look.
I took a quick look at l2tp and the code is doing some weird things.
There are a bunch of references to &init_net that I would expect
to references to either sk_net() or dev_net().
Adding support for multiple network namespaces and then reaching
out to the initial network namespace for things is definitely a recipe
for getting confused.
So my blind guess would be that someone half implemented network
namespace support for l2tp and vxlan copied the bugs.
The vxlan driver has one UDP socket per namespace.
There are no references to init_net in it.
Then my guess is that you have an ordering problem. Attempting
to initialize a vxlan before ipv4 is initialized or some such.
I think the problem is the call chain
copy_net_ns -> setup_net -> ops_init
There is nothing that nothing increments the id after register_pernet_operations.
Shouldn't there be an increment so each new namespace gets a unique id?
No.
There are some extra pointers at the end of struct net and the id is
which of those pointers your subsystem gets to use. net_generic returns
your pointer value.
I can see the confusion but the id is definitely not a namespace id.
Eric
From: Eric W. Biederman <hidden> Date: 2012-10-02 00:35:49
Stephen Hemminger [off-list ref] writes:
On Mon, 01 Oct 2012 16:11:07 -0700
ebiederm@xmission.com (Eric W. Biederman) wrote:
quoted
Then my guess is that you have an ordering problem. Attempting
to initialize a vxlan before ipv4 is initialized or some such.
Isn't there a gurantee that init operations are called in the order
they registered?
Yes. With the caveat that all things registered with
register_pernet_subsys are called before register_pernet_device.
So if you are a registering as a subsystem the loopback device won't
have been registered yet.
So if there is some requirement that I'm not seeing that the loopback
device needs to be registered or possibly even registered and brought up
before we can bind to a port you could easily be hitting that.
[11587.371211] vxlan: bind for UDP socket 0.0.0.0:8472 (-98)
From this one clue it does look like the trace is:
inet_bind
udp4_get_port
udp_lib_get_port
And it does look like the only possible failure when a port number
is passed in is for the port to be genuinly in use.
Ok. So I tracked down your patch so I could find the relevant code.
+static __net_init int vxlan_init_net(struct net *net)
+{
....
+ /* Create UDP socket for encapsulation receive. */
+ rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vn->sock);
+ if (rc < 0) {
+ pr_debug("UDP socket create failed\n");
+ return rc;
+ }
And this is where we have the issue.
sock_create_kern only creates sockets in the initial network namespace.
There is inet_ctl_sock_create which comes closer to what you want
but I expect you want your socket to be hashed.
Still we need to do something here to avoid have a socket in the
network namespace that has a reference count on the network namespace
and keeps the network namespace from exiting.
We very clearly don't have a good interface for handling this at
the moment. I am drawing a blank at the moment on exactly what
such an interface should look like.
What we have is certainly error prone for use inside the kernel.
I have a suspicion the nfs server code that uses __sock_create
has the potential to forever pin a network namespace.
int sock_create_netns(struct net *net, int family, int type, int protocol,
struct socket **res)
{
int err;
err = __sock_create(&init_net, family, type, protocol, res, 1);
if (err == 0) {
sk_change_net(sock->sk, net);
return err;
}
Although I am beginning to suspect we should do the silly refcount
avoidance for all in kernel sockets, and just pass the kern parameter
all of the way down to sk_alloc, so it can get the refcounting right
the first time.
However for the bug fix for the merge window (since it appears Dave
merged this code).
I suggest you just add the sk_change_net and change the socket release
to sk_release_kern in release_net. At least that is localized, and
doesn't require us to clean up the API for in kernel sockets in a rush.
Eric
+ vxlan_addr.sin_port = htons(vxlan_port);
+
+ rc = kernel_bind(vn->sock, (struct sockaddr *) &vxlan_addr,
+ sizeof(vxlan_addr));
+ if (rc < 0) {
+ pr_debug("bind for UDP socket %pI4:%u (%d)\n",
+ &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
+ sock_release(vn->sock);
+ vn->sock = NULL;
+ return rc;
+ }
Eric
From: Stephen Hemminger <hidden> Date: 2012-10-02 00:48:44
The problem was vxlan wasn't doing sk_change_net on the created socket.
I'm testing that fix.
The long term fix is to change sock_create_kern() to take a 'struct net'
argument. This would avoid the trap of having to change the namespace.
Also several places using __sock_create() could use it.
L2TP still looks to have several namespace related issues.
@@ -1136,6 +1136,9 @@ static __net_init int vxlan_init_net(strpr_debug("UDP socket create failed\n");returnrc;}+/* Put in proper namespace */+sk=vn->sock->sk;+sk_change_net(sk,net);vxlan_addr.sin_port=htons(vxlan_port);
@@ -1150,7 +1153,6 @@ static __net_init int vxlan_init_net(str}/* Disable multicast loopback */-sk=vn->sock->sk;inet_sk(sk)->mc_loop=0;/* Mark socket as an encapsulation socket. */
From: Eric W. Biederman <hidden> Date: 2012-10-02 00:58:19
Stephen Hemminger [off-list ref] writes:
Move vxlan UDP socket to correct network namespace
You also need to replease sock_release with
sk_release_kernel.
Otherwise you will decrement the network namespace count
below zero, when sock_release is called.
Eric
@@ -1136,6 +1136,9 @@ static __net_init int vxlan_init_net(strpr_debug("UDP socket create failed\n");returnrc;}+/* Put in proper namespace */+sk=vn->sock->sk;+sk_change_net(sk,net);vxlan_addr.sin_port=htons(vxlan_port);
@@ -1150,7 +1153,6 @@ static __net_init int vxlan_init_net(str}/* Disable multicast loopback */-sk=vn->sock->sk;inet_sk(sk)->mc_loop=0;/* Mark socket as an encapsulation socket. */
@@ -1136,6 +1136,9 @@ static __net_init int vxlan_init_net(strpr_debug("UDP socket create failed\n");returnrc;}+/* Put in proper namespace */+sk=vn->sock->sk;+sk_change_net(sk,net);vxlan_addr.sin_port=htons(vxlan_port);
@@ -1144,13 +1147,12 @@ static __net_init int vxlan_init_net(strif(rc<0){pr_debug("bind for UDP socket %pI4:%u (%d)\n",&vxlan_addr.sin_addr,ntohs(vxlan_addr.sin_port),rc);-sock_release(vn->sock);+sk_release_kernel(sk);vn->sock=NULL;returnrc;}/* Disable multicast loopback */-sk=vn->sock->sk;inet_sk(sk)->mc_loop=0;/* Mark socket as an encapsulation socket. */
Hello,
On Mon, 1 Oct 2012, Stephen Hemminger wrote:
The problem was vxlan wasn't doing sk_change_net on the created socket.
I'm testing that fix.
The long term fix is to change sock_create_kern() to take a 'struct net'
argument. This would avoid the trap of having to change the namespace.
Also several places using __sock_create() could use it.
L2TP still looks to have several namespace related issues.
There should be also .netnsok = true in l2tp_nl_family
as final step.
Regards
--
Julian Anastasov [off-list ref]
@@ -1136,6 +1136,9 @@ static __net_init int vxlan_init_net(strpr_debug("UDP socket create failed\n");returnrc;}+/* Put in proper namespace */+sk=vn->sock->sk;+sk_change_net(sk,net);vxlan_addr.sin_port=htons(vxlan_port);
@@ -1144,13 +1147,12 @@ static __net_init int vxlan_init_net(strif(rc<0){pr_debug("bind for UDP socket %pI4:%u (%d)\n",&vxlan_addr.sin_addr,ntohs(vxlan_addr.sin_port),rc);-sock_release(vn->sock);+sk_release_kernel(sk);vn->sock=NULL;returnrc;}/* Disable multicast loopback */-sk=vn->sock->sk;inet_sk(sk)->mc_loop=0;/* Mark socket as an encapsulation socket. */
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Stephen Hemminger <hidden> Date: 2012-10-02 15:52:03
On Tue, 2 Oct 2012 09:15:46 +0300 (EEST)
Julian Anastasov [off-list ref] wrote:
Hello,
On Mon, 1 Oct 2012, Stephen Hemminger wrote:
quoted
The problem was vxlan wasn't doing sk_change_net on the created socket.
I'm testing that fix.
The long term fix is to change sock_create_kern() to take a 'struct net'
argument. This would avoid the trap of having to change the namespace.
Also several places using __sock_create() could use it.
L2TP still looks to have several namespace related issues.
There should be also .netnsok = true in l2tp_nl_family
as final step.
Regards
--
Julian Anastasov [off-list ref]
There are actually lots more net namespace issues in L2TP.
For example session and tunnel counts are global, not per namespace.