Compare commits

..

13 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek 1048436869
Merge pull request #13452 from yuwata/network-reload
network: add networkctl reload and reconfigure
2019-10-24 11:07:24 +02:00
Yu Watanabe 235ecb6d75 test: drop duplicated 's'
This fixes the following log message
```
Container TEST-07-ISSUE-1981 terminated by signal KILL.
E: test timed out after 30s s
```
2019-10-24 08:39:31 +02:00
Yu Watanabe dcd9f07ccf network: add tests for "networkctl reconfigure" 2019-10-24 14:23:17 +09:00
Yu Watanabe 8dc85c5ef1 networkctl: introduce reconfigure method 2019-10-24 14:23:12 +09:00
Yu Watanabe e4857ee2f2 networkctl: use format_ifname_full() 2019-10-24 14:20:48 +09:00
Yu Watanabe d56d6cb8ca networkctl: fix error message 2019-10-24 14:20:48 +09:00
Yu Watanabe 882e21c72f format-util: introduce format_ifname_full() 2019-10-24 14:20:48 +09:00
Yu Watanabe 99b8517ca7 network: introduce Reconfigure() bus method 2019-10-24 14:20:48 +09:00
Yu Watanabe f39dbf28f3 network: include netinet/in.h to fix build error 2019-10-24 14:20:48 +09:00
Yu Watanabe 66de86712c test-network: add tests for "networkctl reload" 2019-10-24 14:20:48 +09:00
Yu Watanabe a227674cfb networkctl: add reload command 2019-10-24 14:20:42 +09:00
Yu Watanabe e272b62136 network: also reload .netdev files 2019-10-24 14:18:16 +09:00
Yu Watanabe 7f06b3e1b9 network: add Reload() dbus method 2019-10-24 14:18:09 +09:00
18 changed files with 363 additions and 68 deletions

View File

@ -261,6 +261,25 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
Takes interface name or index number.</para></listitem> Takes interface name or index number.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<command>reconfigure</command>
</term>
<listitem><para>Reconfigure network interfaces. Takes interface name or index number.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<command>reload</command>
</term>
<listitem><para>Reload <filename>.netdev</filename> and <filename>.network</filename> files.
If a new <filename>.netdev</filename> file is found, then the corresponding netdev is created.
Note that even if an existing <filename>.netdev</filename> is modified or removed,
<command>systemd-networkd</command> does not update or remove the netdev.
If a new, modified or removed <filename>.network</filename> file is found, then all interfaces
which match the file are reconfigured.</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -4,11 +4,24 @@
#include "format-util.h" #include "format-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "stdio-util.h"
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) { assert_cc(DECIMAL_STR_MAX(int) + 1 <= IF_NAMESIZE + 1);
char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag) {
/* Buffer is always cleared */ /* Buffer is always cleared */
memzero(buf, IF_NAMESIZE + 1); memzero(buf, IF_NAMESIZE + 1);
return if_indextoname(ifindex, buf); if (if_indextoname(ifindex, buf))
return buf;
if (!FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX))
return NULL;
if (FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX_WITH_PERCENT))
snprintf(buf, IF_NAMESIZE + 1, "%%%d", ifindex);
else
snprintf(buf, IF_NAMESIZE + 1, "%d", ifindex);
return buf;
} }
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) { char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {

View File

@ -68,7 +68,15 @@
# error Unknown ino_t size # error Unknown ino_t size
#endif #endif
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]); typedef enum {
FORMAT_IFNAME_IFINDEX = 1 << 0,
FORMAT_IFNAME_IFINDEX_WITH_PERCENT = (1 << 1) | FORMAT_IFNAME_IFINDEX,
} FormatIfnameFlag;
char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag);
static inline char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) {
return format_ifname_full(ifindex, buf, 0);
}
typedef enum { typedef enum {
FORMAT_BYTES_USE_IEC = 1 << 0, FORMAT_BYTES_USE_IEC = 1 << 0,

View File

@ -23,6 +23,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
fflush(f); fflush(f);
assert_se(manager_new(&manager) >= 0); assert_se(manager_new(&manager) >= 0);
(void) network_load_one(manager, network_config); (void) network_load_one(manager, &manager->networks, network_config);
return 0; return 0;
} }

View File

@ -757,9 +757,10 @@ int netdev_load_one(Manager *manager, const char *filename) {
NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname); NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname);
assert(n); assert(n);
log_netdev_warning_errno(netdev, r, if (!streq(netdev->filename, n->filename))
"The setting Name=%s in %s conflicts with the one in %s, ignoring", log_netdev_warning_errno(netdev, r,
netdev->ifname, netdev->filename, n->filename); "The setting Name=%s in %s conflicts with the one in %s, ignoring",
netdev->ifname, netdev->filename, n->filename);
/* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is /* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is
* removed from the hashmap 'manager->netdevs'. */ * removed from the hashmap 'manager->netdevs'. */
@ -828,14 +829,15 @@ int netdev_load_one(Manager *manager, const char *filename) {
return 0; return 0;
} }
int netdev_load(Manager *manager) { int netdev_load(Manager *manager, bool reload) {
_cleanup_strv_free_ char **files = NULL; _cleanup_strv_free_ char **files = NULL;
char **f; char **f;
int r; int r;
assert(manager); assert(manager);
hashmap_clear_with_destructor(manager->netdevs, netdev_unref); if (!reload)
hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS); r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
if (r < 0) if (r < 0)

View File

@ -156,7 +156,7 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
/* For casting the various netdev kinds into a netdev */ /* For casting the various netdev kinds into a netdev */
#define NETDEV(n) (&(n)->meta) #define NETDEV(n) (&(n)->meta)
int netdev_load(Manager *manager); int netdev_load(Manager *manager, bool reload);
int netdev_load_one(Manager *manager, const char *filename); int netdev_load_one(Manager *manager, const char *filename);
void netdev_drop(NetDev *netdev); void netdev_drop(NetDev *netdev);

View File

@ -719,10 +719,8 @@ static int dump_gateways(
if (ifindex <= 0) { if (ifindex <= 0) {
char name[IF_NAMESIZE+1]; char name[IF_NAMESIZE+1];
if (format_ifname(local[i].ifindex, name)) r = table_add_cell_stringf(table, NULL, "%s on %s", with_description ?: gateway,
r = table_add_cell_stringf(table, NULL, "%s on %s", with_description ?: gateway, name); format_ifname_full(local[i].ifindex, name, FORMAT_IFNAME_IFINDEX_WITH_PERCENT));
else
r = table_add_cell_stringf(table, NULL, "%s on %%%i", with_description ?: gateway, local[i].ifindex);
} else } else
r = table_add_cell(table, NULL, TABLE_STRING, with_description ?: gateway); r = table_add_cell(table, NULL, TABLE_STRING, with_description ?: gateway);
if (r < 0) if (r < 0)
@ -775,10 +773,8 @@ static int dump_addresses(
if (ifindex <= 0) { if (ifindex <= 0) {
char name[IF_NAMESIZE+1]; char name[IF_NAMESIZE+1];
if (format_ifname(local[i].ifindex, name)) r = table_add_cell_stringf(table, NULL, "%s on %s", pretty,
r = table_add_cell_stringf(table, NULL, "%s on %s", pretty, name); format_ifname_full(local[i].ifindex, name, FORMAT_IFNAME_IFINDEX_WITH_PERCENT));
else
r = table_add_cell_stringf(table, NULL, "%s on %%%i", pretty, local[i].ifindex);
} else } else
r = table_add_cell(table, NULL, TABLE_STRING, pretty); r = table_add_cell(table, NULL, TABLE_STRING, pretty);
if (r < 0) if (r < 0)
@ -1759,14 +1755,13 @@ static int link_delete(int argc, char *argv[], void *userdata) {
} }
SET_FOREACH(p, indexes, j) { SET_FOREACH(p, indexes, j) {
r = link_delete_send_message(rtnl, PTR_TO_INT(p)); index = PTR_TO_INT(p);
r = link_delete_send_message(rtnl, index);
if (r < 0) { if (r < 0) {
char ifname[IF_NAMESIZE + 1]; char ifname[IF_NAMESIZE + 1];
if (format_ifname(index, ifname)) return log_error_errno(r, "Failed to delete interface %s: %m",
return log_error_errno(r, "Failed to delete interface %s: %m", ifname); format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX));
else
return log_error_errno(r, "Failed to delete interface %d: %m", index);
} }
} }
@ -1815,6 +1810,73 @@ static int link_renew(int argc, char *argv[], void *userdata) {
} }
static int verb_reload(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
r = sd_bus_open_system(&bus);
if (r < 0)
return log_error_errno(r, "Failed to connect system bus: %m");
r = sd_bus_call_method(
bus,
"org.freedesktop.network1",
"/org/freedesktop/network1",
"org.freedesktop.network1.Manager",
"Reload",
&error, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reload network settings: %m");
return 0;
}
static int verb_reconfigure(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_set_free_ Set *indexes = NULL;
int index, i, r;
Iterator j;
void *p;
r = sd_bus_open_system(&bus);
if (r < 0)
return log_error_errno(r, "Failed to connect system bus: %m");
indexes = set_new(NULL);
if (!indexes)
return log_oom();
for (i = 1; i < argc; i++) {
r = parse_ifindex_or_ifname(argv[i], &index);
if (r < 0)
return log_error_errno(r, "Failed to resolve interface %s", argv[i]);
r = set_put(indexes, INT_TO_PTR(index));
if (r < 0)
return log_oom();
}
SET_FOREACH(p, indexes, j) {
index = PTR_TO_INT(p);
r = sd_bus_call_method(
bus,
"org.freedesktop.network1",
"/org/freedesktop/network1",
"org.freedesktop.network1.Manager",
"ReconfigureLink",
&error, NULL, "i", index);
if (r < 0) {
char ifname[IF_NAMESIZE + 1];
return log_error_errno(r, "Failed to reconfigure network interface %s: %m", format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX));
}
}
return 0;
}
static int help(void) { static int help(void) {
_cleanup_free_ char *link = NULL; _cleanup_free_ char *link = NULL;
int r; int r;
@ -1826,19 +1888,21 @@ static int help(void) {
printf("%s%s [OPTIONS...]\n\n" printf("%s%s [OPTIONS...]\n\n"
"Query and control the networking subsystem.%s\n" "Query and control the networking subsystem.%s\n"
"\nCommands:\n" "\nCommands:\n"
" list [PATTERN...] List links\n" " list [PATTERN...] List links\n"
" status [PATTERN...] Show link status\n" " status [PATTERN...] Show link status\n"
" lldp [PATTERN...] Show LLDP neighbors\n" " lldp [PATTERN...] Show LLDP neighbors\n"
" label Show current address label entries in the kernel\n" " label Show current address label entries in the kernel\n"
" delete DEVICES... Delete virtual netdevs\n" " delete DEVICES... Delete virtual netdevs\n"
" renew DEVICES... Renew dynamic configurations\n" " renew DEVICES... Renew dynamic configurations\n"
" reconfigure DEVICES... Reconfigure interfaces\n"
" reload Reload .network and .netdev files\n"
"\nOptions\n" "\nOptions\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n" " --version Show package version\n"
" --no-pager Do not pipe output into a pager\n" " --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n" " --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n" " -a --all Show status for all links\n"
" -s --stats Show detailed link statics\n" " -s --stats Show detailed link statics\n"
"\nSee the %s for details.\n" "\nSee the %s for details.\n"
, ansi_highlight() , ansi_highlight()
, program_invocation_short_name , program_invocation_short_name
@ -1911,12 +1975,14 @@ static int parse_argv(int argc, char *argv[]) {
static int networkctl_main(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) {
static const Verb verbs[] = { static const Verb verbs[] = {
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
{ "status", VERB_ANY, VERB_ANY, 0, link_status }, { "status", VERB_ANY, VERB_ANY, 0, link_status },
{ "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status }, { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
{ "label", VERB_ANY, VERB_ANY, 0, list_address_labels }, { "label", VERB_ANY, VERB_ANY, 0, list_address_labels },
{ "delete", 2, VERB_ANY, 0, link_delete }, { "delete", 2, VERB_ANY, 0, link_delete },
{ "renew", 2, VERB_ANY, 0, link_renew }, { "renew", 2, VERB_ANY, 0, link_renew },
{ "reconfigure", 2, VERB_ANY, 0, verb_reconfigure },
{ "reload", 1, 1, 0, verb_reload },
{} {}
}; };

View File

@ -604,6 +604,29 @@ int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error
return sd_bus_reply_method_return(message, NULL); return sd_bus_reply_method_return(message, NULL);
} }
int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Link *l = userdata;
int r;
assert(message);
assert(l);
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
"org.freedesktop.network1.reconfigure",
NULL, true, UID_INVALID,
&l->manager->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Polkit will call us back */
r = link_reconfigure(l, true);
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}
const sd_bus_vtable link_vtable[] = { const sd_bus_vtable link_vtable[] = {
SD_BUS_VTABLE_START(0), SD_BUS_VTABLE_START(0),
@ -625,6 +648,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reconfigure", NULL, NULL, bus_link_method_reconfigure, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END SD_BUS_VTABLE_END
}; };

View File

@ -31,3 +31,4 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error);

View File

@ -2857,7 +2857,7 @@ static int link_configure_duid(Link *link) {
return 0; return 0;
} }
int link_reconfigure(Link *link) { int link_reconfigure(Link *link, bool force) {
Network *network; Network *network;
int r; int r;
@ -2875,7 +2875,7 @@ int link_reconfigure(Link *link) {
} else if (r < 0) } else if (r < 0)
return r; return r;
if (link->network == network) if (link->network == network && !force)
return 0; return 0;
log_link_info(link, "Re-configuring with %s", network->filename); log_link_info(link, "Re-configuring with %s", network->filename);
@ -3337,7 +3337,7 @@ static int link_carrier_gained(Link *link) {
if (r < 0) if (r < 0)
return r; return r;
if (r > 0) { if (r > 0) {
r = link_reconfigure(link); r = link_reconfigure(link, false);
if (r < 0) if (r < 0)
return r; return r;
} }

View File

@ -208,7 +208,7 @@ uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
int link_request_set_routes(Link *link); int link_request_set_routes(Link *link);
int link_request_set_nexthop(Link *link); int link_request_set_nexthop(Link *link);
int link_reconfigure(Link *link); int link_reconfigure(Link *link, bool force);
#define ADDRESS_FMT_VAL(address) \ #define ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \ be32toh((address).s_addr) >> 24, \

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */ /* SPDX-License-Identifier: LGPL-2.1+ */
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h>
#include <sys/capability.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "bus-common-errors.h" #include "bus-common-errors.h"
@ -11,6 +13,7 @@
#include "networkd-manager.h" #include "networkd-manager.h"
#include "path-util.h" #include "path-util.h"
#include "strv.h" #include "strv.h"
#include "user-util.h"
static int method_list_links(sd_bus_message *message, void *userdata, sd_bus_error *error) { static int method_list_links(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@ -187,6 +190,42 @@ static int bus_method_renew_link(sd_bus_message *message, void *userdata, sd_bus
return call_link_method(userdata, message, bus_link_method_renew, error); return call_link_method(userdata, message, bus_link_method_renew, error);
} }
static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return call_link_method(userdata, message, bus_link_method_reconfigure, error);
}
static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
Iterator i;
Link *link;
int r;
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
"org.freedesktop.network1.reload",
NULL, true, UID_INVALID,
&manager->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Polkit will call us back */
r = netdev_load(manager, true);
if (r < 0)
return r;
r = network_reload(manager);
if (r < 0)
return r;
HASHMAP_FOREACH(link, manager->links, i) {
r = link_reconfigure(link, false);
if (r < 0)
return r;
}
return sd_bus_reply_method_return(message, NULL);
}
const sd_bus_vtable manager_vtable[] = { const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0), SD_BUS_VTABLE_START(0),
@ -209,6 +248,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RenewLink", "i", NULL, bus_method_renew_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("RenewLink", "i", NULL, bus_method_renew_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReconfigureLink", "i", NULL, bus_method_reconfigure_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reload", NULL, NULL, bus_method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END SD_BUS_VTABLE_END
}; };

View File

@ -1856,11 +1856,11 @@ int manager_load_config(Manager *m) {
/* update timestamp */ /* update timestamp */
paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true); paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true);
r = netdev_load(m); r = netdev_load(m, false);
if (r < 0) if (r < 0)
return r; return r;
r = network_load(m); r = network_load(m, &m->networks);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -314,7 +314,7 @@ int network_verify(Network *network) {
return 0; return 0;
} }
int network_load_one(Manager *manager, const char *filename) { int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
_cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_free_ char *fname = NULL, *name = NULL;
_cleanup_(network_unrefp) Network *network = NULL; _cleanup_(network_unrefp) Network *network = NULL;
_cleanup_fclose_ FILE *file = NULL; _cleanup_fclose_ FILE *file = NULL;
@ -488,36 +488,42 @@ int network_load_one(Manager *manager, const char *filename) {
log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m", log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
network->filename); network->filename);
r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops); struct stat stats;
if (r < 0) if (stat(filename, &stats) < 0)
return r; return -errno;
network->timestamp = timespec_load(&stats.st_mtim);
r = ordered_hashmap_put(manager->networks, network->name, network);
if (r < 0)
return r;
if (network_verify(network) < 0) if (network_verify(network) < 0)
/* Ignore .network files that do not match the conditions. */
return 0; return 0;
r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
if (r < 0)
return r;
r = ordered_hashmap_put(*networks, network->name, network);
if (r < 0)
return r;
network = NULL; network = NULL;
return 0; return 0;
} }
int network_load(Manager *manager) { int network_load(Manager *manager, OrderedHashmap **networks) {
_cleanup_strv_free_ char **files = NULL; _cleanup_strv_free_ char **files = NULL;
char **f; char **f;
int r; int r;
assert(manager); assert(manager);
ordered_hashmap_clear_with_destructor(manager->networks, network_unref); ordered_hashmap_clear_with_destructor(*networks, network_unref);
r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS); r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to enumerate network files: %m"); return log_error_errno(r, "Failed to enumerate network files: %m");
STRV_FOREACH(f, files) { STRV_FOREACH(f, files) {
r = network_load_one(manager, *f); r = network_load_one(manager, networks, *f);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to load %s, ignoring: %m", *f); log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
} }
@ -525,6 +531,48 @@ int network_load(Manager *manager) {
return 0; return 0;
} }
int network_reload(Manager *manager) {
OrderedHashmap *new_networks = NULL;
Network *n, *old;
Iterator i;
int r;
assert(manager);
r = network_load(manager, &new_networks);
if (r < 0)
goto failure;
ORDERED_HASHMAP_FOREACH(n, new_networks, i) {
r = network_get_by_name(manager, n->name, &old);
if (r < 0)
continue; /* The .network file is new. */
if (n->timestamp != old->timestamp)
continue; /* The .network file is modified. */
if (!streq(n->filename, old->filename))
continue;
r = ordered_hashmap_replace(new_networks, old->name, old);
if (r < 0)
goto failure;
network_ref(old);
network_unref(n);
}
ordered_hashmap_free_with_destructor(manager->networks, network_unref);
manager->networks = new_networks;
return 0;
failure:
ordered_hashmap_free_with_destructor(new_networks, network_unref);
return r;
}
static Network *network_free(Network *network) { static Network *network_free(Network *network) {
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address; IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
RoutingPolicyRule *rule; RoutingPolicyRule *rule;
@ -615,13 +663,9 @@ static Network *network_free(Network *network) {
hashmap_free(network->prefixes_by_section); hashmap_free(network->prefixes_by_section);
hashmap_free(network->rules_by_section); hashmap_free(network->rules_by_section);
if (network->manager) { if (network->manager &&
if (network->manager->networks && network->name) network->manager->duids_requesting_uuid)
ordered_hashmap_remove(network->manager->networks, network->name); set_remove(network->manager->duids_requesting_uuid, &network->duid);
if (network->manager->duids_requesting_uuid)
set_remove(network->manager->duids_requesting_uuid, &network->duid);
}
free(network->name); free(network->name);

View File

@ -54,6 +54,7 @@ struct Network {
char *filename; char *filename;
char *name; char *name;
usec_t timestamp;
unsigned n_ref; unsigned n_ref;
@ -283,8 +284,9 @@ Network *network_ref(Network *network);
Network *network_unref(Network *network); Network *network_unref(Network *network);
DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_unref);
int network_load(Manager *manager); int network_load(Manager *manager, OrderedHashmap **networks);
int network_load_one(Manager *manager, const char *filename); int network_reload(Manager *manager);
int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename);
int network_verify(Network *network); int network_verify(Network *network);
int network_get_by_name(Manager *manager, const char *name, Network **ret); int network_get_by_name(Manager *manager, const char *name, Network **ret);

View File

@ -150,4 +150,26 @@
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate> <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
</action> </action>
<action id="org.freedesktop.network1.reload">
<description gettext-domain="systemd">Reload network settings</description>
<message gettext-domain="systemd">Authentication is required to reload network settings.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
</action>
<action id="org.freedesktop.network1.reconfigure">
<description gettext-domain="systemd">Reconfigure network interface</description>
<message gettext-domain="systemd">Authentication is required to reconfigure network interface.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
</action>
</policyconfig> </policyconfig>

View File

@ -5,7 +5,7 @@ TEST_NO_QEMU=1
. $TEST_BASE_DIR/test-functions . $TEST_BASE_DIR/test-functions
NSPAWN_TIMEOUT=30s NSPAWN_TIMEOUT=30
test_setup() { test_setup() {
create_empty_image_rootdir create_empty_image_rootdir

View File

@ -380,6 +380,7 @@ class Utilities():
class NetworkctlTests(unittest.TestCase, Utilities): class NetworkctlTests(unittest.TestCase, Utilities):
links = [ links = [
'dummy98',
'test1', 'test1',
'veth99', 'veth99',
] ]
@ -388,6 +389,8 @@ class NetworkctlTests(unittest.TestCase, Utilities):
'11-dummy.netdev', '11-dummy.netdev',
'11-dummy-mtu.netdev', '11-dummy-mtu.netdev',
'11-dummy.network', '11-dummy.network',
'12-dummy.netdev',
'25-address-static.network',
'25-veth.netdev', '25-veth.netdev',
'netdev-link-local-addressing-yes.network', 'netdev-link-local-addressing-yes.network',
] ]
@ -401,6 +404,56 @@ class NetworkctlTests(unittest.TestCase, Utilities):
remove_unit_from_networkd_path(self.units) remove_unit_from_networkd_path(self.units)
stop_networkd(show_logs=True) stop_networkd(show_logs=True)
def test_reconfigure(self):
copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
start_networkd()
self.wait_online(['dummy98:routable'])
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
check_output('ip address del 10.1.2.3/16 dev dummy98')
check_output('ip address del 10.1.2.4/16 dev dummy98')
check_output('ip address del 10.2.2.4/16 dev dummy98')
check_output(*networkctl_cmd, 'reconfigure', 'dummy98', env=env)
self.wait_online(['dummy98:routable'])
output = check_output('ip -4 address show dev dummy98')
print(output)
self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
def test_reload(self):
start_networkd(3)
copy_unit_to_networkd_unit_path('11-dummy.netdev')
check_output(*networkctl_cmd, 'reload', env=env)
time.sleep(3)
self.check_link_exists('test1')
self.check_operstate('test1', 'off', setup_state='unmanaged')
copy_unit_to_networkd_unit_path('11-dummy.network')
check_output(*networkctl_cmd, 'reload', env=env)
self.wait_online(['test1:degraded'])
remove_unit_from_networkd_path(['11-dummy.network'])
check_output(*networkctl_cmd, 'reload', env=env)
time.sleep(1)
self.check_operstate('test1', 'degraded', setup_state='unmanaged')
remove_unit_from_networkd_path(['11-dummy.netdev'])
check_output(*networkctl_cmd, 'reload', env=env)
self.check_operstate('test1', 'degraded', setup_state='unmanaged')
copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
check_output(*networkctl_cmd, 'reload', env=env)
self.check_operstate('test1', 'degraded')
def test_glob(self): def test_glob(self):
copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network') copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
start_networkd() start_networkd()