diff options
-rw-r--r-- | .mkosi/mkosi.arch | 2 | ||||
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | TODO | 14 | ||||
-rw-r--r-- | man/systemd.network.xml | 8 | ||||
-rw-r--r-- | src/basic/fs-util.c | 9 | ||||
-rw-r--r-- | src/basic/static-destruct.h | 4 | ||||
-rw-r--r-- | src/basic/util.c | 8 | ||||
-rw-r--r-- | src/basic/util.h | 3 | ||||
-rw-r--r-- | src/core/cgroup.c | 14 | ||||
-rw-r--r-- | src/core/dbus-cgroup.c | 12 | ||||
-rw-r--r-- | src/core/main.c | 26 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 8 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 3 | ||||
-rw-r--r-- | src/network/tc/netem.c | 17 | ||||
-rw-r--r-- | src/network/tc/netem.h | 3 | ||||
-rw-r--r-- | src/network/tc/qdisc.c | 19 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 12 | ||||
-rw-r--r-- | test/fuzz/fuzz-network-parser/directives.network | 1 | ||||
-rwxr-xr-x | test/test-network/systemd-networkd-tests.py | 92 |
19 files changed, 154 insertions, 104 deletions
diff --git a/.mkosi/mkosi.arch b/.mkosi/mkosi.arch index ce0c1ae38e..350d7cd2b8 100644 --- a/.mkosi/mkosi.arch +++ b/.mkosi/mkosi.arch @@ -27,11 +27,11 @@ BuildPackages= docbook-xsl elfutils gcc - gettext git gnu-efi-libs gnutls gperf + inetutils iptables kmod libcap @@ -127,7 +127,8 @@ CHANGES WITH 244 in spe: disciplines in the kernel using the new [TrafficControlQueueingDiscipline] section and Parent=, NetworkEmulatorDelaySec=, NetworkEmulatorDelayJitterSec=, - NetworkEmulatorPacketLimit=, NetworkEmulatorLossRate= settings. + NetworkEmulatorPacketLimit=, NetworkEmulatorLossRate=, + NetworkEmulatorDuplicateRate= settings. * systemd-tmpfiles gained a new w+ setting to append to files. @@ -17,6 +17,17 @@ Janitorial Clean-ups: * rework mount.c and swap.c to follow proper state enumeration/deserialization semantics, like we do for device.c now +Before v244: + +* revisit SystemdOptions EFI variable. Find a better, systematic name and use + it for the env var, the bootctl verb and the EFI variable itself, clear up + semantics. + +* Figure out a better name for the global per-unit-type drop-in dirs, it's + confusing when it comes to -.mount.d/ (is it a drop-in-dir for all mount + units, or one for the root mount?). Also, OOM handling in + service_unit_name_is_valid() is borked. + Features: * coredump: maybe when coredumping read a new xattr from /proc/$PID/exe that @@ -257,9 +268,6 @@ Features: * bypass SIGTERM state in unit files if KillSignal is SIGKILL -* tree-wide: ensure we always block the signals we hook into with - sd_event_add_signal() first - * add proper dbus APIs for the various sd_notify() commands, such as MAINPID=1 and so on, which would mean we could report errors and such. diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 0d49bf9589..fb2f199ba8 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2351,6 +2351,14 @@ </listitem> </varlistentry> + <varlistentry> + <term><varname>NetworkEmulatorDuplicateRate=</varname></term> + <listitem> + <para>Specifies that the chosen percent of packets is duplicated before queuing them. + Takes a percentage value, suffixed with "%". Defaults to unset.</para> + </listitem> + </varlistentry> + </variablelist> </refsect1> diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 9d2cff0d24..6e6fa20053 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -662,15 +662,12 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { } int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) { - if (inotify_add_watch(fd, pathname, mask) < 0) { - const char *reason; + if (inotify_add_watch(fd, pathname, mask) < 0) { if (errno == ENOSPC) - reason = "inotify watch limit reached"; - else - reason = strerror_safe(errno); + return log_error_errno(errno, "Failed to add a watch for %s: inotify watch limit reached", pathname); - return log_error_errno(errno, "Failed to add a watch for %s: %s", pathname, reason); + return log_error_errno(errno, "Failed to add a watch for %s: %m", pathname); } return 0; diff --git a/src/basic/static-destruct.h b/src/basic/static-destruct.h index 443c0e8ebb..8fbc07c587 100644 --- a/src/basic/static-destruct.h +++ b/src/basic/static-destruct.h @@ -40,8 +40,8 @@ typedef struct StaticDestructor { extern const struct StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[]; extern const struct StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[]; -/* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in the same - * linking unit as the variables we want to destroy. */ +/* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in + * the same linking unit as the variables we want to destroy.) */ static inline void static_destruct(void) { const StaticDestructor *d; diff --git a/src/basic/util.c b/src/basic/util.c index b02471c483..f74ed95a60 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -38,7 +38,6 @@ #include "set.h" #include "signal-util.h" #include "stat-util.h" -#include "static-destruct.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -49,11 +48,8 @@ int saved_argc = 0; char **saved_argv = NULL; -char **saved_env = NULL; static int saved_in_initrd = -1; -STATIC_DESTRUCTOR_REGISTER(saved_env, strv_freep); - bool kexec_loaded(void) { _cleanup_free_ char *s = NULL; @@ -301,7 +297,3 @@ void disable_coredumps(void) { if (r < 0) log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m"); } - -void save_env(void) { - saved_env = strv_copy(environ); -} diff --git a/src/basic/util.h b/src/basic/util.h index 15444b2e5c..6fc7480fcb 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -13,9 +13,6 @@ static inline void save_argc_argv(int argc, char **argv) { saved_argv = argv; } -extern char **saved_env; -void save_env(void); - bool kexec_loaded(void); int prot_from_flags(int flags) _const_; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 981aca53cd..ec8a262314 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -360,9 +360,7 @@ static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u, } void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { - _cleanup_free_ char *disable_controllers_str = NULL; - _cleanup_free_ char *cpuset_cpus = NULL; - _cleanup_free_ char *cpuset_mems = NULL; + _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus = NULL, *cpuset_mems = NULL; CGroupIODeviceLimit *il; CGroupIODeviceWeight *iw; CGroupIODeviceLatency *l; @@ -437,8 +435,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { prefix, c->startup_cpu_shares, prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1), prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1), - prefix, cpuset_cpus, - prefix, cpuset_mems, + prefix, strempty(cpuset_cpus), + prefix, strempty(cpuset_mems), prefix, c->io_weight, prefix, c->startup_io_weight, prefix, c->blockio_weight, @@ -974,8 +972,10 @@ static void cgroup_apply_unified_cpuset(Unit *u, const CPUSet *cpus, const char _cleanup_free_ char *buf = NULL; buf = cpu_set_to_range_string(cpus); - if (!buf) - return; + if (!buf) { + log_oom(); + return; + } (void) set_attribute_and_warn(u, "cpuset", name, buf); } diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index b30318b943..647c3a512c 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -926,23 +926,23 @@ int bus_cgroup_set_property( if (!UNIT_WRITE_FLAGS_NOOP(flags)) { _cleanup_free_ char *setstr = NULL; - _cleanup_free_ char *data = NULL; CPUSet *set; setstr = cpu_set_to_range_string(&new_set); + if (!setstr) + return -ENOMEM; if (streq(name, "AllowedCPUs")) set = &c->cpuset_cpus; else set = &c->cpuset_mems; - if (asprintf(&data, "%s=%s", name, setstr) < 0) - return -ENOMEM; - cpu_set_reset(set); - cpu_set_add_all(set, &new_set); + *set = new_set; + new_set = (CPUSet) {}; + unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET); - unit_write_setting(u, flags, name, data); + unit_write_settingf(u, flags, name, "%s=%s", name, setstr); } return 1; diff --git a/src/core/main.c b/src/core/main.c index 7c814f3237..3545fde71d 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -146,6 +146,9 @@ static OOMPolicy arg_default_oom_policy; static CPUSet arg_cpu_affinity; static NUMAPolicy arg_numa_policy; +/* A copy of the original environment block */ +static char **saved_env = NULL; + static int parse_configuration(const struct rlimit *saved_rlimit_nofile, const struct rlimit *saved_rlimit_memlock); @@ -2353,6 +2356,17 @@ static bool early_skip_setup_check(int argc, char *argv[]) { return found_deserialize; /* When we are deserializing, then we are reexecuting, hence avoid the extensive setup */ } +static int save_env(void) { + char **l; + + l = strv_copy(environ); + if (!l) + return -ENOMEM; + + strv_free_and_replace(saved_env, l); + return 0; +} + int main(int argc, char *argv[]) { dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL, userspace_timestamp = DUAL_TIMESTAMP_NULL, kernel_timestamp = DUAL_TIMESTAMP_NULL, @@ -2391,9 +2405,13 @@ int main(int argc, char *argv[]) { /* Save the original command line */ save_argc_argv(argc, argv); - /* Save the original environment as we might need to restore it if we're requested to - * execute another system manager later. */ - save_env(); + /* Save the original environment as we might need to restore it if we're requested to execute another + * system manager later. */ + r = save_env(); + if (r < 0) { + error_message = "Failed to copy environment block"; + goto finish; + } /* Make sure that if the user says "syslog" we actually log to the journal. */ log_set_upgrade_syslog_to_journal(true); @@ -2681,6 +2699,8 @@ finish: arg_serialization = safe_fclose(arg_serialization); fds = fdset_free(fds); + saved_env = strv_free(saved_env); + #if HAVE_VALGRIND_VALGRIND_H /* If we are PID 1 and running under valgrind, then let's exit * here explicitly. valgrind will only generate nice output on diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index f7022dd715..3316c8bda4 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -136,7 +136,7 @@ static sd_dhcp_raw_option* raw_option_free(sd_dhcp_raw_option *i) { } _public_ int sd_dhcp_raw_option_new(uint8_t type, char *data, size_t length, sd_dhcp_raw_option **ret) { - sd_dhcp_raw_option *p; + _cleanup_(sd_dhcp_raw_option_unrefp) sd_dhcp_raw_option *p = NULL; assert_return(ret, -EINVAL); @@ -151,12 +151,10 @@ _public_ int sd_dhcp_raw_option_new(uint8_t type, char *data, size_t length, sd_ .type = type, }; - if (!p->data) { - free(p); + if (!p->data) return -ENOMEM; - } - *ret = p; + *ret = TAKE_PTR(p); return 0; } diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 9f53385602..7fca93dccb 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -247,7 +247,8 @@ CAN.TripleSampling, config_parse_tristate, TrafficControlQueueingDiscipline.Parent, config_parse_tc_qdiscs_parent, 0, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_tc_network_emulator_delay, 0, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_tc_network_emulator_delay, 0, 0 -TrafficControlQueueingDiscipline.NetworkEmulatorLossRate, config_parse_tc_network_emulator_loss_rate, 0, 0 +TrafficControlQueueingDiscipline.NetworkEmulatorLossRate, config_parse_tc_network_emulator_rate, 0, 0 +TrafficControlQueueingDiscipline.NetworkEmulatorDuplicateRate, config_parse_tc_network_emulator_rate, 0, 0 TrafficControlQueueingDiscipline.NetworkEmulatorPacketLimit, config_parse_tc_network_emulator_packet_limit, 0, 0 /* backwards compatibility: do not add new entries to this section */ Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) diff --git a/src/network/tc/netem.c b/src/network/tc/netem.c index e0e3e9a48e..053af3e7db 100644 --- a/src/network/tc/netem.c +++ b/src/network/tc/netem.c @@ -50,6 +50,9 @@ int network_emulator_fill_message(Link *link, QDiscs *qdisc, sd_netlink_message if (qdisc->ne.loss > 0) opt.loss = qdisc->ne.loss; + if (qdisc->ne.duplicate > 0) + opt.duplicate = qdisc->ne.duplicate; + if (qdisc->ne.delay != USEC_INFINITY) { r = tc_time_to_tick(qdisc->ne.delay, &opt.latency); if (r < 0) @@ -124,7 +127,7 @@ int config_parse_tc_network_emulator_delay( return 0; } -int config_parse_tc_network_emulator_loss_rate( +int config_parse_tc_network_emulator_rate( const char *unit, const char *filename, unsigned line, @@ -138,6 +141,7 @@ int config_parse_tc_network_emulator_loss_rate( _cleanup_(qdisc_free_or_set_invalidp) QDiscs *qdisc = NULL; Network *network = data; + uint32_t rate; int r; assert(filename); @@ -156,14 +160,19 @@ int config_parse_tc_network_emulator_loss_rate( return 0; } - r = parse_tc_percent(rvalue, &qdisc->ne.loss); + r = parse_tc_percent(rvalue, &rate); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse 'NetworkEmularorLossRate=', ignoring assignment: %s", - rvalue); + "Failed to parse '%s=', ignoring assignment: %s", + lvalue, rvalue); return 0; } + if (streq(lvalue, "NetworkEmulatorLossRate")) + qdisc->ne.loss = rate; + else if (streq(lvalue, "NetworkEmulatorDuplicateRate")) + qdisc->ne.duplicate = rate; + qdisc = NULL; return 0; } diff --git a/src/network/tc/netem.h b/src/network/tc/netem.h index 4bac44ca5a..43abf20af8 100644 --- a/src/network/tc/netem.h +++ b/src/network/tc/netem.h @@ -16,11 +16,12 @@ typedef struct NetworkEmulator { uint32_t limit; uint32_t loss; + uint32_t duplicate; } NetworkEmulator; int network_emulator_new(NetworkEmulator **ret); int network_emulator_fill_message(Link *link, QDiscs *qdisc, sd_netlink_message *req); CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay); -CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_loss_rate); +CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate); CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_packet_limit); diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index ed4a11d265..7f4b2b53cb 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -116,6 +116,7 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int qdisc_configure(Link *link, QDiscs *qdisc) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + _cleanup_free_ char *tca_kind = NULL; int r; assert(link); @@ -132,25 +133,31 @@ int qdisc_configure(Link *link, QDiscs *qdisc) { return log_link_error_errno(link, r, "Could not create tcm_parent message: %m"); if (qdisc->parent == TC_H_CLSACT) { + tca_kind = strdup("clsact"); + if (!tca_kind) + return log_oom(); + r = sd_rtnl_message_set_qdisc_handle(req, TC_H_MAKE(TC_H_CLSACT, 0)); if (r < 0) return log_link_error_errno(link, r, "Could not set tcm_handle message: %m"); - - r = sd_netlink_message_append_string(req, TCA_KIND, "clsact"); - if (r < 0) - return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); } if (qdisc->has_network_emulator) { - r = sd_netlink_message_append_string(req, TCA_KIND, "netem"); + r = free_and_strdup(&tca_kind, "netem"); if (r < 0) - return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); + return log_oom(); r = network_emulator_fill_message(link, qdisc, req); if (r < 0) return r; } + if (tca_kind) { + r = sd_netlink_message_append_string(req, TCA_KIND, tca_kind); + if (r < 0) + return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m"); + } + r = netlink_call_async(link->manager->rtnl, NULL, req, qdisc_handler, link_netlink_destroy_callback, link); if (r < 0) return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index c9ff00544c..3513c015b8 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -103,6 +103,7 @@ #include "terminal-util.h" #include "tmpfile-util.h" #include "umask-util.h" +#include "unit-name.h" #include "user-util.h" #include "util.h" @@ -891,13 +892,17 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_MACHINE_ID; break; - case 'S': - r = free_and_strdup(&arg_slice, optarg); + case 'S': { + _cleanup_free_ char *mangled = NULL; + + r = unit_name_mangle_with_suffix(optarg, NULL, UNIT_NAME_MANGLE_WARN, ".slice", &mangled); if (r < 0) return log_oom(); + free_and_replace(arg_slice, mangled); arg_settings_mask |= SETTING_SLICE; break; + } case 'M': if (isempty(optarg)) @@ -2385,7 +2390,8 @@ static int drop_capabilities(uid_t uid) { /* If we're not using OCI, proceed with mangled capabilities (so we don't error out) * in order to maintain the same behavior as systemd < 242. */ if (capability_quintet_mangle(&q)) - log_warning("Some capabilities will not be set because they are not in the current bounding set."); + log_full(arg_quiet ? LOG_DEBUG : LOG_WARNING, + "Some capabilities will not be set because they are not in the current bounding set."); } diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 3469dd443e..a5f54610da 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -268,4 +268,5 @@ Parent= NetworkEmulatorDelaySec= NetworkEmulatorDelayJitterSec= NetworkEmulatorLossRate= +NetworkEmulatorDuplicateRate= NetworkEmulatorPacketLimit= diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index e9b9fb0d7c..ab6e11e0e5 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -22,12 +22,16 @@ network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf' dnsmasq_pid_file='/run/networkd-ci/test-test-dnsmasq.pid' dnsmasq_log_file='/run/networkd-ci/test-dnsmasq-log-file' -networkd_bin='/usr/lib/systemd/systemd-networkd' -resolved_bin='/usr/lib/systemd/systemd-resolved' -wait_online_bin='/usr/lib/systemd/systemd-networkd-wait-online' -networkctl_bin='/usr/bin/networkctl' -resolvectl_bin='/usr/bin/resolvectl' -timedatectl_bin='/usr/bin/timedatectl' +systemd_lib_paths=['/usr/lib/systemd', '/lib/systemd'] +which_paths=':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(':').split(':')) + +networkd_bin=shutil.which('systemd-networkd', path=which_paths) +resolved_bin=shutil.which('systemd-resolved', path=which_paths) +wait_online_bin=shutil.which('systemd-networkd-wait-online', path=which_paths) +networkctl_bin=shutil.which('networkctl', path=which_paths) +resolvectl_bin=shutil.which('resolvectl', path=which_paths) +timedatectl_bin=shutil.which('timedatectl', path=which_paths) + use_valgrind=False enable_debug=True env = {} @@ -53,7 +57,7 @@ def run(*command, **kwargs): def is_module_available(module_name): lsmod_output = check_output('lsmod') module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE) - return module_re.search(lsmod_output) or not call('modprobe', module_name) + return module_re.search(lsmod_output) or not call('modprobe', module_name, stderr=subprocess.DEVNULL) def expectedFailureIfModuleIsNotAvailable(module_name): def f(func): @@ -65,7 +69,7 @@ def expectedFailureIfModuleIsNotAvailable(module_name): def expectedFailureIfERSPANModuleIsNotAvailable(): def f(func): - rc = call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123') + rc = call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr=subprocess.DEVNULL) if rc == 0: call('ip link del erspan99') return func @@ -76,7 +80,7 @@ def expectedFailureIfERSPANModuleIsNotAvailable(): def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable(): def f(func): - rc = call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7') + rc = call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr=subprocess.DEVNULL) if rc == 0: call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7') return func @@ -87,7 +91,7 @@ def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable(): def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable(): def f(func): - rc = call('ip rule add not from 192.168.100.19 ipproto tcp table 7') + rc = call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr=subprocess.DEVNULL) if rc == 0: call('ip rule del not from 192.168.100.19 ipproto tcp table 7') return func @@ -99,7 +103,7 @@ def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable(): def expectedFailureIfLinkFileFieldIsNotSet(): def f(func): support = False - rc = call('ip link add name dummy99 type dummy') + rc = call('ip link add name dummy99 type dummy', stderr=subprocess.DEVNULL) if rc == 0: ret = run('udevadm info -w10s /sys/class/net/dummy99', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if ret.returncode == 0 and 'E: ID_NET_LINK_FILE=' in ret.stdout.rstrip(): @@ -115,7 +119,7 @@ def expectedFailureIfLinkFileFieldIsNotSet(): def expectedFailureIfNexthopIsNotAvailable(): def f(func): - rc = call('ip nexthop list') + rc = call('ip nexthop list', stderr=subprocess.DEVNULL) if rc == 0: return func else: @@ -510,12 +514,12 @@ class NetworkctlTests(unittest.TestCase, Utilities): output = check_output(*networkctl_cmd, 'status', 'test1') print(output) - self.assertRegex(output, r'Link File: (?:/usr)/lib/systemd/network/99-default.link') + self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link') self.assertRegex(output, r'Network File: /run/systemd/network/11-dummy.network') output = check_output(*networkctl_cmd, 'status', 'lo') print(output) - self.assertRegex(output, r'Link File: (?:/usr)/lib/systemd/network/99-default.link') + self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link') self.assertRegex(output, r'Network File: n/a') def test_delete_links(self): @@ -748,7 +752,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.wait_online(['bridge99', 'test1:degraded'], bool_any=True) - self.check_operstate('bridge99', '(?:off|no-carrier)', setup_state='configuring') + self.check_operstate('bridge99', '(off|no-carrier)', setup_state='configuring') self.check_operstate('test1', 'degraded') def test_bridge(self): @@ -921,7 +925,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show tun99') 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.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ') def test_tap(self): copy_unit_to_networkd_unit_path('25-tap.netdev') @@ -932,7 +936,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show tap99') 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.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ') @expectedFailureIfModuleIsNotAvailable('vrf') def test_vrf(self): @@ -1010,16 +1014,16 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show ipiptun99') print(output) - self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98') + self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98') output = check_output('ip -d link show ipiptun98') print(output) - self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98') + self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98') output = check_output('ip -d link show ipiptun97') print(output) - self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98') + self.assertRegex(output, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98') output = check_output('ip -d link show ipiptun96') print(output) - self.assertRegex(output, 'ipip (?:ipip |)remote any local any dev dummy98') + self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98') def test_gre_tunnel(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network', @@ -1159,10 +1163,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98') output = check_output('ip -d link show vti6tun98') print(output) - self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98') + self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98') output = check_output('ip -d link show vti6tun97') print(output) - self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98') + self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98') def test_ip6tnl_tunnel(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network', @@ -1177,10 +1181,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98') output = check_output('ip -d link show ip6tnl98') print(output) - self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98') + self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98') output = check_output('ip -d link show ip6tnl97') print(output) - self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98') + self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98') def test_sit_tunnel(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network', @@ -1193,16 +1197,16 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show sittun99') print(output) - self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98") + self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98") output = check_output('ip -d link show sittun98') print(output) - self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98") + self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98") output = check_output('ip -d link show sittun97') print(output) - self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98") + self.assertRegex(output, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98") output = check_output('ip -d link show sittun96') print(output) - self.assertRegex(output, "sit (?:ip6ip |)remote any local any dev dummy98") + self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98") def test_isatap_tunnel(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network', @@ -1596,7 +1600,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, '111:') self.assertRegex(output, 'from 192.168.100.18') - self.assertRegex(output, r'tos (?:0x08|throughput)\s') + self.assertRegex(output, r'tos (0x08|throughput)\s') self.assertRegex(output, 'iif test1') self.assertRegex(output, 'oif test1') self.assertRegex(output, 'lookup 7') @@ -1634,11 +1638,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip rule list table 7') print(output) - self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7') + self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7') output = check_output('ip rule list table 8') print(output) - self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8') + self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8') stop_networkd(remove_state_files=False) @@ -2109,7 +2113,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'LLMNR=no') self.assertRegex(data, r'MDNS=yes') self.assertRegex(data, r'DNSSEC=no') - self.assertRegex(data, r'ADDRESSES=192.168.(?:10.10|12.12)/24 192.168.(?:12.12|10.10)/24') + self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24') check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env=env) check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env) @@ -2379,7 +2383,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): print('### ip -6 route list table all dev bridge99') output = check_output('ip -6 route list table all dev bridge99') print(output) - self.assertRegex(output, 'ff00::/8 table local metric 256 (?:linkdown |)pref medium') + self.assertRegex(output, 'ff00::/8 table local metric 256 (linkdown )?pref medium') def test_bridge_ignore_carrier_loss(self): copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev', @@ -2645,7 +2649,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') output = check_output(*networkctl_cmd, 'status', 'veth99', env=env) print(output) @@ -2824,7 +2828,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): output = check_output('ip address show dev veth99 scope global') print(output) - self.assertRegex(output, r'inet6 2600::[0-9a-f]*/128 scope global (?:noprefixroute dynamic|dynamic noprefixroute)') + self.assertRegex(output, r'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)') output = check_output('ip -6 route show dev veth99') print(output) @@ -2933,7 +2937,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') output = check_output('ip address show dev veth99 scope global') print(output) @@ -2976,7 +2980,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') print('## ip -d link show dev vrf99') output = check_output('ip -d link show dev vrf99') @@ -2988,7 +2992,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99') self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') - self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)') + self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)') self.assertRegex(output, 'inet6 .* scope link') print('## ip address show dev veth99') @@ -2996,7 +3000,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99') self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') - self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)') + self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)') self.assertRegex(output, 'inet6 .* scope link') print('## ip route show vrf vrf99') @@ -3145,7 +3149,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') time.sleep(3) output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env) @@ -3163,7 +3167,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') time.sleep(3) output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env) @@ -3181,7 +3185,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') time.sleep(3) output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env) @@ -3199,7 +3203,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): # link become 'routable' when at least one protocol provide an valid address. self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4') - self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') + self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6') time.sleep(3) output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env) |