aboutgitcodebugslistschat
path: root/tap.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2022-01-26 16:39:33 +0100
committerStefano Brivio <sbrivio@redhat.com>2022-01-28 18:51:50 +0100
commit34e642923538a05ac21d7e7495da23fb0da56c5f (patch)
tree7bf87c1259114dd95d05302d9fdc9aa985edbab7 /tap.c
parentb1f5688495665269fb17732a3c7fb91c709e61b6 (diff)
downloadpasst-34e642923538a05ac21d7e7495da23fb0da56c5f.tar
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.tar.gz
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.tar.bz2
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.tar.lz
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.tar.xz
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.tar.zst
passt-34e642923538a05ac21d7e7495da23fb0da56c5f.zip
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>
Diffstat (limited to 'tap.c')
-rw-r--r--tap.c62
1 files changed, 45 insertions, 17 deletions
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;