From 95c71c8f6e2f689789eb9f882c605252a83d5827 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:20:21 +0900 Subject: [PATCH 1/9] sysctl: add missing help entry for --strict Follow-up for e88748c17e58aad6818e64fd3071de011808165e. --- src/sysctl/sysctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 7ad56b3ae9..ec622365c9 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -349,6 +349,7 @@ static int help(void) { " --tldr Show non-comment parts of configuration\n" " --prefix=PATH Only apply rules with the specified prefix\n" " --no-pager Do not pipe output into a pager\n" + " --strict Fail on any kind of failures\n" "\nSee the %s for details.\n", program_invocation_short_name, link); From e134b7fdd2c336d7675e6280e2b36f58c8a8fa04 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:26:04 +0900 Subject: [PATCH 2/9] sysctl: prettify help message --- src/sysctl/sysctl.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index ec622365c9..3055f79632 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -341,17 +341,22 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" - "Applies kernel sysctl settings.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" + printf("%1$s [OPTIONS...] [CONFIGURATION FILE...]\n" + "\n%2$sApplies kernel sysctl settings.%4$s\n" + "\n%3$sCommands:%4$s\n" " --cat-config Show configuration files\n" " --tldr Show non-comment parts of configuration\n" + " -h --help Show this help\n" + " --version Show package version\n" + "\n%3$sOptions:%4$s\n" " --prefix=PATH Only apply rules with the specified prefix\n" " --no-pager Do not pipe output into a pager\n" " --strict Fail on any kind of failures\n" - "\nSee the %s for details.\n", + "\nSee the %5$s for details.\n", program_invocation_short_name, + ansi_highlight(), + ansi_underline(), + ansi_normal(), link); return 0; From b65ddc64e0bef1ec9860f966caaf67d100b4e18a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:27:27 +0900 Subject: [PATCH 3/9] sysctl: propagate failures in parsing credential files We already propagate failures in parsing conf files in usual places, or given by command arguments. Let's make the behavior consistent. --- src/sysctl/sysctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 3055f79632..c2b5ca05c5 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -323,8 +323,7 @@ static int read_credential_lines(OrderedHashmap **sysctl_options) { if (!j) return log_oom(); - (void) parse_file(sysctl_options, j, /* ignore_enoent= */ true); - return 0; + return parse_file(sysctl_options, j, /* ignore_enoent= */ true); } static int cat_config(char **files) { From a81259051c77f452f341d991e0bfc266dd0bfdcd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:41:15 +0900 Subject: [PATCH 4/9] sysctl: shorten code a bit --- src/sysctl/sysctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index c2b5ca05c5..4490b9de0b 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -483,9 +483,7 @@ static int run(int argc, char *argv[]) { RET_GATHER(r, read_credential_lines(&sysctl_options)); } - RET_GATHER(r, apply_all(sysctl_options)); - - return r; + return RET_GATHER(r, apply_all(sysctl_options)); } DEFINE_MAIN_FUNCTION(run); From abb7a04361ccb7e67dccc4498ee50d8a9b7bee27 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:55:53 +0900 Subject: [PATCH 5/9] sysctl: assorted coding style cleanups --- src/sysctl/sysctl.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 4490b9de0b..47990b4e69 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -36,7 +36,7 @@ typedef struct Option { bool ignore_failure; } Option; -static Option *option_free(Option *o) { +static Option* option_free(Option *o) { if (!o) return NULL; @@ -47,7 +47,10 @@ static Option *option_free(Option *o) { } DEFINE_TRIVIAL_CLEANUP_FUNC(Option*, option_free); -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(option_hash_ops, char, string_hash_func, string_compare_func, Option, option_free); +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + option_hash_ops, + char, string_hash_func, string_compare_func, + Option, option_free); static bool test_prefix(const char *p) { if (strv_isempty(arg_prefixes)) @@ -56,7 +59,7 @@ static bool test_prefix(const char *p) { return path_startswith_strv(p, arg_prefixes); } -static Option *option_new( +static Option* option_new( const char *key, const char *value, bool ignore_failure) { @@ -155,14 +158,13 @@ static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, Option if (option->ignore_failure || ERRNO_IS_PRIVILEGE(r)) { log_debug_errno(r, "Failed to resolve glob '%s', ignoring: %m", option->key); return 0; - } else - return log_error_errno(r, "Couldn't resolve glob '%s': %m", option->key); + } + + return log_error_errno(r, "Couldn't resolve glob '%s': %m", option->key); } STRV_FOREACH(s, paths) { - const char *key; - - assert_se(key = path_startswith(*s, "/proc/sys")); + const char *key = ASSERT_SE_PTR(path_startswith(*s, "/proc/sys")); if (ordered_hashmap_contains(sysctl_options, key)) { log_debug("Not setting %s (explicit setting exists).", key); From 483de0e76b2a21cc12b9923a5f51e3974246b208 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 01:51:59 +0900 Subject: [PATCH 6/9] sysctl: port parse_file() over conf_file_read() Then, systemd-sysctl can also support stdin and relative paths, like systemd-sysusers and systemd-tmpfiles do. --- man/systemd-sysctl.service.xml | 8 +- src/sysctl/sysctl.c | 149 ++++++++++++++------------------- 2 files changed, 70 insertions(+), 87 deletions(-) diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml index 720beed8ee..0702fa87ce 100644 --- a/man/systemd-sysctl.service.xml +++ b/man/systemd-sysctl.service.xml @@ -42,8 +42,12 @@ When invoked with no arguments, /usr/lib/systemd/systemd-sysctl applies all directives from configuration files listed in sysctl.d5. - If one or more filenames are passed on the command line, only the directives in these files are - applied. + When invoked with positional arguments, the configuration specified by the command line arguments is + executed. If the string - is specified instead of a filename, the configuration is + read from standard input. If the argument is a file name (without any slashes), all configuration + directories are searched for a matching file and the file found that has the highest priority is + executed. If the argument is a path, that file is used directly without searching the configuration + directories for any other matching file. In addition, option may be used to limit which sysctl settings are applied. diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 47990b4e69..4e0c977c93 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -214,100 +214,79 @@ static int apply_all(OrderedHashmap *sysctl_options) { return r; } -static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ignore_enoent) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *pp = NULL; - unsigned c = 0; +static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config, void *userdata) { + OrderedHashmap **sysctl_options = ASSERT_PTR(userdata); + _cleanup_free_ char *k = NULL, *v = NULL; + bool ignore_failure = false; int r; - assert(path); - - r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("sysctl.d"), &f, &pp); - if (r < 0) { - if (ignore_enoent && r == -ENOENT) - return 0; - - return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path); - } - - log_debug("Parsing %s", pp); - for (;;) { - _cleanup_(option_freep) Option *new_option = NULL; - _cleanup_free_ char *l = NULL; - bool ignore_failure = false; - Option *existing; - char *value; - int k; - - k = read_stripped_line(f, LONG_LINE_MAX, &l); - if (k == 0) - break; - if (k < 0) - return log_error_errno(k, "Failed to read file '%s', ignoring: %m", pp); - - c++; - - if (isempty(l)) - continue; - if (strchr(COMMENTS, l[0])) - continue; - - char *p = l; - value = strchr(p, '='); - if (value) { - if (p[0] == '-') { - ignore_failure = true; - p++; - } - - *value = 0; - value++; - value = strstrip(value); - - } else { - if (p[0] == '-') - /* We have a "negative match" option. Let's continue with value==NULL. */ - p++; - else { - log_syntax(NULL, LOG_WARNING, pp, c, 0, - "Line is not an assignment, ignoring: %s", p); - if (r == 0) - r = -EINVAL; - continue; - } + const char *eq = strchr(buffer, '='); + if (eq) { + if (buffer[0] == '-') { + ignore_failure = true; + buffer++; } - p = strstrip(p); - p = sysctl_normalize(p); - - /* We can't filter out globs at this point, we'll need to do that later. */ - if (!string_is_glob(p) && - !test_prefix(p)) - continue; - - existing = ordered_hashmap_get(*sysctl_options, p); - if (existing) { - if (streq_ptr(value, existing->value)) { - existing->ignore_failure = existing->ignore_failure || ignore_failure; - continue; - } - - log_debug("Overwriting earlier assignment of %s at '%s:%u'.", p, pp, c); - option_free(ordered_hashmap_remove(*sysctl_options, p)); - } - - new_option = option_new(p, value, ignore_failure); - if (!new_option) + k = strndup(buffer, eq - buffer); + if (!k) return log_oom(); - k = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, new_option->key, new_option); - if (k < 0) - return log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", p); + v = strdup(eq + 1); + if (!v) + return log_oom(); - TAKE_PTR(new_option); + } else { + if (buffer[0] == '-') + /* We have a "negative match" option. Let's continue with value==NULL. */ + buffer++; + else + return log_syntax(NULL, LOG_WARNING, fname, line, SYNTHETIC_ERRNO(EINVAL), + "Line is not an assignment, ignoring: %s", buffer); + + k = strdup(buffer); + if (!k) + return log_oom(); } - return r; + const char *key = sysctl_normalize(strstrip(k)), *value = strstrip(v); + + /* We can't filter out globs at this point, we'll need to do that later. */ + if (!string_is_glob(key) && !test_prefix(key)) + return 0; + + Option *existing = ordered_hashmap_get(*sysctl_options, key); + if (existing) { + if (streq_ptr(value, existing->value)) { + existing->ignore_failure = existing->ignore_failure || ignore_failure; + return 0; + } + + log_syntax(NULL, LOG_DEBUG, fname, line, 0, + "Overwriting earlier assignment of '%s'.", key); + option_free(ordered_hashmap_remove(*sysctl_options, key)); + } + + _cleanup_(option_freep) Option *option = option_new(key, value, ignore_failure); + if (!option) + return log_oom(); + + r = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, option->key, option); + if (r < 0) + return log_error_errno(r, "Failed to add sysctl variable '%s' to hashmap: %m", key); + + TAKE_PTR(option); + return 0; +} + +static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ignore_enoent) { + return conf_file_read( + /* root = */ NULL, + (const char**) CONF_PATHS_STRV("sysctl.d"), + path, + parse_line, + sysctl_options, + ignore_enoent, + /* invalid_config = */ NULL); } static int read_credential_lines(OrderedHashmap **sysctl_options) { From ef6aa2351e2dab6c84cbeda2c00e2ed6bac96436 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 02:29:39 +0900 Subject: [PATCH 7/9] sysctl: add --inline option This maybe useful to apply a simple configuration without creating conf file. --- man/systemd-sysctl.service.xml | 8 ++++++++ src/sysctl/sysctl.c | 20 ++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml index 0702fa87ce..61fe5238b7 100644 --- a/man/systemd-sysctl.service.xml +++ b/man/systemd-sysctl.service.xml @@ -81,6 +81,14 @@ + + + Treat each positional argument as a separate configuration line instead of a file + name. + + + + diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 4e0c977c93..d761c7375a 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -26,6 +26,7 @@ static char **arg_prefixes = NULL; static CatFlags arg_cat_flags = CAT_CONFIG_OFF; static bool arg_strict = false; +static bool arg_inline = false; static PagerFlags arg_pager_flags = 0; STATIC_DESTRUCTOR_REGISTER(arg_prefixes, strv_freep); @@ -332,6 +333,7 @@ static int help(void) { " --prefix=PATH Only apply rules with the specified prefix\n" " --no-pager Do not pipe output into a pager\n" " --strict Fail on any kind of failures\n" + " --inline Treat arguments as configuration lines\n" "\nSee the %5$s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -351,6 +353,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_PREFIX, ARG_NO_PAGER, ARG_STRICT, + ARG_INLINE, }; static const struct option options[] = { @@ -361,6 +364,7 @@ static int parse_argv(int argc, char *argv[]) { { "prefix", required_argument, NULL, ARG_PREFIX }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "strict", no_argument, NULL, ARG_STRICT }, + { "inline", no_argument, NULL, ARG_INLINE }, {} }; @@ -416,6 +420,10 @@ static int parse_argv(int argc, char *argv[]) { arg_strict = true; break; + case ARG_INLINE: + arg_inline = true; + break; + case '?': return -EINVAL; @@ -443,11 +451,15 @@ static int run(int argc, char *argv[]) { umask(0022); if (argc > optind) { - r = 0; - - for (int i = optind; i < argc; i++) - RET_GATHER(r, parse_file(&sysctl_options, argv[i], false)); + unsigned pos = 0; + STRV_FOREACH(arg, strv_skip(argv, optind)) { + if (arg_inline) + /* Use (argument):n, where n==1 for the first positional arg */ + RET_GATHER(r, parse_line("(argument)", ++pos, *arg, /* invalid_config = */ NULL, &sysctl_options)); + else + RET_GATHER(r, parse_file(&sysctl_options, *arg, false)); + } } else { _cleanup_strv_free_ char **files = NULL; From 862b61a3a15a1c00077aabf771c1069c22c70278 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 03:26:28 +0900 Subject: [PATCH 8/9] test: merge TEST-76-SYSCTL into TEST-87-AUX-UTILS-VM --- .../TEST-76-SYSCTL/meson.build | 7 ---- test/integration-tests/meson.build | 1 - test/units/TEST-76-SYSCTL.sh | 39 ------------------- test/units/TEST-87-AUX-UTILS-VM.sysctl.sh | 36 +++++++++++++++++ 4 files changed, 36 insertions(+), 47 deletions(-) delete mode 100644 test/integration-tests/TEST-76-SYSCTL/meson.build delete mode 100755 test/units/TEST-76-SYSCTL.sh create mode 100755 test/units/TEST-87-AUX-UTILS-VM.sysctl.sh diff --git a/test/integration-tests/TEST-76-SYSCTL/meson.build b/test/integration-tests/TEST-76-SYSCTL/meson.build deleted file mode 100644 index 8dec5f37e7..0000000000 --- a/test/integration-tests/TEST-76-SYSCTL/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -integration_tests += [ - integration_test_template + { - 'name' : fs.name(meson.current_source_dir()), - }, -] diff --git a/test/integration-tests/meson.build b/test/integration-tests/meson.build index 5965f6646c..5d71e87c79 100644 --- a/test/integration-tests/meson.build +++ b/test/integration-tests/meson.build @@ -90,7 +90,6 @@ foreach dirname : [ 'TEST-73-LOCALE', 'TEST-74-AUX-UTILS', 'TEST-75-RESOLVED', - 'TEST-76-SYSCTL', 'TEST-78-SIGQUEUE', 'TEST-79-MEMPRESS', 'TEST-80-NOTIFYACCESS', diff --git a/test/units/TEST-76-SYSCTL.sh b/test/units/TEST-76-SYSCTL.sh deleted file mode 100755 index 04d89b8252..0000000000 --- a/test/units/TEST-76-SYSCTL.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# shellcheck source=test/units/util.sh -. "$(dirname "$0")"/util.sh - -export SYSTEMD_LOG_LEVEL=debug - -echo "foo.bar=42" >/tmp/foo.conf -assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf -assert_rc 1 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf - -echo "-foo.foo=42" >/tmp/foo.conf -assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf -assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf - -if ! systemd-detect-virt --quiet --container; then - ip link add hoge type dummy - udevadm wait --timeout=30 /sys/class/net/hoge - - cat >/tmp/foo.conf </proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp - echo 0 >/proc/sys/net/ipv4/conf/hoge/bootp_relay - echo 0 >/proc/sys/net/ipv4/conf/hoge/disable_policy - - assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge /tmp/foo.conf - assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1" - assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1" - assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0" -fi - -touch /testok diff --git a/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh b/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh new file mode 100755 index 0000000000..3bf1317327 --- /dev/null +++ b/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +export SYSTEMD_LOG_LEVEL=debug + +echo "foo.bar=42" >/tmp/foo.conf +assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf +assert_rc 1 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf + +echo "-foo.foo=42" >/tmp/foo.conf +assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf +assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf + +ip link add hoge type dummy +trap 'ip link del hoge' EXIT +udevadm wait --timeout=30 /sys/class/net/hoge + +cat >/tmp/foo.conf </proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp +echo 0 >/proc/sys/net/ipv4/conf/hoge/bootp_relay +echo 0 >/proc/sys/net/ipv4/conf/hoge/disable_policy + +assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge /tmp/foo.conf +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1" +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1" +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0" From 2de03c8e8b8ff553ece1423b003ec00492d33a6e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Oct 2025 03:21:05 +0900 Subject: [PATCH 9/9] test: add test cases for sysctl reading configuration from stdin or positional arguments --- test/units/TEST-87-AUX-UTILS-VM.sysctl.sh | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh b/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh index 3bf1317327..f84621431c 100755 --- a/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh +++ b/test/units/TEST-87-AUX-UTILS-VM.sysctl.sh @@ -16,6 +16,25 @@ echo "-foo.foo=42" >/tmp/foo.conf assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf +assert_rc 0 /usr/lib/systemd/systemd-sysctl --inline "foo.bar=42" +assert_rc 1 /usr/lib/systemd/systemd-sysctl --inline --strict "foo.bar=42" +assert_rc 0 /usr/lib/systemd/systemd-sysctl --inline -- "-foo.bar=42" +assert_rc 0 /usr/lib/systemd/systemd-sysctl --inline --strict -- "-foo.bar=42" + +/usr/lib/systemd/systemd-sysctl - </proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp +echo 0 >/proc/sys/net/ipv4/conf/hoge/bootp_relay +echo 0 >/proc/sys/net/ipv4/conf/hoge/disable_policy + +assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge --inline \ + 'net.ipv4.conf.*.drop_gratuitous_arp=1' \ + 'net.ipv4.*.*.bootp_relay=1' \ + 'net.ipv4.aaa.*.disable_policy=1' +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1" +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1" +assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0" + +echo 0 >/proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp +echo 0 >/proc/sys/net/ipv4/conf/hoge/bootp_relay +echo 0 >/proc/sys/net/ipv4/conf/hoge/disable_policy + +/usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge - <