aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--conf.c43
-rw-r--r--passt.15
-rw-r--r--passt.c7
-rw-r--r--passt.h7
-rw-r--r--pasta.c52
-rw-r--r--pasta.h2
7 files changed, 107 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index 8477cf0..28ef316 100644
--- a/Makefile
+++ b/Makefile
@@ -153,6 +153,7 @@ pkgs:
# - android-cloexec-pipe
# - android-cloexec-pipe2
# - android-cloexec-epoll-create1
+# - android-cloexec-inotify-init1
# TODO: check, fix except for the few cases where we need to share fds
#
# - bugprone-narrowing-conversions
@@ -197,7 +198,7 @@ clang-tidy: $(wildcard *.c) $(wildcard *.h)
-cppcoreguidelines-avoid-magic-numbers,\
-readability-isolate-declaration,\
-android-cloexec-open,-android-cloexec-pipe,-android-cloexec-pipe2,\
- -android-cloexec-epoll-create1,\
+ -android-cloexec-epoll-create1,-android-cloexec-inotify-init1,\
-bugprone-narrowing-conversions,\
-cppcoreguidelines-narrowing-conversions,\
-cppcoreguidelines-avoid-non-const-global-variables,\
diff --git a/conf.c b/conf.c
index 21e9bc0..9851575 100644
--- a/conf.c
+++ b/conf.c
@@ -20,6 +20,7 @@
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <libgen.h>
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
@@ -414,20 +415,34 @@ static int conf_ns_opt(struct ctx *c,
nfd = open(netns, O_RDONLY);
- if (nfd >= 0 && (ufd >= 0 || c->netns_only)) {
- c->pasta_netns_fd = nfd;
- c->pasta_userns_fd = ufd;
+ if (nfd == -1 || (ufd == -1 && !c->netns_only)) {
+ if (nfd >= 0)
+ close(nfd);
- NS_CALL(conf_ns_check, c);
- if (c->pasta_netns_fd >= 0)
- return 0;
+ if (ufd >= 0)
+ close(ufd);
+
+ continue;
}
- if (nfd >= 0)
- close(nfd);
+ c->pasta_netns_fd = nfd;
+ c->pasta_userns_fd = ufd;
+
+ NS_CALL(conf_ns_check, c);
+
+ if (c->pasta_netns_fd >= 0) {
+ char buf[PATH_MAX];
+
+ if (try == 0 || c->no_netns_quit)
+ return 0;
+
+ strncpy(buf, netns, PATH_MAX);
+ strncpy(c->netns_base, basename(buf), PATH_MAX - 1);
+ strncpy(buf, netns, PATH_MAX);
+ strncpy(c->netns_dir, dirname(buf), PATH_MAX - 1);
- if (ufd >= 0)
- close(ufd);
+ return 0;
+ }
}
c->netns_only = netns_only_reset;
@@ -813,6 +828,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"dhcp-search", no_argument, NULL, 7 },
{"no-dhcp-search", no_argument, NULL, 8 },
{"dns-forward", required_argument, NULL, 9 },
+ {"no-netns-quit", no_argument, NULL, 10 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -937,6 +953,13 @@ void conf(struct ctx *c, int argc, char **argv)
err("Invalid DNS forwarding address: %s", optarg);
usage(argv[0]);
break;
+ case 10:
+ if (c->mode != MODE_PASTA) {
+ err("--no-netns-quit is for pasta mode only");
+ usage(argv[0]);
+ }
+ c->no_netns_quit = 1;
+ break;
case 'd':
if (c->debug) {
err("Multiple --debug options given");
diff --git a/passt.1 b/passt.1
index 7070a31..485e1db 100644
--- a/passt.1
+++ b/passt.1
@@ -427,6 +427,11 @@ for sandboxing purposes either. This is implied if PATH or NAME are given
without \-\-userns.
.TP
+.BR \-\-no-netns-quit
+If the target network namespace is bound to the filesystem (that is, if PATH or
+NAME are given as target), do not exit once the network namespace is deleted.
+
+.TP
.BR \-\-nsrun-dir " " \fIpath
Directory for nsfs mountpoints, used as path prefix for names of namespaces.
diff --git a/passt.c b/passt.c
index 67ad1c7..36f0161 100644
--- a/passt.c
+++ b/passt.c
@@ -301,7 +301,7 @@ void exit_handler(int signal)
*/
int main(int argc, char **argv)
{
- int nfds, i, devnull_fd = -1, pidfile_fd = -1;
+ int nfds, i, devnull_fd = -1, pidfile_fd = -1, quit_fd;
struct epoll_event events[EPOLL_EVENTS];
struct ctx c = { 0 };
struct rlimit limit;
@@ -357,6 +357,8 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ quit_fd = pasta_netns_quit_init(&c);
+
if (getrlimit(RLIMIT_NOFILE, &limit)) {
perror("getrlimit");
exit(EXIT_FAILURE);
@@ -416,6 +418,7 @@ int main(int argc, char **argv)
seccomp(&c);
timer_init(&c, &now);
+
loop:
nfds = epoll_wait(c.epollfd, events, EPOLL_EVENTS, TIMER_INTERVAL);
if (nfds == -1 && errno != EINTR) {
@@ -431,6 +434,8 @@ loop:
if (fd == c.fd_tap || fd == c.fd_tap_listen)
tap_handler(&c, fd, events[i].events, &now);
+ else if (fd == quit_fd)
+ pasta_netns_quit_handler(&c, fd);
else
sock_handler(&c, ref, events[i].events, &now);
}
diff --git a/passt.h b/passt.h
index 2589ee7..042f760 100644
--- a/passt.h
+++ b/passt.h
@@ -101,6 +101,9 @@ enum passt_modes {
* @pasta_netns_fd: File descriptor for network namespace in pasta mode
* @pasta_userns_fd: Descriptor for user namespace to join, -1 once joined
* @netns_only: In pasta mode, don't join or create a user namespace
+ * @no_netns_quit: In pasta mode, don't exit if fs-bound namespace is gone
+ * @netns_base: Base name for fs-bound namespace, if any, in pasta mode
+ * @netns_dir: Directory of fs-bound namespace, if any, in pasta mode
* @proc_net_tcp: Stored handles for /proc/net/tcp{,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
@@ -161,6 +164,10 @@ struct ctx {
int pasta_userns_fd;
int netns_only;
+ int no_netns_quit;
+ char netns_base[PATH_MAX];
+ char netns_dir[PATH_MAX];
+
int proc_net_tcp[IP_VERSIONS][2];
int proc_net_udp[IP_VERSIONS][2];
diff --git a/pasta.c b/pasta.c
index 972cbcf..e45cc92 100644
--- a/pasta.c
+++ b/pasta.c
@@ -24,6 +24,8 @@
#include <stdint.h>
#include <unistd.h>
#include <syslog.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -219,3 +221,53 @@ void pasta_ns_conf(struct ctx *c)
proto_update_l2_buf(c->mac_guest, NULL, NULL);
}
+
+/**
+ * pasta_netns_quit_init() - Watch network namespace to quit once it's gone
+ * @c: Execution context
+ *
+ * Return: inotify file descriptor, -1 on failure or if not needed/applicable
+ */
+int pasta_netns_quit_init(struct ctx *c)
+{
+ struct epoll_event ev = { .events = EPOLLIN };
+ int inotify_fd;
+
+ if (c->mode != MODE_PASTA || c->no_netns_quit || !*c->netns_base)
+ return -1;
+
+ if ((inotify_fd = inotify_init1(O_NONBLOCK)) < 0) {
+ perror("inotify_init(): won't quit once netns is gone");
+ return -1;
+ }
+
+ if (inotify_add_watch(inotify_fd, c->netns_dir, IN_DELETE) < 0) {
+ perror("inotify_add_watch(): won't quit once netns is gone");
+ return -1;
+ }
+
+ ev.data.fd = inotify_fd;
+ epoll_ctl(c->epollfd, EPOLL_CTL_ADD, inotify_fd, &ev);
+
+ return inotify_fd;
+}
+
+/**
+ * pasta_netns_quit_handler() - Handle ns directory events, exit if ns is gone
+ * @c: Execution context
+ * @inotify_fd: inotify file descriptor with watch on namespace directory
+ */
+void pasta_netns_quit_handler(struct ctx *c, int inotify_fd)
+{
+ char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
+ struct inotify_event *in_ev = (struct inotify_event *)buf;
+
+ if (read(inotify_fd, buf, sizeof(buf)) < (ssize_t)sizeof(*in_ev))
+ return;
+
+ if (strncmp(in_ev->name, c->netns_base, sizeof(c->netns_base)))
+ return;
+
+ info("Namespace %s is gone, exiting", c->netns_base);
+ exit(EXIT_SUCCESS);
+}
diff --git a/pasta.h b/pasta.h
index 1fcd6a9..235bfb9 100644
--- a/pasta.h
+++ b/pasta.h
@@ -6,3 +6,5 @@
void pasta_start_ns(struct ctx *c);
void pasta_ns_conf(struct ctx *c);
void pasta_child_handler(int signal);
+int pasta_netns_quit_init(struct ctx *c);
+void pasta_netns_quit_handler(struct ctx *c, int inotify_fd);