diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-08-13 17:18:55 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-08-16 21:57:35 +0900 |
commit | af7a86b8a6b6510264b7ac0ae6a1e1d37d510ef5 (patch) | |
tree | dc45da1110cd80232ea6b2c899920d2542e08fde /src/network/netdev | |
parent | f8b7c177640e19a0146fa26c4263e713b7045222 (diff) | |
download | systemd-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.c | 3 | ||||
-rw-r--r-- | src/network/netdev/netdev.h | 3 | ||||
-rw-r--r-- | src/network/netdev/tuntap.c | 93 | ||||
-rw-r--r-- | src/network/netdev/tuntap.h | 3 |
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); |