Merge pull request #24301 from yuwata/network-tuntap

network/tuntap: introduce KeepFileDescriptor= setting
This commit is contained in:
Luca Boccassi
2022-08-16 23:06:16 +01:00
committed by GitHub
20 changed files with 378 additions and 98 deletions

View File

@@ -1558,6 +1558,15 @@
<filename>/dev/net/tun</filename> device.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>KeepCarrier=</varname></term>
<listitem>
<para>Takes a boolean. If enabled, to make the interface maintain its carrier status, the file
descriptor of the interface is kept open. This may be useful to keep the interface in running
state, for example while the backing process is temporarily shutdown. Defaults to
<literal>no</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "daemon-util.h"
#include "fd-util.h"
#include "logind-session-dbus.h"
#include "logind-session-device.h"
@@ -376,19 +377,11 @@ error:
}
void session_device_free(SessionDevice *sd) {
int r;
assert(sd);
/* Make sure to remove the pushed fd. */
if (sd->pushed_fd) {
r = sd_notifyf(false,
"FDSTOREREMOVE=1\n"
"FDNAME=session-%s-device-%u-%u",
sd->session->id, major(sd->dev), minor(sd->dev));
if (r < 0)
log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
}
if (sd->pushed_fd)
(void) notify_remove_fd_warnf("session-%s-device-%u-%u", sd->session->id, major(sd->dev), minor(sd->dev));
session_device_stop(sd);
session_device_notify(sd, SESSION_DEVICE_RELEASE);
@@ -469,7 +462,6 @@ unsigned session_device_try_pause_all(Session *s) {
}
int session_device_save(SessionDevice *sd) {
_cleanup_free_ char *m = NULL;
const char *id;
int r;
@@ -489,13 +481,7 @@ int session_device_save(SessionDevice *sd) {
id = sd->session->id;
assert(*(id + strcspn(id, "-\n")) == '\0');
r = asprintf(&m, "FDSTORE=1\n"
"FDNAME=session-%s-device-%u-%u\n",
id, major(sd->dev), minor(sd->dev));
if (r < 0)
return r;
r = sd_pid_notify_with_fds(0, false, m, &sd->fd, 1);
r = notify_push_fdf(sd->fd, "session-%s-device-%u-%u", id, major(sd->dev), minor(sd->dev));
if (r < 0)
return r;

View File

@@ -438,7 +438,7 @@ static int deliver_fd(Manager *m, const char *fdname, int fd) {
static int manager_attach_fds(Manager *m) {
_cleanup_strv_free_ char **fdnames = NULL;
int r, n;
int n;
/* Upon restart, PID1 will send us back all fds of session devices that we previously opened. Each
* file descriptor is associated with a given session. The session ids are passed through FDNAMES. */
@@ -455,15 +455,9 @@ static int manager_attach_fds(Manager *m) {
if (deliver_fd(m, fdnames[i], fd) >= 0)
continue;
/* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd */
safe_close(fd);
/* Remove from fdstore as well */
r = sd_notifyf(false,
"FDSTOREREMOVE=1\n"
"FDNAME=%s", fdnames[i]);
if (r < 0)
log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
/* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd
* and remove it from fdstore. */
close_and_notify_warn(fd, fdnames[i]);
}
return 0;

View File

@@ -185,12 +185,14 @@ Tun.PacketInfo, config_parse_bool,
Tun.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
Tun.User, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, user_name)
Tun.Group, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, group_name)
Tun.KeepCarrier, config_parse_bool, 0, offsetof(TunTap, keep_fd)
Tap.OneQueue, config_parse_warn_compat, DISABLED_LEGACY, 0
Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
Tap.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr)
Tap.User, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, user_name)
Tap.Group, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(TunTap, group_name)
Tap.KeepCarrier, config_parse_bool, 0, offsetof(TunTap, keep_fd)
Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)

View File

@@ -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");

View File

@@ -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);

View File

@@ -10,119 +10,197 @@
#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"
#define TUN_DEV "/dev/net/tun"
static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
TunTap *t;
static TunTap* TUNTAP(NetDev *netdev) {
assert(netdev);
assert(netdev->ifname);
assert(ifr);
if (netdev->kind == NETDEV_KIND_TAP) {
t = TAP(netdev);
ifr->ifr_flags |= IFF_TAP;
} else {
t = TUN(netdev);
ifr->ifr_flags |= IFF_TUN;
switch (netdev->kind) {
case NETDEV_KIND_TAP:
return TAP(netdev);
case NETDEV_KIND_TUN:
return TUN(netdev);
default:
return NULL;
}
}
if (!t->packet_info)
ifr->ifr_flags |= IFF_NO_PI;
static void *close_fd_ptr(void *p) {
safe_close(PTR_TO_FD(p));
return NULL;
}
if (t->multi_queue)
ifr->ifr_flags |= IFF_MULTI_QUEUE;
DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
if (t->vnet_hdr)
ifr->ifr_flags |= IFF_VNET_HDR;
int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
_cleanup_free_ char *tuntap_name = NULL;
const char *p;
int r;
strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
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;
}
static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
_cleanup_close_ int fd = -1;
TunTap *t = NULL;
const char *user;
const char *group;
uid_t uid;
gid_t gid;
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(ifr);
assert(netdev->manager);
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
if (fd < 0)
return log_netdev_error_errno(netdev, errno, "Failed to open tun dev: %m");
r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
if (r < 0)
return r;
if (ioctl(fd, TUNSETIFF, ifr) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed on tun dev: %m");
p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
if (!p)
return -ENOENT;
if (netdev->kind == NETDEV_KIND_TAP)
t = TAP(netdev);
else
t = TUN(netdev);
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 = {};
TunTap *t;
int r;
assert(netdev);
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);
if (fd < 0)
return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
if (netdev->kind == NETDEV_KIND_TAP)
ifr.ifr_flags |= IFF_TAP;
else
ifr.ifr_flags |= IFF_TUN;
if (!t->packet_info)
ifr.ifr_flags |= IFF_NO_PI;
if (t->multi_queue)
ifr.ifr_flags |= IFF_MULTI_QUEUE;
if (t->vnet_hdr)
ifr.ifr_flags |= IFF_VNET_HDR;
strncpy(ifr.ifr_name, netdev->ifname, IFNAMSIZ-1);
if (ioctl(fd, TUNSETIFF, &ifr) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed: %m");
if (t->user_name) {
user = t->user_name;
const char *user = t->user_name;
uid_t uid;
r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
if (ioctl(fd, TUNSETOWNER, uid) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed on tun dev: %m");
return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed: %m");
}
if (t->group_name) {
group = t->group_name;
const char *group = t->group_name;
gid_t gid;
r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
if (ioctl(fd, TUNSETGROUP, gid) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed on tun dev: %m");
return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed: %m");
}
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed on tun dev: %m");
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);
}
return 0;
}
static int netdev_create_tuntap(NetDev *netdev) {
struct ifreq ifr = {};
int r;
static void tuntap_init(NetDev *netdev) {
TunTap *t;
r = netdev_fill_tuntap_message(netdev, &ifr);
if (r < 0)
return r;
assert(netdev);
t = TUNTAP(netdev);
assert(t);
return netdev_tuntap_add(netdev, &ifr);
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 = NULL;
TunTap *t;
assert(netdev);
if (netdev->kind == NETDEV_KIND_TUN)
t = TUN(netdev);
else
t = TAP(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);
}
@@ -149,6 +227,8 @@ 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,
.create_type = NETDEV_CREATE_INDEPENDENT,
@@ -159,6 +239,8 @@ 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,
.create_type = NETDEV_CREATE_INDEPENDENT,

View File

@@ -8,14 +8,19 @@ typedef struct TunTap TunTap;
struct TunTap {
NetDev meta;
int fd;
char *user_name;
char *group_name;
bool multi_queue;
bool packet_info;
bool vnet_hdr;
bool keep_fd;
};
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);

View File

@@ -64,6 +64,7 @@
#include "strv.h"
#include "tc.h"
#include "tmpfile-util.h"
#include "tuntap.h"
#include "udev-util.h"
#include "util.h"
#include "vrf.h"

View File

@@ -8,7 +8,6 @@
#include <linux/nexthop.h>
#include <linux/nl80211.h>
#include "sd-daemon.h"
#include "sd-netlink.h"
#include "alloc-util.h"
@@ -18,6 +17,7 @@
#include "bus-polkit.h"
#include "bus-util.h"
#include "conf-parser.h"
#include "daemon-util.h"
#include "def.h"
#include "device-private.h"
#include "device-util.h"
@@ -58,6 +58,7 @@
#include "sysctl-util.h"
#include "tclass.h"
#include "tmpfile-util.h"
#include "tuntap.h"
#include "udev-util.h"
/* use 128 MB for receive socket kernel queue. */
@@ -243,22 +244,45 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
static int systemd_netlink_fd(void) {
int n, fd, rtnl_fd = -EINVAL;
static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) {
_cleanup_strv_free_ char **names = NULL;
int n, rtnl_fd = -1;
n = sd_listen_fds(true);
if (n <= 0)
assert(m);
assert(ret_rtnl_fd);
n = sd_listen_fds_with_names(/* unset_environment = */ true, &names);
if (n < 0)
return n;
if (strv_length(names) != (size_t) n)
return -EINVAL;
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
for (int i = 0; i < n; i++) {
int fd = i + SD_LISTEN_FDS_START;
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (rtnl_fd >= 0)
return -EINVAL;
if (rtnl_fd >= 0) {
log_debug("Received multiple netlink socket, ignoring.");
safe_close(fd);
continue;
}
rtnl_fd = fd;
continue;
}
return rtnl_fd;
if (manager_add_tuntap_fd(m, fd, names[i]) >= 0)
continue;
if (m->test_mode)
safe_close(fd);
else
close_and_notify_warn(fd, names[i]);
}
*ret_rtnl_fd = rtnl_fd;
return 0;
}
static int manager_connect_genl(Manager *m) {
@@ -325,18 +349,21 @@ static int manager_setup_rtnl_filter(Manager *manager) {
return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter);
}
static int manager_connect_rtnl(Manager *m) {
int fd, r;
static int manager_connect_rtnl(Manager *m, int fd) {
_unused_ _cleanup_close_ int fd_close = fd;
int r;
assert(m);
fd = systemd_netlink_fd();
/* This takes input fd. */
if (fd < 0)
r = sd_netlink_open(&m->rtnl);
else
r = sd_netlink_open_fd(&m->rtnl, fd);
if (r < 0)
return r;
TAKE_FD(fd_close);
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
* case systemd sets the receive buffer size for us, and the value in the .socket unit
@@ -487,6 +514,7 @@ static int manager_set_keep_configuration(Manager *m) {
}
int manager_setup(Manager *m) {
_cleanup_close_ int rtnl_fd = -1;
int r;
assert(m);
@@ -510,7 +538,11 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
r = manager_connect_rtnl(m);
r = manager_listen_fds(m, &rtnl_fd);
if (r < 0)
return r;
r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd));
if (r < 0)
return r;
@@ -600,6 +632,8 @@ Manager* manager_free(Manager *m) {
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
@@ -678,6 +712,8 @@ int manager_load_config(Manager *m) {
if (r < 0)
return r;
manager_clear_unmanaged_tuntap_fds(m);
r = network_load(m, &m->networks);
if (r < 0)
return r;

View File

@@ -100,6 +100,8 @@ struct Manager {
FirewallContext *fw_ctx;
OrderedSet *request_queue;
Hashmap *tuntap_fds_by_name;
};
int manager_new(Manager **ret, bool test_mode);

76
src/shared/daemon-util.c Normal file
View File

@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "daemon-util.h"
#include "fd-util.h"
#include "log.h"
#include "string-util.h"
static int notify_remove_fd_warn(const char *name) {
int r;
assert(name);
r = sd_notifyf(/* unset_environment = */ false,
"FDSTOREREMOVE=1\n"
"FDNAME=%s", name);
if (r < 0)
return log_warning_errno(r,
"Failed to remove file descriptor \"%s\" from the store, ignoring: %m",
name);
return 0;
}
int notify_remove_fd_warnf(const char *format, ...) {
_cleanup_free_ char *p = NULL;
va_list ap;
int r;
assert(format);
va_start(ap, format);
r = vasprintf(&p, format, ap);
va_end(ap);
if (r < 0)
return log_oom();
return notify_remove_fd_warn(p);
}
int close_and_notify_warn(int fd, const char *name) {
if (name)
(void) notify_remove_fd_warn(name);
return safe_close(fd);
}
static int notify_push_fd(int fd, const char *name) {
_cleanup_free_ char *state = NULL;
assert(fd >= 0);
assert(name);
state = strjoin("FDSTORE=1\n"
"FDNAME=", name);
if (!state)
return -ENOMEM;
return sd_pid_notify_with_fds(0, /* unset_environment = */ false, state, &fd, 1);
}
int notify_push_fdf(int fd, const char *format, ...) {
_cleanup_free_ char *name = NULL;
va_list ap;
int r;
assert(fd >= 0);
assert(format);
va_start(ap, format);
r = vasprintf(&name, format, ap);
va_end(ap);
if (r < 0)
return -ENOMEM;
return notify_push_fd(fd, name);
}

View File

@@ -5,6 +5,8 @@
#include "sd-daemon.h"
#include "macro.h"
#define NOTIFY_READY "READY=1\n" "STATUS=Processing requests..."
#define NOTIFY_STOPPING "STOPPING=1\n" "STATUS=Shutting down..."
@@ -20,3 +22,7 @@ static inline void notify_on_cleanup(const char **p) {
if (*p)
(void) sd_notify(false, *p);
}
int notify_remove_fd_warnf(const char *format, ...) _printf_(1, 2);
int close_and_notify_warn(int fd, const char *name);
int notify_push_fdf(int fd, const char *format, ...) _printf_(2, 3);

View File

@@ -85,6 +85,7 @@ shared_sources = files(
'creds-util.h',
'cryptsetup-util.c',
'cryptsetup-util.h',
'daemon-util.c',
'daemon-util.h',
'data-fd-util.c',
'data-fd-util.h',

View File

@@ -171,6 +171,7 @@ User=
Group=
PacketInfo=
VNetHeader=
KeepCarrier=
[IPVLAN]
Mode=
Flags=
@@ -184,6 +185,7 @@ PacketInfo=
VNetHeader=
Group=
User=
KeepCarrier=
[NetDev]
Kind=
MACAddress=

View File

@@ -7,3 +7,4 @@ Kind=tap
MultiQueue=true
PacketInfo=true
VNetHeader=true
KeepCarrier=yes

View File

@@ -7,3 +7,4 @@ Kind=tun
MultiQueue=true
PacketInfo=true
VNetHeader=true
KeepCarrier=yes

View File

@@ -22,6 +22,8 @@ Name=nlmon99
Name=xfrm98 xfrm99
Name=vxlan98
Name=hogehogehogehogehogehoge
Name=testtun99
Name=testtap99
[Network]
LinkLocalAddressing=yes

View File

@@ -13,6 +13,7 @@ import errno
import itertools
import os
import pathlib
import psutil
import re
import shutil
import signal
@@ -607,6 +608,9 @@ def restart_networkd(show_logs=True):
if show_logs:
print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id))
def networkd_pid():
return int(check_output('systemctl show --value -p MainPID systemd-networkd.service'))
def networkctl_reconfigure(*links):
check_output(*networkctl_cmd, 'reconfigure', *links, env=env)
@@ -1321,20 +1325,83 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'mtu 1800')
def test_tuntap(self):
copy_network_unit('25-tun.netdev', '25-tap.netdev')
copy_network_unit('25-tun.netdev', '25-tap.netdev', '26-netdev-link-local-addressing-yes.network')
start_networkd()
self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
self.wait_online(['testtun99:degraded', 'testtap99:degraded'])
pid = networkd_pid()
name = psutil.Process(pid).name()[:15]
output = check_output('ip -d tuntap show')
print(output)
self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
output = check_output('ip -d link show testtun99')
print(output)
# Old ip command does not support IFF_ flags
self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
self.assertIn('UP,LOWER_UP', output)
output = check_output('ip -d link show testtap99')
print(output)
# Old ip command does not support IFF_ flags
self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
self.assertIn('UP,LOWER_UP', output)
remove_network_unit('26-netdev-link-local-addressing-yes.network')
restart_networkd()
self.wait_online(['testtun99:degraded', 'testtap99:degraded'], setup_state='unmanaged')
pid = networkd_pid()
name = psutil.Process(pid).name()[:15]
output = check_output('ip -d tuntap show')
print(output)
self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
output = check_output('ip -d link show testtun99')
print(output)
self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
self.assertIn('UP,LOWER_UP', output)
output = check_output('ip -d link show testtap99')
print(output)
self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
self.assertIn('UP,LOWER_UP', output)
clear_network_units()
restart_networkd()
self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
output = check_output('ip -d tuntap show')
print(output)
self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
for i in range(10):
if i != 0:
time.sleep(1)
output = check_output('ip -d link show testtun99')
print(output)
self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
if 'NO-CARRIER' in output:
break
else:
self.fail()
for i in range(10):
if i != 0:
time.sleep(1)
output = check_output('ip -d link show testtap99')
print(output)
self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
if 'NO-CARRIER' in output:
break
else:
self.fail()
@expectedFailureIfModuleIsNotAvailable('vrf')
def test_vrf(self):

View File

@@ -25,6 +25,7 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_N
DeviceAllow=char-* rw
ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
ExecReload=networkctl reload
FileDescriptorStoreMax=512
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes