</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>
</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>
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'
)
'(- *)--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'
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;
}
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) {
return 0;
}
-int reload_networkd(void) {
+int reload_networkd(bool reconfigure_links) {
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL;
int r;
(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) {
#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);
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;
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))
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;
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;
#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"
}
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;
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;
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");
"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,
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;
}
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;
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;
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
/* 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 */
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"),
&vl_method_GetStates,
&vl_method_GetNamespaceId,
&vl_method_GetLLDPNeighbors,
+ &vl_method_Reload,
&vl_method_SetPersistentStorage,
&vl_type_Address,
&vl_type_BitRates,
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()