Compare commits
13 Commits
6f3ad94590
...
1048436869
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 1048436869 | |
Yu Watanabe | 235ecb6d75 | |
Yu Watanabe | dcd9f07ccf | |
Yu Watanabe | 8dc85c5ef1 | |
Yu Watanabe | e4857ee2f2 | |
Yu Watanabe | d56d6cb8ca | |
Yu Watanabe | 882e21c72f | |
Yu Watanabe | 99b8517ca7 | |
Yu Watanabe | f39dbf28f3 | |
Yu Watanabe | 66de86712c | |
Yu Watanabe | a227674cfb | |
Yu Watanabe | e272b62136 | |
Yu Watanabe | 7f06b3e1b9 |
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, \
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue