Bug#673522: unshare NEWNET + using sockets from before: unregister_netdevice: waiting for lo to become free. Usage count = 2
Package: linux-image-3.2.0-2-amd64
Version: 3.2.16-1
Hi,
CLONE_NEWNET is still buggy (i found random reports with the same error message from 2010).
uname: Linux * 3.2.0-2-amd64 #1 SMP Mon Apr 30 05:20:23 UTC 2012 x86_64 GNU/Linux
See the attached example.
I don't think it matters much how the socket is used: just create the socket
before the unshare and use it somehow - listen() after unshare() triggered it too.
The kernel starts spamming the message after the program is terminated.
Also the port is not reachable from the outside - although i admit i couldn't
find docs mentioning this is supported, but it really should be.
(Given that struct net is part of struct sock(common) this shouldn't be hard)
I could reproduce it in virtualbox with rescue mode from
http://cdimage.debian.org/cdimage/wheezy_di_alpha1/amd64/iso-cd/debian-wheezy-DI-a1-amd64-netinst.iso
- when i started it a second time the process would even hang for some time (not killable).
logs look like this:
[ 796.444219] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 806.684213] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 816.924212] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 827.164217] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 837.408237] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 847.648216] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 857.888219] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 868.128224] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 878.368221] unregister_netdevice: waiting for lo to become free. Usage count = 2
[ 888.608215] unregister_netdevice: waiting for lo to become free. Usage count = 2
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main() {
int listenfd, acceptfd, connectfd;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
puts("newnet + listen/connect test");
if (-1 == (listenfd = socket(AF_INET, SOCK_STREAM, 0))) { perror("socket failed"); abort(); }
if (0 != listen(listenfd, 1)) { perror("listen failed"); abort(); }
if (0 != unshare(CLONE_NEWNET)) { perror("unshare failed"); abort(); }
if (0 != getsockname(listenfd, (struct sockaddr*) &addr, &addrlen)) { perror("getsockname failed"); }
if (-1 == (connectfd = socket(AF_INET, SOCK_STREAM, 0))) { perror("socket failed"); abort(); }
if (0 == connect(connectfd, (struct sockaddr*) &addr, addrlen)) {
puts("successful connect - something is wrong here");
} else {
perror("connect failed as expected");
}
close(connectfd);
printf("listening on 0.0.0.0:%i\n", (int) addr.sin_port);
if (-1 == (acceptfd = accept(listenfd, NULL, NULL))) { perror("accept failed"); abort(); }
{
char buf[1024];
int len = read(acceptfd, buf, sizeof(buf)-1);
if (len < 0) { perror("read failed"); abort(); }
buf[len] = 0;
printf("received: '%s'\n", buf);
write(acceptfd, buf, len);
close(acceptfd);
}
puts("done.");
}
Reply to: