networkctl,networkd: add --no-reconfigure flag to networkctl reload

Add a new --no-reconfigure flag to 'networkctl reload' that reloads
.network and .netdev files from disk without reconfiguring any network
interfaces. This may be useful to avoid reconfiguring multiple interfaces
simultaneously when multiple .network files are updated, or when an updated
.network file is applied to multiple interfaces.

On the networkd side, manager_reload() gains a reconfigure_links parameter
that gates the per-link reconfiguration loop. A new io.systemd.Network.Reload
varlink method is added that exposes this as an optional reconfigureLinks
boolean (defaults to true). Both plain 'networkctl reload' and
'--no-reconfigure' now unconditionally call this method first. If an older
networkd returns MethodNotFound, plain reload falls back to
io.systemd.service.Reload for backward compatibility; '--no-reconfigure'
fails with a clear error in that case.
This commit is contained in:
Nandakumar Raghavan
2026-07-20 14:35:04 +09:00
committed by Yu Watanabe
parent 1166f4472d
commit 13aec9fddf
15 changed files with 133 additions and 22 deletions
+19 -1
View File
@@ -543,7 +543,10 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
</para>
<para>If a new, modified, or removed <filename>.network</filename> file is found, then all
interfaces that matched the file are reconfigured.</para>
interfaces that matched the file are reconfigured. This reconfiguration step can be skipped by
passing <option>--no-reconfigure</option>, in which case only config files are reloaded from disk
without reconfiguring any network interfaces. Use <command>networkctl reconfigure</command> afterwards
to selectively apply config changes per interface.</para>
<xi:include href="version-info.xml" xpointer="v244"/>
</listitem>
@@ -729,6 +732,21 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
</listitem>
</varlistentry>
<varlistentry>
<term><option>--no-reconfigure</option></term>
<listitem>
<para>When used with <command>reload</command>, only reload config files from disk without
reconfiguring any network interfaces. This may be useful to avoid reconfiguring multiple
interfaces simultaneously when multiple <filename>.network</filename> files are updated,
or when an updated <filename>.network</filename> file is applied to multiple interfaces.
Use <command>networkctl reconfigure</command> afterwards to apply changes selectively
per interface.</para>
<xi:include href="version-info.xml" xpointer="v262"/>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--runtime</option></term>
+1 -1
View File
@@ -45,7 +45,7 @@ _networkctl() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
local -A OPTS=(
[STANDALONE]='-a --all -h --help --version --no-pager --no-legend --no-ask-password
-s --stats -l --full --no-reload --runtime'
-s --stats -l --full --no-reload --no-reconfigure --runtime'
[ARG]='-n --lines --json --drop-in'
)
+1
View File
@@ -58,5 +58,6 @@ _arguments \
'(- *)--version[Show package version]' \
'--drop-in=[Use the given drop-in file name]:NAME' \
'--no-reload[Do not reload the network manager state when editing]' \
'--no-reconfigure[Reload config files without reconfiguring network interfaces]' \
'--json=[Shows output formatted as JSON]:format:_networkctl_get_json' \
'*::networkctl commands:_networkctl_commands'
+1 -1
View File
@@ -411,7 +411,7 @@ static int reload_daemons(ReloadFlags flags) {
if (!networkd_is_running())
log_debug("systemd-networkd is not running, skipping reload.");
else
RET_GATHER(ret, reload_networkd());
RET_GATHER(ret, reload_networkd(/* reconfigure_links= */ true));
}
return ret;
+1 -1
View File
@@ -123,7 +123,7 @@ int verb_link_varlink_simple_method(int argc, char *argv[], uintptr_t _data, voi
}
int verb_reload(int argc, char *argv[], uintptr_t _data, void *userdata) {
return reload_networkd();
return reload_networkd(!arg_no_reconfigure);
}
int verb_persistent_storage(int argc, char *argv[], uintptr_t _data, void *userdata) {
+32 -4
View File
@@ -60,7 +60,7 @@ int varlink_connect_networkd(sd_varlink **ret_varlink) {
return 0;
}
int reload_networkd(void) {
int reload_networkd(bool reconfigure_links) {
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL;
int r;
@@ -70,11 +70,39 @@ int reload_networkd(void) {
(void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
return varlink_callbo_and_log(
sd_json_variant *reply = NULL;
const char *error_id = NULL;
r = sd_varlink_callbo(
vl,
"io.systemd.service.Reload",
/* reply= */ NULL,
"io.systemd.Network.Reload",
&reply,
&error_id,
SD_JSON_BUILD_PAIR_BOOLEAN("reconfigureLinks", reconfigure_links),
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
if (r < 0)
return log_error_errno(r, "Failed to call io.systemd.Network.Reload varlink method: %m");
if (error_id) {
if (streq(error_id, SD_VARLINK_ERROR_METHOD_NOT_FOUND)) {
if (!reconfigure_links)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Installed version of systemd-networkd does not support --no-reconfigure.");
/* Older networkd without io.systemd.Network.Reload, fall back to io.systemd.service.Reload. */
return varlink_callbo_and_log(
vl,
"io.systemd.service.Reload",
/* reply= */ NULL,
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password));
}
r = sd_varlink_error_to_errno(error_id, reply);
if (r != -EBADR)
return log_error_errno(r, "Failed to call io.systemd.Network.Reload varlink method: %m");
return log_error_errno(r, "Failed to call io.systemd.Network.Reload varlink method: %s", error_id);
}
return 0;
}
int reload_udevd(void) {
+1 -1
View File
@@ -4,7 +4,7 @@
#include "forward.h"
int varlink_connect_networkd(sd_varlink **ret_varlink);
int reload_networkd(void);
int reload_networkd(bool reconfigure_links);
int reload_udevd(void);
bool networkd_is_running(void);
+6
View File
@@ -28,6 +28,7 @@
PagerFlags arg_pager_flags = 0;
bool arg_legend = true;
bool arg_no_reload = false;
bool arg_no_reconfigure = false;
bool arg_all = false;
bool arg_stats = false;
bool arg_full = false;
@@ -167,6 +168,11 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
arg_no_reload = true;
break;
OPTION_LONG("no-reconfigure", NULL,
"Only reload config files, do not reconfigure network interfaces"):
arg_no_reconfigure = true;
break;
OPTION_LONG("drop-in", "NAME",
"Edit specified drop-in instead of main config file"):
if (isempty(opts.arg))
+1
View File
@@ -7,6 +7,7 @@
extern PagerFlags arg_pager_flags;
extern bool arg_legend;
extern bool arg_no_reload;
extern bool arg_no_reconfigure;
extern bool arg_all;
extern bool arg_stats;
extern bool arg_full;
+1 -1
View File
@@ -215,7 +215,7 @@ static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_err
if (r == 0)
return 1; /* Polkit will call us back */
r = manager_reload(manager, message, /* varlink= */ NULL);
r = manager_reload(manager, message, /* varlink= */ NULL, /* reconfigure_links= */ true);
if (r < 0)
return r;
+21 -2
View File
@@ -18,6 +18,7 @@
#include "networkd-manager.h"
#include "networkd-manager-varlink.h"
#include "stat-util.h"
#include "string-util.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.Network.Link.h"
#include "varlink-io.systemd.service.h"
@@ -237,6 +238,12 @@ static int vl_method_set_persistent_storage(sd_varlink *vlink, sd_json_variant *
}
static int vl_method_reload(sd_varlink *vlink, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "reconfigureLinks", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, 0, SD_JSON_NULLABLE },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
Manager *m = ASSERT_PTR(userdata);
int r;
@@ -245,7 +252,18 @@ static int vl_method_reload(sd_varlink *vlink, sd_json_variant *parameters, sd_v
if (m->reloading > 0)
return sd_varlink_error(vlink, "io.systemd.Network.AlreadyReloading", NULL);
r = sd_varlink_dispatch(vlink, parameters, dispatch_table_polkit_only, /* userdata= */ NULL);
const char *method;
r = sd_varlink_get_current_method(vlink, &method);
if (r < 0)
return r;
bool is_network_reload = streq(method, "io.systemd.Network.Reload");
int reconfigure_links = -1; /* tristate: -1 = unset (defaults to true) */
r = sd_varlink_dispatch(
vlink,
parameters,
is_network_reload ? dispatch_table : dispatch_table_polkit_only,
&reconfigure_links);
if (r != 0)
return r;
@@ -258,7 +276,7 @@ static int vl_method_reload(sd_varlink *vlink, sd_json_variant *parameters, sd_v
if (r <= 0)
return r;
r = manager_reload(m, /* message= */ NULL, vlink);
r = manager_reload(m, /* message= */ NULL, vlink, /* reconfigure_links= */ reconfigure_links != 0);
if (r < 0)
return log_error_errno(r, "Failed to reload: %m");
@@ -302,6 +320,7 @@ int manager_varlink_init(Manager *m, int fd) {
"io.systemd.Network.GetStates", vl_method_get_states,
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id,
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors,
"io.systemd.Network.Reload", vl_method_reload,
"io.systemd.Network.SetPersistentStorage", vl_method_set_persistent_storage,
"io.systemd.Network.Link.Describe", vl_method_link_describe,
"io.systemd.Network.Link.Up", vl_method_link_up,
+10 -9
View File
@@ -535,7 +535,7 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig
static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
(void) manager_reload(m, /* message= */ NULL, /* varlink= */ NULL);
(void) manager_reload(m, /* message= */ NULL, /* varlink= */ NULL, /* reconfigure_links= */ true);
return 0;
}
@@ -1266,7 +1266,7 @@ int manager_set_timezone(Manager *m, const char *tz) {
return 0;
}
int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink) {
int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink, bool reconfigure_links) {
Link *link;
int r;
@@ -1288,13 +1288,14 @@ int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink) {
goto finish;
}
HASHMAP_FOREACH(link, m->links_by_index)
(void) link_reconfigure_full(
link,
/* flags= */ 0,
message,
varlink,
/* counter= */ (message || varlink) ? &m->reloading : NULL);
if (reconfigure_links)
HASHMAP_FOREACH(link, m->links_by_index)
(void) link_reconfigure_full(
link,
/* flags= */ 0,
message,
varlink,
/* counter= */ (message || varlink) ? &m->reloading : NULL);
log_debug("Reloaded.");
r = 0;
+1 -1
View File
@@ -159,7 +159,7 @@ int manager_enumerate(Manager *m);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *tz);
int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink);
int manager_reload(Manager *m, sd_bus_message *message, sd_varlink *varlink, bool reconfigure_links);
static inline Hashmap** manager_get_sysctl_shadow(Manager *manager) {
#if ENABLE_SYSCTL_BPF
+8
View File
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bus-polkit.h"
#include "varlink-io.systemd.Network.h"
/* Helper macro to define address fields with both binary and string representation */
@@ -544,6 +545,12 @@ SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("Current transmit/receive bitrates from speed meter"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(BitRates, BitRates, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Reload,
SD_VARLINK_FIELD_COMMENT("If true (default), reload config files and reconfigure all matching network interfaces. If false, only reload config files without reconfiguring interfaces; use 'networkctl reconfigure' afterwards to apply changes selectively."),
SD_VARLINK_DEFINE_INPUT(reconfigureLinks, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_METHOD(
Describe,
SD_VARLINK_FIELD_COMMENT("All network interfaces managed by systemd-networkd"),
@@ -612,6 +619,7 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_GetStates,
&vl_method_GetNamespaceId,
&vl_method_GetLLDPNeighbors,
&vl_method_Reload,
&vl_method_SetPersistentStorage,
&vl_type_Address,
&vl_type_BitRates,
@@ -1699,6 +1699,35 @@ class NetworkctlTests(unittest.TestCase, Utilities):
networkctl_reload()
self.wait_operstate('test1', 'degraded')
def test_reload_no_reconfigure(self):
copy_network_unit('12-dummy.netdev', '25-address-static.network', copy_dropins=False)
start_networkd()
self.wait_online('dummy98:routable')
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
with open(
os.path.join(network_unit_dir, '25-address-static.network'), mode='w', encoding='utf-8'
) as f:
f.write('[Match]\nName=dummy98\n\n[Network]\nIPv6AcceptRA=no\nAddress=10.99.0.1/24\n')
networkctl('reload', '--no-reconfigure')
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
self.assertNotIn('inet 10.99.0.1/24', output)
networkctl_reconfigure('dummy98')
self.wait_online('dummy98:routable')
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertIn('inet 10.99.0.1/24 brd 10.99.0.255 scope global dummy98', output)
self.assertNotIn('inet 10.1.2.3/16', output)
def test_glob(self):
copy_network_unit('11-dummy.netdev', '11-dummy.network')
start_networkd()