summaryrefslogtreecommitdiff
path: root/src/network/netdev
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-08-13 17:18:55 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-08-16 21:57:35 +0900
commitaf7a86b8a6b6510264b7ac0ae6a1e1d37d510ef5 (patch)
treedc45da1110cd80232ea6b2c899920d2542e08fde /src/network/netdev
parentf8b7c177640e19a0146fa26c4263e713b7045222 (diff)
downloadsystemd-af7a86b8a6b6510264b7ac0ae6a1e1d37d510ef5.tar.gz
network/tuntap: save tun or tap file descriptor in fd store
Diffstat (limited to 'src/network/netdev')
-rw-r--r--src/network/netdev/netdev.c3
-rw-r--r--src/network/netdev/netdev.h3
-rw-r--r--src/network/netdev/tuntap.c93
-rw-r--r--src/network/netdev/tuntap.h3
4 files changed, 100 insertions, 2 deletions
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 464f47f2cf..212df3daa0 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -237,6 +237,9 @@ void netdev_drop(NetDev *netdev) {
return;
}
+ if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
+ NETDEV_VTABLE(netdev)->drop(netdev);
+
netdev->state = NETDEV_STATE_LINGER;
log_netdev_debug(netdev, "netdev removed");
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 1c7dc0f7e5..49eadbb7a4 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -142,6 +142,9 @@ typedef struct NetDevVTable {
* to be set != 0. */
void (*init)(NetDev *n);
+ /* This is called when the interface is removed. */
+ void (*drop)(NetDev *n);
+
/* This should free all kind-specific variables. It should be
* idempotent. */
void (*done)(NetDev *n);
diff --git a/src/network/netdev/tuntap.c b/src/network/netdev/tuntap.c
index f48ebf268a..39ea7c1d73 100644
--- a/src/network/netdev/tuntap.c
+++ b/src/network/netdev/tuntap.c
@@ -10,7 +10,11 @@
#include <linux/if_tun.h>
#include "alloc-util.h"
+#include "daemon-util.h"
#include "fd-util.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "socket-util.h"
#include "tuntap.h"
#include "user-util.h"
@@ -29,6 +33,73 @@ static TunTap* TUNTAP(NetDev *netdev) {
}
}
+static void *close_fd_ptr(void *p) {
+ safe_close(PTR_TO_FD(p));
+ return NULL;
+}
+
+DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
+
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
+ _cleanup_free_ char *tuntap_name = NULL;
+ const char *p;
+ int r;
+
+ assert(m);
+ assert(fd >= 0);
+ assert(name);
+
+ p = startswith(name, "tuntap-");
+ if (!p)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unknown fd (%s).", name);
+
+ if (!ifname_valid(p))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received tuntap fd with invalid name (%s).", p);
+
+ tuntap_name = strdup(p);
+ if (!tuntap_name)
+ return log_oom_debug();
+
+ r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to store tuntap fd: %m");
+
+ TAKE_PTR(tuntap_name);
+ return 0;
+}
+
+void manager_clear_unmanaged_tuntap_fds(Manager *m) {
+ char *name;
+ void *p;
+
+ assert(m);
+
+ while ((p = hashmap_steal_first_key_and_value(m->tuntap_fds_by_name, (void**) &name))) {
+ close_and_notify_warn(PTR_TO_FD(p), name);
+ name = mfree(name);
+ }
+}
+
+static int tuntap_take_fd(NetDev *netdev) {
+ _cleanup_free_ char *name = NULL;
+ void *p;
+ int r;
+
+ assert(netdev);
+ assert(netdev->manager);
+
+ r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
+ if (r < 0)
+ return r;
+
+ p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
+ if (!p)
+ return -ENOENT;
+
+ log_netdev_debug(netdev, "Found file descriptor in fd store.");
+ return PTR_TO_FD(p);
+}
+
static int netdev_create_tuntap(NetDev *netdev) {
_cleanup_close_ int fd = -1;
struct ifreq ifr = {};
@@ -39,7 +110,11 @@ static int netdev_create_tuntap(NetDev *netdev) {
t = TUNTAP(netdev);
assert(t);
- fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
+ fd = TAKE_FD(t->fd);
+ if (fd < 0)
+ fd = tuntap_take_fd(netdev);
+ if (fd < 0)
+ fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
if (fd < 0)
return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
@@ -90,8 +165,10 @@ static int netdev_create_tuntap(NetDev *netdev) {
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
- if (t->keep_fd)
+ if (t->keep_fd) {
t->fd = TAKE_FD(fd);
+ (void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
+ }
return 0;
}
@@ -106,6 +183,16 @@ static void tuntap_init(NetDev *netdev) {
t->fd = -1;
}
+static void tuntap_drop(NetDev *netdev) {
+ TunTap *t;
+
+ assert(netdev);
+ t = TUNTAP(netdev);
+ assert(t);
+
+ t->fd = close_and_notify_warn(t->fd, netdev->ifname);
+}
+
static void tuntap_done(NetDev *netdev) {
TunTap *t;
@@ -141,6 +228,7 @@ const NetDevVTable tun_vtable = {
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
.config_verify = tuntap_verify,
.init = tuntap_init,
+ .drop = tuntap_drop,
.done = tuntap_done,
.create = netdev_create_tuntap,
.create_type = NETDEV_CREATE_INDEPENDENT,
@@ -152,6 +240,7 @@ const NetDevVTable tap_vtable = {
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
.config_verify = tuntap_verify,
.init = tuntap_init,
+ .drop = tuntap_drop,
.done = tuntap_done,
.create = netdev_create_tuntap,
.create_type = NETDEV_CREATE_INDEPENDENT,
diff --git a/src/network/netdev/tuntap.h b/src/network/netdev/tuntap.h
index 52f2da9fab..88e0ce5f97 100644
--- a/src/network/netdev/tuntap.h
+++ b/src/network/netdev/tuntap.h
@@ -21,3 +21,6 @@ DEFINE_NETDEV_CAST(TUN, TunTap);
DEFINE_NETDEV_CAST(TAP, TunTap);
extern const NetDevVTable tun_vtable;
extern const NetDevVTable tap_vtable;
+
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name);
+void manager_clear_unmanaged_tuntap_fds(Manager *m);