uses: redhat-plumbers-in-action/differential-shellcheck@91e2582e40236f831458392d905578d680baa138
with:
# exclude all `.in` files because they may contain unsupported syntax, and they have to be preprocessed first
- exclude-path: '**/*.in'
+ # TEMPORARY: exclude bash completion files, they would generate too many defects in Code scanning dashboard (600+)
+ # exclude zsh completion files, zsh is not supported by ShellCheck
+ exclude-path: |
+ '**/*.in'
+ 'shell-completion/bash/*'
+ 'shell-completion/zsh/*'
token: ${{ secrets.GITHUB_TOKEN }}
Features:
* add a new specifier to unit files that figures out the DDI the unit file is
- from, tracing trough overlayfs, DM, loopback block device.
+ from, tracing through overlayfs, DM, loopback block device.
* in os-release define a field that can be initialized at build time from
SOURCE_DATE_EPOCH (maybe even under that name?). Would then be used to
<xi:include href="version-info.xml" xpointer="v232"/>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ReceivePacketSteeringCPUMask=</varname></term>
+ <listitem>
+ <para>Configures Receive Packet Steering (RPS) list of CPUs to which RPS may forward traffic.
+ Takes a list of CPU indices or ranges separated by either whitespace or commas. Alternatively,
+ takes the special value <literal>all</literal> in which will include all available CPUs in the mask.
+ CPU ranges are specified by the lower and upper CPU indices separated by a dash (e.g. <literal>2-6</literal>).
+ This option may be specified more than once, in which case the specified CPU affinity masks are merged.
+ If an empty string is assigned, the mask is reset, all assignments prior to this will have no effect.
+ Defaults to unset and RPS CPU list is unchanged. To disable RPS when it was previously enabled, use the
+ special value <literal>disable</literal>.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>ReceiveVLANCTAGHardwareAcceleration=</varname></term>
<listitem>
</listitem>
</varlistentry>
- <varlistentry>
- <term><varname>UseICMP6RateLimit=</varname></term>
- <listitem>
- <para>Takes a boolean. When true, the ICMP6 rate limit received in the Router Advertisement will be set to ICMP6
- rate limit based on the advertisement. Defaults to true.</para>
-
- <xi:include href="version-info.xml" xpointer="v255"/>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><varname>UseGateway=</varname></term>
<listitem>
+# shellcheck shell=bash
# bootctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# busctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# coredumpctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# homectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# hostnamectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# journalctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# kernel-install(8) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# localectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# loginctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# machinectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# networkctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# oomctl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# portablectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# resolvectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemctl(1) completion -*- shell-script -*-
# vi: ft=sh
# SPDX-License-Identifier: LGPL-2.1-or-later
+# shellcheck shell=bash
# systemd-analyze(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-cat(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-cgls(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-cgtop(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-confext(8) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-cryptenroll(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-delta(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-detect-virt(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-dissect(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-id128(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-nspawn(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-path(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-resolve(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-run(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# systemd-sysext(8) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# timedatectl(1) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
+# shellcheck shell=bash
# udevadm(8) completion -*- shell-script -*-
# SPDX-License-Identifier: LGPL-2.1-or-later
#
uint8_t hop_limit;
uint32_t mtu;
- uint64_t icmp6_ratelimit_usec;
};
static inline void* NDISC_ROUTER_RAW(const sd_ndisc_router *rt) {
rt->hop_limit = a->nd_ra_curhoplimit;
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
- rt->icmp6_ratelimit_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* mas_as_infinity = */ false);
rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
return 0;
}
-int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret) {
- assert_return(rt, -EINVAL);
- assert_return(ret, -EINVAL);
-
- *ret = rt->icmp6_ratelimit_usec;
- return 0;
-}
-
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
assert_return(rt, -EINVAL);
assert_return(ret, -EINVAL);
return 0;
}
-static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt) {
- usec_t icmp6_ratelimit, msec;
- int r;
-
- assert(link);
- assert(link->network);
- assert(rt);
-
- if (!link->network->ndisc_use_icmp6_ratelimit)
- return 0;
-
- /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
- r = sd_ndisc_router_get_lifetime(rt, NULL);
- if (r <= 0)
- return r;
-
- r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to get ICMP6 ratelimit from RA: %m");
-
- /* We do not allow 0 here. */
- if (!timestamp_is_set(icmp6_ratelimit))
- return 0;
-
- msec = DIV_ROUND_UP(icmp6_ratelimit, USEC_PER_MSEC);
- if (msec <= 0 || msec > INT_MAX)
- return 0;
-
- /* Limit the maximal rates for sending ICMPv6 packets. 0 to disable any limiting, otherwise the
- * minimal space between responses in milliseconds. Default: 1000. */
- r = sysctl_write_ip_property_int(AF_INET6, NULL, "icmp/ratelimit", (int) msec);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to apply ICMP6 ratelimit, ignoring: %m");
-
- return 0;
-}
-
static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
usec_t reachable_time, msec;
int r;
if (r < 0)
return r;
- r = ndisc_router_process_icmp6_ratelimit(link, rt);
- if (r < 0)
- return r;
-
r = ndisc_router_process_reachable_time(link, rt);
if (r < 0)
return r;
IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ndisc_use_hop_limit)
IPv6AcceptRA.UseReachableTime, config_parse_bool, 0, offsetof(Network, ndisc_use_reachable_time)
IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ndisc_use_retransmission_time)
-IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ndisc_use_icmp6_ratelimit)
IPv6AcceptRA.DHCPv6Client, config_parse_ndisc_start_dhcp6_client, 0, offsetof(Network, ndisc_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET6, 0
IPv6AcceptRA.RouteMetric, config_parse_ndisc_route_metric, 0, 0
DHCPv6PrefixDelegation.RouteMetric, config_parse_uint32, 0, offsetof(Network, dhcp_pd_route_metric)
IPv6AcceptRA.DenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
IPv6AcceptRA.BlackList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_prefix)
+IPv6AcceptRA.UseICMP6RateLimit, config_parse_warn_compat, DISABLED_LEGACY, 0
TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_network_emulator_delay, 0, 0
TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_network_emulator_delay, 0, 0
.ndisc_use_hop_limit = true,
.ndisc_use_reachable_time = true,
.ndisc_use_retransmission_time = true,
- .ndisc_use_icmp6_ratelimit = true,
.ndisc_route_table = RT_TABLE_MAIN,
.ndisc_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
.ndisc_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
bool ndisc_use_hop_limit;
bool ndisc_use_reachable_time;
bool ndisc_use_retransmission_time;
- bool ndisc_use_icmp6_ratelimit;
bool ndisc_quickack;
bool ndisc_use_captive_portal;
bool ndisc_use_pref64;
r = bus_append_scope_pidref(m, &pidref);
} else
- r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
+ r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) pid);
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_parse_error(r);
- r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL);
+ r = bus_wait_for_jobs_one(
+ w,
+ object,
+ BUS_WAIT_JOBS_LOG_ERROR,
+ /* extra_args= */ NULL);
if (r < 0)
return r;
return -EINVAL;
r = varlink_dispatch(link, parameters, dispatch_table, &p);
- if (r < 0)
+ if (r != 0)
return r;
if (p.ifindex < 0)
return (wanted = true);
/* If any controller is in use as v1, don't use unified. */
- return (wanted = cg_any_controller_used_for_v1() <= 0);
+ return (wanted = (cg_any_controller_used_for_v1() <= 0));
}
bool cg_is_legacy_wanted(void) {
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
+#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"
return TAKE_PTR(str) ?: strdup("");
}
+char* cpu_set_to_mask_string(const CPUSet *a) {
+ _cleanup_free_ char *str = NULL;
+ size_t len = 0;
+ bool found_nonzero = false;
+
+ assert(a);
+
+ /* Return CPU set in hexadecimal bitmap mask, e.g.
+ * CPU 0 -> "1"
+ * CPU 1 -> "2"
+ * CPU 0,1 -> "3"
+ * CPU 0-3 -> "f"
+ * CPU 0-7 -> "ff"
+ * CPU 4-7 -> "f0"
+ * CPU 7 -> "80"
+ * None -> "0"
+ *
+ * When there are more than 32 CPUs, separate every 32 CPUs by comma, e.g.
+ * CPU 0-47 -> "ffff,ffffffff"
+ * CPU 0-63 -> "ffffffff,ffffffff"
+ * CPU 0-71 -> "ff,ffffffff,ffffffff" */
+
+ for (ssize_t i = a->allocated * 8; i >= 0; i -= 4) {
+ uint8_t m = 0;
+
+ for (size_t j = 0; j < 4; j++)
+ if (CPU_ISSET_S(i + j, a->allocated, a->set))
+ m |= 1U << j;
+
+ if (!found_nonzero)
+ found_nonzero = m > 0;
+
+ if (!found_nonzero && m == 0)
+ /* Skip leading zeros */
+ continue;
+
+ if (!GREEDY_REALLOC(str, len + 3))
+ return NULL;
+
+ str[len++] = hexchar(m);
+ if (i >= 4 && i % 32 == 0)
+ /* Separate by comma for each 32 CPUs. */
+ str[len++] = ',';
+ str[len] = 0;
+ }
+
+ return TAKE_PTR(str) ?: strdup("0");
+}
+
+CPUSet* cpu_set_free(CPUSet *c) {
+ if (!c)
+ return c;
+
+ cpu_set_reset(c);
+ return mfree(c);
+}
+
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
size_t need;
*set = TAKE_STRUCT(s);
return 0;
}
+
+int cpu_mask_add_all(CPUSet *mask) {
+ long m;
+ int r;
+
+ assert(mask);
+
+ m = sysconf(_SC_NPROCESSORS_ONLN);
+ if (m < 0)
+ return -errno;
+
+ for (unsigned i = 0; i < (unsigned) m; i++) {
+ r = cpu_set_add(mask, i);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
*a = (CPUSet) {};
}
+CPUSet* cpu_set_free(CPUSet *c);
+DEFINE_TRIVIAL_CLEANUP_FUNC(CPUSet*, cpu_set_free);
+
int cpu_set_add_all(CPUSet *a, const CPUSet *b);
int cpu_set_add(CPUSet *a, unsigned cpu);
char* cpu_set_to_string(const CPUSet *a);
char *cpu_set_to_range_string(const CPUSet *a);
+char* cpu_set_to_mask_string(const CPUSet *a);
int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus);
int parse_cpu_set_full(
int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set);
int cpus_in_affinity_mask(void);
+int cpu_mask_add_all(CPUSet *mask);
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "1"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Simple range (from CPUAffinity example) */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "1-2 4"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "16"));
+ str = mfree(str);
cpu_set_reset(&c);
/* A more interesting range */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0-3 8-11"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "f0f"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Quoted strings */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "8-11"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "f00"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Use commas as separators */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0-7 63"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "80000000,000000ff"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Ranges */
log_info("cpu_set_to_string: %s", str);
str = mfree(str);
cpu_set_reset(&c);
+ assert_se(parse_cpu_set_full("36-39,44-47", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
+ for (cpu = 36; cpu < 40; cpu++)
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ for (cpu = 44; cpu < 48; cpu++)
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "f0f0,00000000"));
+ str = mfree(str);
+ cpu_set_reset(&c);
+ assert_se(parse_cpu_set_full("64-71", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
+ assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
+ assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
+ for (cpu = 64; cpu < 72; cpu++)
+ assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "ff,00000000,00000000"));
+ str = mfree(str);
+ cpu_set_reset(&c);
/* Ranges with trailing comma, space */
assert_se(parse_cpu_set_full("0-3 8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0-3 8-11"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "f0f"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Negative range (returns empty cpu_set) */
assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "0"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Overlapping ranges */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0-11"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "fff"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Mix ranges and individual CPUs */
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "0 2 4-11"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "ff5"));
+ str = mfree(str);
cpu_set_reset(&c);
/* Garbage */
assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
assert_se(!c.set); /* empty string returns NULL */
assert_se(c.allocated == 0);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ assert_se(streq(str, "0"));
+ str = mfree(str);
/* Runaway quoted string */
assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
log_info("cpu_set_to_range_string: %s", str);
assert_se(streq(str, "8000-8191"));
str = mfree(str);
+ assert_se(str = cpu_set_to_mask_string(&c));
+ log_info("cpu_set_to_mask_string: %s", str);
+ for (size_t i = 0; i < strlen(str); i++) {
+ if (i < 54) {
+ if (i >= 8 && (i + 1) % 9 == 0)
+ assert_se(str[i] == ',');
+ else
+ assert_se(str[i] == 'f');
+ }
+ else {
+ if (i >= 8 && (i + 1) % 9 == 0)
+ assert_se(str[i] == ',');
+ else
+ assert_se(str[i] == '0');
+ }
+ }
+ str = mfree(str);
cpu_set_reset(&c);
}
Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high)
Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high)
Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval)
+Link.ReceivePacketSteeringCPUMask, config_parse_rps_cpu_mask, 0, offsetof(LinkConfig, rps_cpu_mask)
Link.MDI, config_parse_mdi, 0, offsetof(LinkConfig, mdi)
Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs)
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
free(config->alias);
free(config->wol_password_file);
erase_and_free(config->wol_password);
+ cpu_set_free(config->rps_cpu_mask);
ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free);
return 0;
}
+static int link_apply_rps_cpu_mask(Link *link) {
+ _cleanup_free_ char *mask_str = NULL;
+ LinkConfig *config;
+ int r;
+
+ assert(link);
+ config = ASSERT_PTR(link->config);
+
+ /* Skip if the config is not specified. */
+ if (!config->rps_cpu_mask)
+ return 0;
+
+ mask_str = cpu_set_to_mask_string(config->rps_cpu_mask);
+ if (!mask_str)
+ return log_oom();
+
+ log_link_debug(link, "Applying RPS CPU mask: %s", mask_str);
+
+ /* Currently, this will set CPU mask to all rx queue of matched device. */
+ FOREACH_DEVICE_SYSATTR(link->device, attr) {
+ const char *c;
+
+ c = path_startswith(attr, "queues/");
+ if (!c)
+ continue;
+
+ c = startswith(c, "rx-");
+ if (!c)
+ continue;
+
+ c += strcspn(c, "/");
+
+ if (!path_equal(c, "/rps_cpus"))
+ continue;
+
+ r = sd_device_set_sysattr_value(link->device, attr, mask_str);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to write %s sysfs attribute, ignoring: %m", attr);
+ }
+
+ return 0;
+}
+
static int link_apply_udev_properties(Link *link, bool test) {
LinkConfig *config;
sd_device *device;
if (r < 0)
return r;
+ r = link_apply_rps_cpu_mask(link);
+ if (r < 0)
+ return r;
+
return 0;
}
return 0;
}
+int config_parse_rps_cpu_mask(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(cpu_set_freep) CPUSet *allocated = NULL;
+ CPUSet *mask, **rps_cpu_mask = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *rps_cpu_mask = cpu_set_free(*rps_cpu_mask);
+ return 0;
+ }
+
+ if (*rps_cpu_mask)
+ mask = *rps_cpu_mask;
+ else {
+ allocated = new0(CPUSet, 1);
+ if (!allocated)
+ return log_oom();
+
+ mask = allocated;
+ }
+
+ if (streq(rvalue, "disable")) {
+ cpu_set_reset(mask);
+ return 0;
+ }
+
+ if (streq(rvalue, "all")) {
+ r = cpu_mask_add_all(mask);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to create CPU affinity mask representing \"all\" cpus, ignoring: %m");
+ return 0;
+ }
+ } else {
+ r = parse_cpu_set_extend(rvalue, mask, /* warn= */ true, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+ }
+
+ if (allocated)
+ *rps_cpu_mask = TAKE_PTR(allocated);
+
+ return 0;
+}
+
static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
[MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
[MAC_ADDRESS_POLICY_RANDOM] = "random",
#include "condition.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
#include "ethtool-util.h"
#include "hashmap.h"
#include "list.h"
int autoneg_flow_control;
netdev_coalesce_param coalesce;
uint8_t mdi;
+ CPUSet *rps_cpu_mask;
uint32_t sr_iov_num_vfs;
OrderedHashmap *sr_iov_by_section;
CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_name_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_rps_cpu_mask);
_exit(EXIT_FAILURE);
}
+ r = setenv_systemd_log_level();
+ if (r < 0) {
+ log_error_errno(r, "Failed to set $SYSTEMD_LOG_LEVEL: %m");
+ _exit(EXIT_FAILURE);
+ }
+
r = invoke_callout_binary(SYSTEMD_USERWORK_PATH, STRV_MAKE(SYSTEMD_USERWORK_PATH, "xxxxxxxxxxxxxxxx")); /* With some extra space rename_process() can make use of */
log_error_errno(r, "Failed start worker process: %m");
_exit(EXIT_FAILURE);
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=disable
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0 3 8-invalid
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0 1
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0
+ReceivePacketSteeringCPUMask=
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0
+ReceivePacketSteeringCPUMask=invalid
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=1
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=all
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+OriginalName=dummy98
+
+[Link]
+ReceivePacketSteeringCPUMask=0 1
+ReceivePacketSteeringCPUMask=2,3
self.wait_online('ifb99:degraded')
+ def test_rps_cpu_0(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 1)
+
+ @unittest.skipUnless(os.cpu_count() >= 2, reason="CPU count should be >= 2 to pass this test")
+ def test_rps_cpu_1(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-1.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 2)
+
+ @unittest.skipUnless(os.cpu_count() >= 2, reason="CPU count should be >= 2 to pass this test")
+ def test_rps_cpu_0_1(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0-1.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 3)
+
+ @unittest.skipUnless(os.cpu_count() >= 4, reason="CPU count should be >= 4 to pass this test")
+ def test_rps_cpu_multi(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-multi.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 15)
+
+ def test_rps_cpu_all(self):
+ cpu_count = os.cpu_count()
+
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-all.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(f"{int(output.replace(',', ''), base=16):x}", f'{(1 << cpu_count) - 1:x}')
+
+ def test_rps_cpu_disable(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-all.link', '24-rps-cpu-disable.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
+ def test_rps_cpu_empty(self):
+ copy_network_unit('12-dummy.netdev', '24-rps-cpu-empty.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
+ def test_rps_cpu_0_empty(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0-empty.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
+ def test_rps_cpu_0_and_empty(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0.link', '24-rps-cpu-empty.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
+ def test_rps_cpu_invalid(self):
+ copy_network_unit('12-dummy.netdev', '24-rps-cpu-invalid.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
+ def test_rps_cpu_0_invalid(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0-invalid.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 1)
+
+ def test_rps_cpu_0_and_invalid(self):
+ copy_network_unit('12-dummy.netdev', '25-rps-cpu-0.link', '24-rps-cpu-invalid.link')
+ start_networkd()
+
+ self.wait_links('dummy98')
+
+ output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
+ print(output)
+ self.assertEqual(int(output.replace(',', ''), base=16), 0)
+
class NetworkdL2TPTests(unittest.TestCase, Utilities):
def setUp(self):
print(output)
self.assertRegex(output, r'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
- def test_replay_agent_on_bridge(self):
+ def test_relay_agent_on_bridge(self):
copy_network_unit('25-agent-bridge.netdev',
'25-agent-veth-client.netdev',
'25-agent-bridge.network',