mirror of
https://github.com/systemd/systemd.git
synced 2025-01-26 14:04:03 +03:00
Merge pull request #34318 from YHNdnzj/networkctl-edit-if-netdev
networkctl: support editing netdev files by link and cat ":all"
This commit is contained in:
commit
6d449bc71f
@ -434,8 +434,9 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
||||
<filename>/run/</filename>, depending on whether <option>--runtime</option> is specified.
|
||||
Specially, if the name is prefixed by <literal>@</literal>, it will be treated as
|
||||
a network interface, and editing will be performed on the network config files associated
|
||||
with it. Additionally, the interface name can be suffixed with <literal>:network</literal> (default)
|
||||
or <literal>:link</literal>, in order to choose the type of network config to operate on.</para>
|
||||
with it. Additionally, the interface name can be suffixed with <literal>:network</literal> (default),
|
||||
<literal>:link</literal>, or <literal>:netdev</literal>, in order to choose the type of network config
|
||||
to operate on.</para>
|
||||
|
||||
<para>If <option>--drop-in=</option> is specified, edit the drop-in file instead of
|
||||
the main configuration file. Unless <option>--no-reload</option> is specified,
|
||||
@ -460,9 +461,10 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
||||
<optional><replaceable>FILE</replaceable>|<replaceable>@DEVICE</replaceable>…</optional>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Show network configuration files. This command honors the <literal>@</literal> prefix in the
|
||||
same way as <command>edit</command>. When no argument is specified,
|
||||
<citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
<para>Show network configuration files. This command honors the <literal>@</literal> prefix in a
|
||||
similar way as <command>edit</command>, with support for an additional suffix <literal>:all</literal>
|
||||
for showing all types of configuration files associated with the interface at once. When no argument
|
||||
is specified, <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
and its drop-in files will be shown.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v254"/>
|
||||
|
@ -159,25 +159,37 @@ int sd_network_link_get_network_file(int ifindex, char **ret) {
|
||||
return network_link_get_string(ifindex, "NETWORK_FILE", ret);
|
||||
}
|
||||
|
||||
int sd_network_link_get_network_file_dropins(int ifindex, char ***ret) {
|
||||
_cleanup_free_ char **sv = NULL, *joined = NULL;
|
||||
int sd_network_link_get_netdev_file(int ifindex, char **ret) {
|
||||
return network_link_get_string(ifindex, "NETDEV_FILE", ret);
|
||||
}
|
||||
|
||||
static int link_get_config_file_dropins_internal(int ifindex, const char *field, char ***ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(field);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = network_link_get_string(ifindex, "NETWORK_FILE_DROPINS", &joined);
|
||||
r = network_link_get_string(ifindex, field, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_split_full(&sv, joined, ":", EXTRACT_CUNESCAPE);
|
||||
r = strv_split_full(ret, s, ":", EXTRACT_CUNESCAPE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(sv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_network_link_get_network_file_dropins(int ifindex, char ***ret) {
|
||||
return link_get_config_file_dropins_internal(ifindex, "NETWORK_FILE_DROPINS", ret);
|
||||
}
|
||||
|
||||
int sd_network_link_get_netdev_file_dropins(int ifindex, char ***ret) {
|
||||
return link_get_config_file_dropins_internal(ifindex, "NETDEV_FILE_DROPINS", ret);
|
||||
}
|
||||
|
||||
int sd_network_link_get_operational_state(int ifindex, char **ret) {
|
||||
return network_link_get_string(ifindex, "OPER_STATE", ret);
|
||||
}
|
||||
|
@ -215,6 +215,7 @@ static NetDev *netdev_free(NetDev *netdev) {
|
||||
|
||||
condition_free_list(netdev->conditions);
|
||||
free(netdev->filename);
|
||||
strv_free(netdev->dropins);
|
||||
free(netdev->description);
|
||||
free(netdev->ifname);
|
||||
|
||||
@ -832,7 +833,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
NETDEV_VTABLE(netdev)->sections,
|
||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||
CONFIG_PARSE_WARN,
|
||||
netdev, NULL, NULL);
|
||||
netdev,
|
||||
NULL,
|
||||
&netdev->dropins);
|
||||
if (r < 0)
|
||||
return r; /* config_parse_many() logs internally. */
|
||||
|
||||
|
@ -116,6 +116,7 @@ typedef struct NetDev {
|
||||
unsigned n_ref;
|
||||
|
||||
char *filename;
|
||||
char **dropins;
|
||||
|
||||
LIST_HEAD(Condition, conditions);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "selinux-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "virt.h"
|
||||
|
||||
@ -31,6 +32,22 @@ typedef enum ReloadFlags {
|
||||
RELOAD_UDEVD = 1 << 1,
|
||||
} ReloadFlags;
|
||||
|
||||
typedef enum LinkConfigType {
|
||||
CONFIG_NETWORK,
|
||||
CONFIG_LINK,
|
||||
CONFIG_NETDEV,
|
||||
_CONFIG_MAX,
|
||||
_CONFIG_INVALID = -EINVAL,
|
||||
} LinkConfigType;
|
||||
|
||||
static const char* const link_config_type_table[_CONFIG_MAX] = {
|
||||
[CONFIG_NETWORK] = "network",
|
||||
[CONFIG_LINK] = "link",
|
||||
[CONFIG_NETDEV] = "netdev",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(link_config_type, LinkConfigType);
|
||||
|
||||
static int get_config_files_by_name(
|
||||
const char *name,
|
||||
bool allow_masked,
|
||||
@ -115,28 +132,25 @@ static int get_dropin_by_name(
|
||||
}
|
||||
|
||||
static int get_network_files_by_link(
|
||||
sd_netlink **rtnl,
|
||||
const char *link,
|
||||
int ifindex,
|
||||
bool ignore_missing,
|
||||
char **ret_path,
|
||||
char ***ret_dropins) {
|
||||
|
||||
_cleanup_strv_free_ char **dropins = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r, ifindex;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(link);
|
||||
assert(ifindex > 0);
|
||||
assert(ret_path);
|
||||
assert(ret_dropins);
|
||||
|
||||
ifindex = rtnl_resolve_interface_or_warn(rtnl, link);
|
||||
if (ifindex < 0)
|
||||
return ifindex;
|
||||
|
||||
r = sd_network_link_get_network_file(ifindex, &path);
|
||||
if (r == -ENODATA)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
|
||||
"Link '%s' has no associated network file.", link);
|
||||
return log_full_errno(ignore_missing ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ENOENT),
|
||||
"Link '%s' has no associated network file.", link);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get network file for link '%s': %m", link);
|
||||
|
||||
@ -150,7 +164,40 @@ static int get_network_files_by_link(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_link_files_by_link(const char *link, char **ret_path, char ***ret_dropins) {
|
||||
static int get_netdev_files_by_link(
|
||||
const char *link,
|
||||
int ifindex,
|
||||
bool ignore_missing,
|
||||
char **ret_path,
|
||||
char ***ret_dropins) {
|
||||
|
||||
_cleanup_strv_free_ char **dropins = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(ifindex > 0);
|
||||
assert(ret_path);
|
||||
assert(ret_dropins);
|
||||
|
||||
r = sd_network_link_get_netdev_file(ifindex, &path);
|
||||
if (r == -ENODATA)
|
||||
return log_full_errno(ignore_missing ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ENOENT),
|
||||
"Link '%s' has no associated netdev file.", link);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get netdev file for link '%s': %m", link);
|
||||
|
||||
r = sd_network_link_get_netdev_file_dropins(ifindex, &dropins);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return log_error_errno(r, "Failed to get netdev drop-ins for link '%s': %m", link);
|
||||
|
||||
*ret_path = TAKE_PTR(path);
|
||||
*ret_dropins = TAKE_PTR(dropins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_link_files_by_link(const char *link, bool ignore_missing, char **ret_path, char ***ret_dropins) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
_cleanup_strv_free_ char **dropins_split = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
@ -167,7 +214,8 @@ static int get_link_files_by_link(const char *link, char **ret_path, char ***ret
|
||||
|
||||
r = sd_device_get_property_value(device, "ID_NET_LINK_FILE", &path);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "Link '%s' has no associated link file.", link);
|
||||
return log_full_errno(ignore_missing ? LOG_DEBUG : LOG_ERR, r,
|
||||
"Link '%s' has no associated link file.", link);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get link file for link '%s': %m", link);
|
||||
|
||||
@ -191,62 +239,72 @@ static int get_link_files_by_link(const char *link, char **ret_path, char ***ret
|
||||
}
|
||||
|
||||
static int get_config_files_by_link_config(
|
||||
const char *link_config,
|
||||
const char *ifname,
|
||||
LinkConfigType type,
|
||||
bool ignore_missing,
|
||||
sd_netlink **rtnl,
|
||||
char **ret_path,
|
||||
char ***ret_dropins,
|
||||
ReloadFlags *ret_reload) {
|
||||
char ***ret_dropins) {
|
||||
|
||||
_cleanup_strv_free_ char **dropins = NULL, **link_config_split = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
const char *ifname, *type;
|
||||
ReloadFlags reload;
|
||||
size_t n;
|
||||
int r;
|
||||
|
||||
assert(link_config);
|
||||
assert(ifname);
|
||||
assert(type >= 0 && type < _CONFIG_MAX);
|
||||
assert(rtnl);
|
||||
assert(ret_path);
|
||||
assert(ret_dropins);
|
||||
|
||||
link_config_split = strv_split(link_config, ":");
|
||||
if (!link_config_split)
|
||||
return log_oom();
|
||||
if (type == CONFIG_LINK)
|
||||
return get_link_files_by_link(ifname, ignore_missing, ret_path, ret_dropins);
|
||||
|
||||
n = strv_length(link_config_split);
|
||||
if (n == 0 || isempty(link_config_split[0]))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No link name is given.");
|
||||
if (n > 2)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid link config '%s'.", link_config);
|
||||
if (!networkd_is_running())
|
||||
return log_full_errno(ignore_missing ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ESRCH),
|
||||
"Cannot get network/netdev file for link if systemd-networkd is not running.");
|
||||
|
||||
ifname = link_config_split[0];
|
||||
type = n == 2 ? link_config_split[1] : "network";
|
||||
int ifindex = rtnl_resolve_interface_or_warn(rtnl, ifname);
|
||||
if (ifindex < 0)
|
||||
return ifindex;
|
||||
|
||||
if (streq(type, "network")) {
|
||||
if (!networkd_is_running())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
||||
"Cannot get network file for link if systemd-networkd is not running.");
|
||||
if (type == CONFIG_NETWORK)
|
||||
r = get_network_files_by_link(ifname, ifindex, ignore_missing, ret_path, ret_dropins);
|
||||
else if (type == CONFIG_NETDEV)
|
||||
r = get_netdev_files_by_link(ifname, ifindex, ignore_missing, ret_path, ret_dropins);
|
||||
else
|
||||
assert_not_reached();
|
||||
|
||||
r = get_network_files_by_link(rtnl, ifname, &path, &dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
reload = RELOAD_NETWORKD;
|
||||
} else if (streq(type, "link")) {
|
||||
r = get_link_files_by_link(ifname, &path, &dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
static int parse_link_config(const char *link_config, char **ret_ifname, LinkConfigType *ret_type) {
|
||||
const char *p = ASSERT_PTR(link_config);
|
||||
_cleanup_free_ char *ifname = NULL;
|
||||
int r;
|
||||
|
||||
reload = RELOAD_UDEVD;
|
||||
} else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid config type '%s' for link '%s'.", type, ifname);
|
||||
assert(ret_ifname);
|
||||
assert(ret_type);
|
||||
|
||||
*ret_path = TAKE_PTR(path);
|
||||
*ret_dropins = TAKE_PTR(dropins);
|
||||
r = extract_first_word(&p, &ifname, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r <= 0)
|
||||
return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL),
|
||||
"Failed to extract link name from '%s': %m", link_config);
|
||||
|
||||
if (ret_reload)
|
||||
*ret_reload = reload;
|
||||
if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid link name: %s", ifname);
|
||||
|
||||
LinkConfigType t;
|
||||
|
||||
if (isempty(p))
|
||||
t = CONFIG_NETWORK;
|
||||
else if (streq(p, "all"))
|
||||
t = _CONFIG_MAX;
|
||||
else {
|
||||
t = link_config_type_from_string(p);
|
||||
if (t < 0)
|
||||
return log_error_errno(t, "Invalid config type '%s' for link '%s'.", p, ifname);
|
||||
}
|
||||
|
||||
*ret_ifname = TAKE_PTR(ifname);
|
||||
*ret_type = t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -427,18 +485,29 @@ int verb_edit(int argc, char *argv[], void *userdata) {
|
||||
|
||||
link_config = startswith(*name, "@");
|
||||
if (link_config) {
|
||||
ReloadFlags flags;
|
||||
_cleanup_free_ char *ifname = NULL;
|
||||
LinkConfigType type;
|
||||
|
||||
r = get_config_files_by_link_config(link_config, &rtnl, &path, &dropins, &flags);
|
||||
r = parse_link_config(link_config, &ifname, &type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (type == _CONFIG_MAX)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Config type 'all' cannot be used with 'edit'.");
|
||||
|
||||
reload |= flags;
|
||||
r = get_config_files_by_link_config(ifname, type,
|
||||
/* ignore_missing = */ false,
|
||||
&rtnl,
|
||||
&path, &dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_config_to_edit(&context, path, dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
reload |= type == CONFIG_LINK ? RELOAD_UDEVD : RELOAD_NETWORKD;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -482,6 +551,66 @@ int verb_edit(int argc, char *argv[], void *userdata) {
|
||||
return reload_daemons(reload);
|
||||
}
|
||||
|
||||
static int cat_files_by_link_one(
|
||||
const char *ifname,
|
||||
LinkConfigType type,
|
||||
sd_netlink **rtnl,
|
||||
bool ignore_missing,
|
||||
bool *first) {
|
||||
|
||||
_cleanup_strv_free_ char **dropins = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
assert(ifname);
|
||||
assert(type >= 0 && type < _CONFIG_MAX);
|
||||
assert(rtnl);
|
||||
assert(first);
|
||||
|
||||
r = get_config_files_by_link_config(ifname, type, ignore_missing, rtnl, &path, &dropins);
|
||||
if (ignore_missing && IN_SET(r, -ENOENT, -ESRCH))
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!*first)
|
||||
putchar('\n');
|
||||
|
||||
r = cat_files(path, dropins, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*first = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cat_files_by_link_config(const char *link_config, sd_netlink **rtnl, bool *first) {
|
||||
_cleanup_free_ char *ifname = NULL;
|
||||
LinkConfigType type;
|
||||
int r;
|
||||
|
||||
assert(link_config);
|
||||
assert(rtnl);
|
||||
assert(first);
|
||||
|
||||
r = parse_link_config(link_config, &ifname, &type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (type == _CONFIG_MAX) {
|
||||
for (LinkConfigType i = 0; i < _CONFIG_MAX; i++) {
|
||||
r = cat_files_by_link_one(ifname, i, rtnl, /* ignore_missing = */ true, first);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cat_files_by_link_one(ifname, type, rtnl, /* ignore_missing = */ false, first);
|
||||
}
|
||||
|
||||
int verb_cat(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
char **args = strv_skip(argv, 1);
|
||||
@ -494,37 +623,37 @@ int verb_cat(int argc, char *argv[], void *userdata) {
|
||||
|
||||
bool first = true;
|
||||
STRV_FOREACH(name, args) {
|
||||
_cleanup_strv_free_ char **dropins = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
const char *link_config;
|
||||
|
||||
link_config = startswith(*name, "@");
|
||||
if (link_config) {
|
||||
r = get_config_files_by_link_config(link_config, &rtnl, &path, &dropins, /* ret_reload = */ NULL);
|
||||
r = cat_files_by_link_config(link_config, &rtnl, &first);
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
} else {
|
||||
r = get_config_files_by_name(*name, /* allow_masked = */ false, &path, &dropins);
|
||||
if (r == -ENOENT) {
|
||||
RET_GATHER(ret, log_error_errno(r, "Cannot find network config file '%s'.", *name));
|
||||
continue;
|
||||
}
|
||||
if (r == -ERFKILL) {
|
||||
RET_GATHER(ret, log_debug_errno(r, "Network config '%s' is masked, ignoring.", *name));
|
||||
continue;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to get the path of network config '%s': %m", *name);
|
||||
return RET_GATHER(ret, r);
|
||||
}
|
||||
return r;
|
||||
continue;
|
||||
}
|
||||
|
||||
_cleanup_strv_free_ char **dropins = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
r = get_config_files_by_name(*name, /* allow_masked = */ false, &path, &dropins);
|
||||
if (r == -ENOENT) {
|
||||
RET_GATHER(ret, log_error_errno(r, "Cannot find network config file '%s'.", *name));
|
||||
continue;
|
||||
}
|
||||
if (r == -ERFKILL) {
|
||||
RET_GATHER(ret, log_debug_errno(r, "Network config '%s' is masked, ignoring.", *name));
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get the path of network config '%s': %m", *name);
|
||||
|
||||
if (!first)
|
||||
putchar('\n');
|
||||
|
||||
r = cat_files(path, dropins, /* flags = */ CAT_FORMAT_HAS_SECTIONS);
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
return r;
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
@ -227,8 +227,10 @@ static int table_add_string_line(Table *table, const char *key, const char *valu
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int format_dropins(char **dropins) {
|
||||
STRV_FOREACH(d, dropins) {
|
||||
static int format_config_files(char ***files, const char *main_config) {
|
||||
assert(files);
|
||||
|
||||
STRV_FOREACH(d, *files) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int glyph = *(d + 1) == NULL ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH;
|
||||
|
||||
@ -239,6 +241,9 @@ static int format_dropins(char **dropins) {
|
||||
free_and_replace(*d, s);
|
||||
}
|
||||
|
||||
if (strv_prepend(files, main_config) < 0)
|
||||
return log_oom();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -250,8 +255,8 @@ static int link_status_one(
|
||||
const LinkInfo *info) {
|
||||
|
||||
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL,
|
||||
**route_domains = NULL, **link_dropins = NULL, **network_dropins = NULL;
|
||||
_cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL, *captive_portal = NULL,
|
||||
**route_domains = NULL, **link_dropins = NULL, **network_dropins = NULL, **netdev_dropins = NULL;
|
||||
_cleanup_free_ char *t = NULL, *network = NULL, *netdev = NULL, *iaid = NULL, *duid = NULL, *captive_portal = NULL,
|
||||
*setup_state = NULL, *operational_state = NULL, *online_state = NULL, *activation_policy = NULL;
|
||||
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
|
||||
*on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup, *on_color_online;
|
||||
@ -282,6 +287,8 @@ static int link_status_one(
|
||||
(void) sd_network_link_get_captive_portal(info->ifindex, &captive_portal);
|
||||
(void) sd_network_link_get_network_file(info->ifindex, &network);
|
||||
(void) sd_network_link_get_network_file_dropins(info->ifindex, &network_dropins);
|
||||
(void) sd_network_link_get_netdev_file(info->ifindex, &netdev);
|
||||
(void) sd_network_link_get_netdev_file_dropins(info->ifindex, &netdev_dropins);
|
||||
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
|
||||
(void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
|
||||
(void) sd_network_link_get_activation_policy(info->ifindex, &activation_policy);
|
||||
@ -312,19 +319,17 @@ static int link_status_one(
|
||||
|
||||
(void) dhcp_lease_load(&lease, lease_file);
|
||||
|
||||
r = format_dropins(network_dropins);
|
||||
r = format_config_files(&network_dropins, network);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_prepend(&network_dropins, network) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = format_dropins(link_dropins);
|
||||
r = format_config_files(&link_dropins, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_prepend(&link_dropins, link) < 0)
|
||||
return log_oom();
|
||||
r = format_config_files(&netdev_dropins, netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
table = table_new_vertical();
|
||||
if (!table)
|
||||
@ -333,7 +338,15 @@ static int link_status_one(
|
||||
if (arg_full)
|
||||
table_set_width(table, 0);
|
||||
|
||||
/* unit files and basic states. */
|
||||
/* Config files and basic states. */
|
||||
if (netdev_dropins) {
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "NetDev File",
|
||||
TABLE_STRV, netdev_dropins);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "Link File",
|
||||
TABLE_STRV, link_dropins ?: STRV_MAKE("n/a"),
|
||||
|
@ -277,10 +277,6 @@ int manager_save(Manager *m) {
|
||||
address_state = LINK_ADDRESS_STATE_OFF;
|
||||
LinkOnlineState online_state;
|
||||
size_t links_offline = 0, links_online = 0;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_strv_free_ char **p = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -288,6 +284,7 @@ int manager_save(Manager *m) {
|
||||
if (isempty(m->state_file))
|
||||
return 0; /* Do not update state file when running in test mode. */
|
||||
|
||||
Link *link;
|
||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
continue;
|
||||
@ -336,20 +333,14 @@ int manager_save(Manager *m) {
|
||||
(links_offline > 0 ? LINK_ONLINE_STATE_PARTIAL : LINK_ONLINE_STATE_ONLINE) :
|
||||
(links_offline > 0 ? LINK_ONLINE_STATE_OFFLINE : _LINK_ONLINE_STATE_INVALID);
|
||||
|
||||
operstate_str = link_operstate_to_string(operstate);
|
||||
assert(operstate_str);
|
||||
operstate_str = ASSERT_PTR(link_operstate_to_string(operstate));
|
||||
carrier_state_str = ASSERT_PTR(link_carrier_state_to_string(carrier_state));
|
||||
address_state_str = ASSERT_PTR(link_address_state_to_string(address_state));
|
||||
ipv4_address_state_str = ASSERT_PTR(link_address_state_to_string(ipv4_address_state));
|
||||
ipv6_address_state_str = ASSERT_PTR(link_address_state_to_string(ipv6_address_state));
|
||||
|
||||
carrier_state_str = link_carrier_state_to_string(carrier_state);
|
||||
assert(carrier_state_str);
|
||||
|
||||
address_state_str = link_address_state_to_string(address_state);
|
||||
assert(address_state_str);
|
||||
|
||||
ipv4_address_state_str = link_address_state_to_string(ipv4_address_state);
|
||||
assert(ipv4_address_state_str);
|
||||
|
||||
ipv6_address_state_str = link_address_state_to_string(ipv6_address_state);
|
||||
assert(ipv6_address_state_str);
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
r = fopen_temporary(m->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
@ -386,6 +377,8 @@ int manager_save(Manager *m) {
|
||||
|
||||
temp_path = mfree(temp_path);
|
||||
|
||||
_cleanup_strv_free_ char **p = NULL;
|
||||
|
||||
if (m->operational_state != operstate) {
|
||||
m->operational_state = operstate;
|
||||
if (strv_extend(&p, "OperationalState") < 0)
|
||||
@ -568,9 +561,32 @@ static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, U
|
||||
}
|
||||
}
|
||||
|
||||
static int serialize_config_files(FILE *f, const char *prefix, const char *main_config, char * const *dropins) {
|
||||
assert(f);
|
||||
assert(prefix);
|
||||
assert(main_config);
|
||||
|
||||
fprintf(f, "%s_FILE=%s\n", prefix, main_config);
|
||||
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s_FILE_DROPINS=\"", prefix);
|
||||
STRV_FOREACH(d, dropins) {
|
||||
_cleanup_free_ char *escaped = NULL;
|
||||
|
||||
escaped = xescape(*d, ":");
|
||||
if (!escaped)
|
||||
return -ENOMEM;
|
||||
|
||||
fputs_with_separator(f, escaped, ":", &space);
|
||||
}
|
||||
fputs("\"\n", f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_save(Link *link) {
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state,
|
||||
*captive_portal;
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
@ -584,23 +600,12 @@ static int link_save(Link *link) {
|
||||
if (link->state == LINK_STATE_LINGER)
|
||||
return 0;
|
||||
|
||||
admin_state = link_state_to_string(link->state);
|
||||
assert(admin_state);
|
||||
|
||||
oper_state = link_operstate_to_string(link->operstate);
|
||||
assert(oper_state);
|
||||
|
||||
carrier_state = link_carrier_state_to_string(link->carrier_state);
|
||||
assert(carrier_state);
|
||||
|
||||
address_state = link_address_state_to_string(link->address_state);
|
||||
assert(address_state);
|
||||
|
||||
ipv4_address_state = link_address_state_to_string(link->ipv4_address_state);
|
||||
assert(ipv4_address_state);
|
||||
|
||||
ipv6_address_state = link_address_state_to_string(link->ipv6_address_state);
|
||||
assert(ipv6_address_state);
|
||||
admin_state = ASSERT_PTR(link_state_to_string(link->state));
|
||||
oper_state = ASSERT_PTR(link_operstate_to_string(link->operstate));
|
||||
carrier_state = ASSERT_PTR(link_carrier_state_to_string(link->carrier_state));
|
||||
address_state = ASSERT_PTR(link_address_state_to_string(link->address_state));
|
||||
ipv4_address_state = ASSERT_PTR(link_address_state_to_string(link->ipv4_address_state));
|
||||
ipv6_address_state = ASSERT_PTR(link_address_state_to_string(link->ipv6_address_state));
|
||||
|
||||
r = fopen_temporary(link->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
@ -619,7 +624,7 @@ static int link_save(Link *link) {
|
||||
admin_state, oper_state, carrier_state, address_state, ipv4_address_state, ipv6_address_state);
|
||||
|
||||
if (link->network) {
|
||||
const char *online_state;
|
||||
const char *online_state, *captive_portal;
|
||||
bool space = false;
|
||||
|
||||
online_state = link_online_state_to_string(link->online_state);
|
||||
@ -641,19 +646,15 @@ static int link_save(Link *link) {
|
||||
fprintf(f, "ACTIVATION_POLICY=%s\n",
|
||||
activation_policy_to_string(link->network->activation_policy));
|
||||
|
||||
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
||||
r = serialize_config_files(f, "NETWORK", link->network->filename, link->network->dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fputs("NETWORK_FILE_DROPINS=\"", f);
|
||||
STRV_FOREACH(d, link->network->dropins) {
|
||||
_cleanup_free_ char *escaped = NULL;
|
||||
|
||||
escaped = xescape(*d, ":");
|
||||
if (!escaped)
|
||||
return -ENOMEM;
|
||||
|
||||
fputs_with_separator(f, escaped, ":", &space);
|
||||
if (link->netdev) {
|
||||
r = serialize_config_files(f, "NETDEV", link->netdev->filename, link->netdev->dropins);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
fputs("\"\n", f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
@ -778,8 +779,9 @@ static int link_save(Link *link) {
|
||||
if (!set_isempty(nta_anchors)) {
|
||||
const char *n;
|
||||
|
||||
fputs("DNSSEC_NTA=", f);
|
||||
space = false;
|
||||
|
||||
fputs("DNSSEC_NTA=", f);
|
||||
SET_FOREACH(n, nta_anchors)
|
||||
fputs_with_separator(f, n, NULL, &space);
|
||||
fputc('\n', f);
|
||||
@ -794,9 +796,7 @@ static int link_save(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fprintf(f,
|
||||
"DHCP_LEASE=%s\n",
|
||||
link->lease_file);
|
||||
fprintf(f, "DHCP_LEASE=%s\n", link->lease_file);
|
||||
} else
|
||||
(void) unlink(link->lease_file);
|
||||
|
||||
|
@ -122,6 +122,12 @@ int sd_network_link_get_network_file(int ifindex, char **ret);
|
||||
/* Get paths to .network file dropins applied to link */
|
||||
int sd_network_link_get_network_file_dropins(int ifindex, char ***ret);
|
||||
|
||||
/* Get path to .netdev file associated with link */
|
||||
int sd_network_link_get_netdev_file(int ifindex, char **ret);
|
||||
|
||||
/* Get path to .netdev file dropins associated with link */
|
||||
int sd_network_link_get_netdev_file_dropins(int ifindex, char ***ret);
|
||||
|
||||
/* Get DNS entries for a given link. These are string representations of
|
||||
* IP addresses */
|
||||
int sd_network_link_get_dns(int ifindex, char ***ret);
|
||||
|
@ -1027,6 +1027,7 @@ DNS=127.0.0.1
|
||||
subprocess.check_call([NETWORKD_WAIT_ONLINE, '--interface', 'dummy0', '--timeout=10'])
|
||||
|
||||
out = subprocess.check_output(['networkctl', 'status', 'dummy0'])
|
||||
self.assertIn(b'50-test.netdev', out)
|
||||
self.assertIn(b'50-test.network.d/dns.conf', out)
|
||||
|
||||
for _ in range(50):
|
||||
|
@ -99,10 +99,18 @@ cmp "/usr/lib/systemd/network/$LINK_NAME" "/etc/systemd/network/$LINK_NAME"
|
||||
systemctl unmask systemd-networkd
|
||||
systemctl stop systemd-networkd
|
||||
(! networkctl cat @test2)
|
||||
(! networkctl cat @test2:netdev)
|
||||
|
||||
systemctl start systemd-networkd
|
||||
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:carrier --timeout 20
|
||||
|
||||
networkctl cat @test2:network | cmp - <(networkctl cat "$NETWORK_NAME")
|
||||
networkctl cat @test2:netdev | cmp - <(networkctl cat "$NETDEV_NAME")
|
||||
for c in "$NETWORK_NAME" "$NETDEV_NAME"; do
|
||||
assert_in "$(networkctl cat "$c" | head -n1)" "$(networkctl cat @test2:all)"
|
||||
done
|
||||
|
||||
(! networkctl edit @test2:all)
|
||||
|
||||
EDITOR='cp' script -ec 'networkctl edit @test2 --drop-in test2.conf' /dev/null
|
||||
cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test2.conf"
|
||||
@ -112,6 +120,9 @@ SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:c
|
||||
|
||||
ip_link="$(ip link show test2)"
|
||||
if systemctl --quiet is-active systemd-udevd; then
|
||||
networkctl cat @test2:link | cmp - <(networkctl cat "$LINK_NAME")
|
||||
assert_in "$(networkctl cat "$LINK_NAME" | head -n1)" "$(networkctl cat @test2:all)"
|
||||
|
||||
assert_in 'alias test_alias' "$ip_link"
|
||||
fi
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user