mirror of
https://github.com/systemd/systemd.git
synced 2025-01-23 02:04:32 +03:00
network/tuntap: manage tun/tap fds by manager
Otherwise, when a .netdev file for tun or tap netdev is updated, reloading the file leaks the previous file descriptor.
This commit is contained in:
parent
69bd661a2d
commit
34e5440fb2
@ -36,15 +36,33 @@ static TunTap* TUNTAP(NetDev *netdev) {
|
||||
|
||||
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) {
|
||||
static int manager_add_tuntap_fd_impl(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);
|
||||
|
||||
tuntap_name = strdup(name);
|
||||
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;
|
||||
}
|
||||
|
||||
int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
|
||||
const char *p;
|
||||
|
||||
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);
|
||||
@ -52,66 +70,76 @@ int manager_add_tuntap_fd(Manager *m, int fd, const char *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();
|
||||
return manager_add_tuntap_fd_impl(m, fd, p);
|
||||
}
|
||||
|
||||
r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
|
||||
static int netdev_take_tuntap_fd(Manager *m, const char *ifname) {
|
||||
_unused_ _cleanup_free_ char *name = NULL;
|
||||
void *p;
|
||||
|
||||
assert(m);
|
||||
assert(ifname);
|
||||
|
||||
p = hashmap_remove2(m->tuntap_fds_by_name, ifname, (void**) &name);
|
||||
if (!p)
|
||||
return -EBADF;
|
||||
|
||||
return PTR_TO_FD(p);
|
||||
}
|
||||
|
||||
static int netdev_push_tuntap_fd(NetDev *netdev, int fd) {
|
||||
_unused_ _cleanup_close_ int fd_old = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(netdev->manager);
|
||||
|
||||
fd_old = netdev_take_tuntap_fd(netdev->manager, netdev->ifname);
|
||||
|
||||
if (!TUNTAP(netdev)->keep_fd)
|
||||
return 0;
|
||||
|
||||
r = manager_add_tuntap_fd_impl(netdev->manager, fd, netdev->ifname);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to store tuntap fd: %m");
|
||||
return r;
|
||||
|
||||
TAKE_PTR(tuntap_name);
|
||||
return 0;
|
||||
(void) notify_push_fdf(fd, "tuntap-%s", netdev->ifname);
|
||||
return 1; /* saved */
|
||||
}
|
||||
|
||||
static void manager_close_and_notify_tuntap_fd(Manager *m, const char *ifname) {
|
||||
assert(m);
|
||||
assert(ifname);
|
||||
|
||||
/* netdev_take_tuntap_fd() may invalidate ifname. Hence, need to create fdname earlier. */
|
||||
const char *fdname = strjoina("tuntap-", ifname);
|
||||
close_and_notify_warn(netdev_take_tuntap_fd(m, ifname), fdname);
|
||||
}
|
||||
|
||||
void manager_clear_unmanaged_tuntap_fds(Manager *m) {
|
||||
char *name;
|
||||
const 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);
|
||||
HASHMAP_FOREACH_KEY(p, name, m->tuntap_fds_by_name) {
|
||||
NetDev *netdev;
|
||||
|
||||
if (netdev_get(m, name, &netdev) < 0 ||
|
||||
!IN_SET(netdev->kind, NETDEV_KIND_TAP, NETDEV_KIND_TUN) ||
|
||||
!TUNTAP(netdev)->keep_fd)
|
||||
manager_close_and_notify_tuntap_fd(m, 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 = -EBADF;
|
||||
struct ifreq ifr = {};
|
||||
TunTap *t;
|
||||
TunTap *t = TUNTAP(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
fd = TAKE_FD(t->fd);
|
||||
if (fd < 0)
|
||||
fd = tuntap_take_fd(netdev);
|
||||
if (fd < 0)
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
|
||||
|
||||
@ -175,42 +203,25 @@ 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) {
|
||||
t->fd = TAKE_FD(fd);
|
||||
(void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
|
||||
}
|
||||
r = netdev_push_tuntap_fd(netdev, fd);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to save TUN/TAP fd: %m");
|
||||
if (r > 0)
|
||||
TAKE_FD(fd);
|
||||
|
||||
netdev_enter_ready(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tuntap_init(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = -EBADF;
|
||||
}
|
||||
|
||||
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);
|
||||
manager_close_and_notify_tuntap_fd(netdev->manager, netdev->ifname);
|
||||
}
|
||||
|
||||
static void tuntap_done(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
TunTap *t = TUNTAP(netdev);
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = safe_close(t->fd);
|
||||
t->user_name = mfree(t->user_name);
|
||||
t->group_name = mfree(t->group_name);
|
||||
}
|
||||
@ -237,7 +248,6 @@ const NetDevVTable tun_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
@ -249,7 +259,6 @@ const NetDevVTable tap_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
|
@ -8,7 +8,6 @@ typedef struct TunTap TunTap;
|
||||
struct TunTap {
|
||||
NetDev meta;
|
||||
|
||||
int fd;
|
||||
char *user_name;
|
||||
char *group_name;
|
||||
bool multi_queue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user