passt, tap: Add --fd option

This passes a fully connected stream socket to passt.

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
[sbrivio: reuse fd_tap instead of adding a new descriptor,
 imply --one-off on --fd, add to optstring and usage()]
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Richard W.M. Jones 2022-11-17 18:49:34 +00:00 committed by Stefano Brivio
parent 15119dcf6c
commit 6b4e68383c
5 changed files with 46 additions and 4 deletions

28
conf.c
View file

@ -719,6 +719,7 @@ static void usage(const char *name)
UNIX_SOCK_PATH, 1); UNIX_SOCK_PATH, 1);
} }
info( " -F, --fd FD Use FD as pre-opened connected socket");
info( " -p, --pcap FILE Log tap-facing traffic to pcap file"); info( " -p, --pcap FILE Log tap-facing traffic to pcap file");
info( " -P, --pid FILE Write own PID to the given file"); info( " -P, --pid FILE Write own PID to the given file");
info( " -m, --mtu MTU Assign MTU via DHCP/NDP"); info( " -m, --mtu MTU Assign MTU via DHCP/NDP");
@ -1079,6 +1080,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"log-file", required_argument, NULL, 'l' }, {"log-file", required_argument, NULL, 'l' },
{"help", no_argument, NULL, 'h' }, {"help", no_argument, NULL, 'h' },
{"socket", required_argument, NULL, 's' }, {"socket", required_argument, NULL, 's' },
{"fd", required_argument, NULL, 'F' },
{"ns-ifname", required_argument, NULL, 'I' }, {"ns-ifname", required_argument, NULL, 'I' },
{"pcap", required_argument, NULL, 'p' }, {"pcap", required_argument, NULL, 'p' },
{"pid", required_argument, NULL, 'P' }, {"pid", required_argument, NULL, 'P' },
@ -1138,9 +1140,9 @@ void conf(struct ctx *c, int argc, char **argv)
if (c->mode == MODE_PASTA) { if (c->mode == MODE_PASTA) {
c->no_dhcp_dns = c->no_dhcp_dns_search = 1; c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
optstring = "dqfel:hI:p:P:m:a:n:M:g:i:D:S:46t:u:T:U:"; optstring = "dqfel:hF:I:p:P:m:a:n:M:g:i:D:S:46t:u:T:U:";
} else { } else {
optstring = "dqfel:hs:p:P:m:a:n:M:g:i:D:S:461t:u:"; optstring = "dqfel:hs:F:p:P:m:a:n:M:g:i:D:S:461t:u:";
} }
c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = 0; c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = 0;
@ -1355,6 +1357,23 @@ void conf(struct ctx *c, int argc, char **argv)
err("Invalid socket path: %s", optarg); err("Invalid socket path: %s", optarg);
usage(argv[0]); usage(argv[0]);
} }
break;
case 'F':
if (c->fd_tap >= 0) {
err("Multiple --fd options given");
usage(argv[0]);
}
errno = 0;
c->fd_tap = strtol(optarg, NULL, 0);
if (c->fd_tap < 0 || errno) {
err("Invalid --fd: %s", optarg);
usage(argv[0]);
}
c->one_off = true;
break; break;
case 'I': case 'I':
if (*c->pasta_ifn) { if (*c->pasta_ifn) {
@ -1590,6 +1609,11 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]); usage(argv[0]);
} }
if (*c->sock_path && c->fd_tap >= 0) {
err("Options --socket and --fd are mutually exclusive");
usage(argv[0]);
}
ret = conf_ugid(runas, &uid, &gid); ret = conf_ugid(runas, &uid, &gid);
if (ret) if (ret)
usage(argv[0]); usage(argv[0]);

10
passt.1
View file

@ -297,6 +297,16 @@ Path for UNIX domain socket used by \fBqemu\fR(1) or \fBqrap\fR(1) to connect to
Default is to probe a free socket, not accepting connections, starting from Default is to probe a free socket, not accepting connections, starting from
\fI/tmp/passt_1.socket\fR to \fI/tmp/passt_64.socket\fR. \fI/tmp/passt_1.socket\fR to \fI/tmp/passt_64.socket\fR.
.TP
.BR \-F ", " \-\-fd " " \fIFD
Pass a pre-opened, connected socket to \fBpasst\fR. Usually the socket is opened
in the parent process and \fBpasst\fR inherits it when run as a child. This
allows the parent process to open sockets using another address family or
requiring special privileges.
This option implies the behaviour described for \-\-one-off, once this socket
is closed.
.TP .TP
.BR \-1 ", " \-\-one-off .BR \-1 ", " \-\-one-off
Quit after handling a single client connection, that is, once the client closes Quit after handling a single client connection, that is, once the client closes

View file

@ -255,7 +255,6 @@ int main(int argc, char **argv)
quit_fd = pasta_netns_quit_init(&c); quit_fd = pasta_netns_quit_init(&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);

View file

@ -159,7 +159,7 @@ struct ip6_ctx {
* @proc_net_udp: Stored handles for /proc/net/udp{,6} in init and ns * @proc_net_udp: Stored handles for /proc/net/udp{,6} in init and ns
* @epollfd: File descriptor for epoll instance * @epollfd: File descriptor for epoll instance
* @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any * @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any
* @fd_tap: File descriptor for AF_UNIX socket or tuntap device * @fd_tap: AF_UNIX socket, tuntap device, or pre-opened socket
* @mac: Host MAC address * @mac: Host MAC address
* @mac_guest: MAC address of guest or namespace, seen or configured * @mac_guest: MAC address of guest or namespace, seen or configured
* @ifi4: Index of routable interface for IPv4, 0 if IPv4 disabled * @ifi4: Index of routable interface for IPv4, 0 if IPv4 disabled

9
tap.c
View file

@ -1069,6 +1069,15 @@ void tap_sock_init(struct ctx *c)
} }
if (c->fd_tap != -1) { if (c->fd_tap != -1) {
if (c->one_off) { /* Passed as --fd */
struct epoll_event ev = { 0 };
ev.data.fd = c->fd_tap;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_tap, &ev);
return;
}
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);
c->fd_tap = -1; c->fd_tap = -1;