passt, tap: Daemonise once socket is ready without waiting for connection

The existing behaviour is not really practical: an automated agent in
charge of starting both qemu and passt would need to fork itself to
start passt, because passt won't fork to background until qemu
connects, and the agent needs to unblock to start qemu.

Instead of waiting for a connection to daemonise, do it right away as
soon as a socket is available: that can be considered an initialised
state already.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Stefano Brivio 2022-01-26 16:39:33 +01:00
parent b1f5688495
commit 34e6429235
4 changed files with 51 additions and 21 deletions

View file

@ -345,6 +345,7 @@ int main(int argc, char **argv)
} }
sock_probe_mem(&c); sock_probe_mem(&c);
c.fd_tap = c.fd_tap_listen = -1;
tap_sock_init(&c); tap_sock_init(&c);
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
@ -387,9 +388,10 @@ loop:
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
union epoll_ref ref = *((union epoll_ref *)&events[i].data.u64); union epoll_ref ref = *((union epoll_ref *)&events[i].data.u64);
int fd = events[i].data.fd;
if (events[i].data.fd == c.fd_tap) if (fd == c.fd_tap || fd == c.fd_tap_listen)
tap_handler(&c, events[i].events, &now); tap_handler(&c, fd, events[i].events, &now);
else else
sock_handler(&c, ref, events[i].events, &now); sock_handler(&c, ref, events[i].events, &now);
} }

62
tap.c
View file

@ -769,7 +769,7 @@ restart:
} }
/** /**
* tap_sock_init_unix() - Create and bind AF_UNIX socket, wait for connection * tap_sock_init_unix() - Create and bind AF_UNIX socket, listen for connection
* @c: Execution context * @c: Execution context
* *
* #syscalls:passt unlink|unlinkat * #syscalls:passt unlink|unlinkat
@ -777,19 +777,21 @@ restart:
static void tap_sock_init_unix(struct ctx *c) static void tap_sock_init_unix(struct ctx *c)
{ {
int fd = socket(AF_UNIX, SOCK_STREAM, 0), ex; int fd = socket(AF_UNIX, SOCK_STREAM, 0), ex;
struct epoll_event ev = { 0 };
struct sockaddr_un addr = { struct sockaddr_un addr = {
.sun_family = AF_UNIX, .sun_family = AF_UNIX,
}; };
int i, ret, v = INT_MAX / 2; int i, ret;
if (c->fd_tap_listen) if (c->fd_tap_listen != -1) {
epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_tap_listen, &ev);
close(c->fd_tap_listen); close(c->fd_tap_listen);
}
if (fd < 0) { if (fd < 0) {
perror("UNIX socket"); perror("UNIX socket");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
c->fd_tap_listen = fd;
for (i = 1; i < UNIX_SOCK_MAX; i++) { for (i = 1; i < UNIX_SOCK_MAX; i++) {
char *path = addr.sun_path; char *path = addr.sun_path;
@ -836,6 +838,10 @@ static void tap_sock_init_unix(struct ctx *c)
listen(fd, 0); listen(fd, 0);
ev.data.fd = c->fd_tap_listen = fd;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap_listen, &ev);
info("You can now start qrap:"); info("You can now start qrap:");
info(" ./qrap 5 kvm ... -net socket,fd=5 -net nic,model=virtio"); info(" ./qrap 5 kvm ... -net socket,fd=5 -net nic,model=virtio");
info("or directly qemu, patched with:"); info("or directly qemu, patched with:");
@ -843,14 +849,32 @@ static void tap_sock_init_unix(struct ctx *c)
info("as follows:"); info("as follows:");
info(" kvm ... -net socket,connect=%s -net nic,model=virtio", info(" kvm ... -net socket,connect=%s -net nic,model=virtio",
addr.sun_path); addr.sun_path);
}
c->fd_tap = accept(fd, NULL, NULL); /**
* tap_sock_accept_unix() - Accept connection on listening socket
* @c: Execution context
*/
static void tap_sock_accept_unix(struct ctx *c)
{
struct epoll_event ev = { 0 };
int v = INT_MAX / 2;
c->fd_tap = accept(c->fd_tap_listen, NULL, NULL);
epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_tap_listen, &ev);
close(c->fd_tap_listen);
c->fd_tap_listen = -1;
if (!c->low_rmem) if (!c->low_rmem)
setsockopt(c->fd_tap, SOL_SOCKET, SO_RCVBUF, &v, sizeof(v)); setsockopt(c->fd_tap, SOL_SOCKET, SO_RCVBUF, &v, sizeof(v));
if (!c->low_wmem) if (!c->low_wmem)
setsockopt(c->fd_tap, SOL_SOCKET, SO_SNDBUF, &v, sizeof(v)); setsockopt(c->fd_tap, SOL_SOCKET, SO_SNDBUF, &v, sizeof(v));
ev.data.fd = c->fd_tap;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap, &ev);
} }
static int tun_ns_fd = -1; static int tun_ns_fd = -1;
@ -885,6 +909,8 @@ static int tap_ns_tun(void *arg)
*/ */
static void tap_sock_init_tun(struct ctx *c) static void tap_sock_init_tun(struct ctx *c)
{ {
struct epoll_event ev = { 0 };
NS_CALL(tap_ns_tun, c); NS_CALL(tap_ns_tun, c);
if (tun_ns_fd == -1) { if (tun_ns_fd == -1) {
err("Failed to open tun socket in namespace"); err("Failed to open tun socket in namespace");
@ -896,6 +922,10 @@ static void tap_sock_init_tun(struct ctx *c)
pcap_init(c, c->pasta_netns_fd); pcap_init(c, c->pasta_netns_fd);
c->fd_tap = tun_ns_fd; c->fd_tap = tun_ns_fd;
ev.data.fd = c->fd_tap;
ev.events = EPOLLIN | EPOLLRDHUP;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap, &ev);
} }
/** /**
@ -904,33 +934,31 @@ static void tap_sock_init_tun(struct ctx *c)
*/ */
void tap_sock_init(struct ctx *c) void tap_sock_init(struct ctx *c)
{ {
struct epoll_event ev = { 0 }; if (c->fd_tap != -1) {
if (c->fd_tap) {
epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_tap, NULL); epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_tap, NULL);
close(c->fd_tap); close(c->fd_tap);
} }
if (c->mode == MODE_PASST) { if (c->mode == MODE_PASST)
tap_sock_init_unix(c); tap_sock_init_unix(c);
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP; else
} else {
tap_sock_init_tun(c); tap_sock_init_tun(c);
ev.events = EPOLLIN | EPOLLRDHUP;
}
ev.data.fd = c->fd_tap;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap, &ev);
} }
/** /**
* tap_handler() - Packet handler for AF_UNIX or tuntap file descriptor * tap_handler() - Packet handler for AF_UNIX or tuntap file descriptor
* @c: Execution context * @c: Execution context
* @fd: File descriptor where event occurred
* @events: epoll events * @events: epoll events
* @now: Current timestamp * @now: Current timestamp
*/ */
void tap_handler(struct ctx *c, uint32_t events, struct timespec *now) void tap_handler(struct ctx *c, int fd, uint32_t events, struct timespec *now)
{ {
if (fd == c->fd_tap_listen && events == EPOLLIN) {
tap_sock_accept_unix(c);
return;
}
if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
goto fail; goto fail;

2
tap.h
View file

@ -6,5 +6,5 @@
void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto, void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto,
char *in, size_t len, uint32_t flow); char *in, size_t len, uint32_t flow);
int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre); int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre);
void tap_handler(struct ctx *c, uint32_t events, struct timespec *now); void tap_handler(struct ctx *c, int fd, uint32_t events, struct timespec *now);
void tap_sock_init(struct ctx *c); void tap_sock_init(struct ctx *c);

2
tcp.c
View file

@ -2319,7 +2319,7 @@ recvmsg:
if (errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EAGAIN || errno == EWOULDBLOCK)
return 0; return 0;
tap_handler(c, EPOLLERR, now); tap_handler(c, c->fd_tap, EPOLLERR, now);
} }
i--; i--;