From 34e642923538a05ac21d7e7495da23fb0da56c5f Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 26 Jan 2022 16:39:33 +0100 Subject: [PATCH] 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 --- passt.c | 6 ++++-- tap.c | 62 +++++++++++++++++++++++++++++++++++++++++---------------- tap.h | 2 +- tcp.c | 2 +- 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/passt.c b/passt.c index 3c9fb90..a8bb88e 100644 --- a/passt.c +++ b/passt.c @@ -345,6 +345,7 @@ int main(int argc, char **argv) } sock_probe_mem(&c); + c.fd_tap = c.fd_tap_listen = -1; tap_sock_init(&c); clock_gettime(CLOCK_MONOTONIC, &now); @@ -387,9 +388,10 @@ loop: for (i = 0; i < nfds; i++) { 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) - tap_handler(&c, events[i].events, &now); + if (fd == c.fd_tap || fd == c.fd_tap_listen) + tap_handler(&c, fd, events[i].events, &now); else sock_handler(&c, ref, events[i].events, &now); } diff --git a/tap.c b/tap.c index 2bf6f71..34a5705 100644 --- a/tap.c +++ b/tap.c @@ -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 * * #syscalls:passt unlink|unlinkat @@ -777,19 +777,21 @@ restart: static void tap_sock_init_unix(struct ctx *c) { int fd = socket(AF_UNIX, SOCK_STREAM, 0), ex; + struct epoll_event ev = { 0 }; struct sockaddr_un addr = { .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); + } if (fd < 0) { perror("UNIX socket"); exit(EXIT_FAILURE); } - c->fd_tap_listen = fd; for (i = 1; i < UNIX_SOCK_MAX; i++) { char *path = addr.sun_path; @@ -836,6 +838,10 @@ static void tap_sock_init_unix(struct ctx *c) 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(" ./qrap 5 kvm ... -net socket,fd=5 -net nic,model=virtio"); info("or directly qemu, patched with:"); @@ -843,14 +849,32 @@ static void tap_sock_init_unix(struct ctx *c) info("as follows:"); info(" kvm ... -net socket,connect=%s -net nic,model=virtio", 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) setsockopt(c->fd_tap, SOL_SOCKET, SO_RCVBUF, &v, sizeof(v)); if (!c->low_wmem) 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; @@ -885,6 +909,8 @@ static int tap_ns_tun(void *arg) */ static void tap_sock_init_tun(struct ctx *c) { + struct epoll_event ev = { 0 }; + NS_CALL(tap_ns_tun, c); if (tun_ns_fd == -1) { 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); 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) { - struct epoll_event ev = { 0 }; - - if (c->fd_tap) { + if (c->fd_tap != -1) { epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_tap, NULL); close(c->fd_tap); } - if (c->mode == MODE_PASST) { + if (c->mode == MODE_PASST) tap_sock_init_unix(c); - ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP; - } else { + else 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 * @c: Execution context + * @fd: File descriptor where event occurred * @events: epoll events * @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)) goto fail; diff --git a/tap.h b/tap.h index c437f5f..8942fcf 100644 --- a/tap.h +++ b/tap.h @@ -6,5 +6,5 @@ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto, char *in, size_t len, uint32_t flow); 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); diff --git a/tcp.c b/tcp.c index 01f09e9..7122898 100644 --- a/tcp.c +++ b/tcp.c @@ -2319,7 +2319,7 @@ recvmsg: if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; - tap_handler(c, EPOLLERR, now); + tap_handler(c, c->fd_tap, EPOLLERR, now); } i--;