1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-21 02:50:18 +03:00

Merge pull request #21766 from yuwata/network-generator-name-policy

network-generator: support setting NamePolicy=
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-12-16 09:34:01 +01:00 committed by GitHub
commit 67cb0d4725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 256 additions and 90 deletions

View File

@ -929,10 +929,7 @@ manpages = [
''],
['systemd-modules-load.service', '8', ['systemd-modules-load'], 'HAVE_KMOD'],
['systemd-mount', '1', ['systemd-umount'], ''],
['systemd-network-generator.service',
'8',
['systemd-network-generator'],
'ENABLE_NETWORKD'],
['systemd-network-generator.service', '8', ['systemd-network-generator'], ''],
['systemd-networkd-wait-online.service',
'8',
['systemd-networkd-wait-online'],

View File

@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-network-generator.service" conditional='ENABLE_NETWORKD'>
<refentry id="systemd-network-generator.service">
<refentryinfo>
<title>systemd-network-generator.service</title>
@ -59,6 +59,7 @@
<varlistentry>
<term><varname>ifname=</varname></term>
<term><varname>net.ifname-policy=</varname></term>
<listitem>
<para>— translated into
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry> files.</para>
@ -88,6 +89,8 @@
<para>See
<citerefentry project='man-pages'><refentrytitle>dracut.kernel</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for option syntax and details.</para>
</refsect1>

View File

@ -224,6 +224,45 @@
appear, which affects older name derivation algorithms, too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>net.ifname-policy=<replaceable>policy1</replaceable>[,<replaceable>policy2</replaceable>,…][,<replaceable>MAC</replaceable>]</varname></term>
<listitem>
<para>Specifies naming policies applied when renaming network interfaces. Takes a list of
policies and an optional MAC address separated with comma. Each policy value must be one of
the policies understood by the <varname>NamePolicy=</varname> setting in .link files, e.g.
<literal>onboard</literal> or <literal>path</literal>. See
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more details. When the MAC address is specified, the policies are applied to the
interface which has the address. When no MAC address is specified, the policies are applied
to all interfaces. This kernel command line argument can be specified multiple times. This
argument is not directly read from <command>systemd-udevd</command>, but read and converted
to a .link file by <command>systemd-network-generator</command>. So, to make this argument
take effect, <filename>systemd-network-generator.service</filename> must be enabled and
started before starting <filename>systemd-udevd.service</filename>. See
<citerefentry><refentrytitle>systemd-network-generator.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for more details about the service.</para>
<para>Example:
<programlisting>net.ifname-policy=keep,kernel,path,slot,onboard,01:23:45:67:89:ab
net.ifname-policy=keep,kernel,path,slot,onboard,mac</programlisting>
This is mostly equivalent to creating the following .link files:
<programlisting># 91-name-policy-with-mac.link
[Match]
MACAddress=01:23:45:67:89:ab
[Link]
NamePolicy=keep kernel path slot onboard
AlternativeNamePolicy=path slot onboard</programlisting>
and
<programlisting># 92-name-policy-for-all.link
[Match]
OriginalName=*
[Link]
NamePolicy=keep kernel path slot onboard mac
AlternativeNamePolicy=path slot onboard mac</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
<!-- when adding entries here, consider also adding them in kernel-command-line.xml -->
</refsect1>

View File

@ -3467,22 +3467,22 @@ if conf.get('ENABLE_NETWORKD') == 1
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
endif
exe = executable(
'systemd-network-generator',
network_generator_sources,
include_directories : includes,
link_with : [networkd_link_with],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
exe = executable(
'systemd-network-generator',
network_generator_sources,
include_directories : includes,
link_with : [networkd_link_with],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
if want_tests != 'false'
test('test-network-generator-conversion',
test_network_generator_conversion_sh,
# https://github.com/mesonbuild/meson/issues/2681
args : exe.full_path())
endif
if want_tests != 'false'
test('test-network-generator-conversion',
test_network_generator_conversion_sh,
# https://github.com/mesonbuild/meson/issues/2681
args : exe.full_path())
endif
executable(

View File

@ -65,9 +65,10 @@ static int link_save(Link *link, const char *dest_dir) {
assert(link);
r = asprintf(&filename, "90-%s.link",
link->ifname);
if (r < 0)
filename = strjoin(!isempty(link->ifname) ? "90" :
!hw_addr_is_null(&link->mac) ? "91" : "92",
"-", link->filename, ".link");
if (!filename)
return log_oom();
r = generator_open_unit_file(dest_dir, "kernel command line", filename, &f);
@ -104,7 +105,7 @@ static int context_save(Context *context) {
r = k;
}
HASHMAP_FOREACH(link, context->links_by_name) {
HASHMAP_FOREACH(link, context->links_by_filename) {
k = link_save(link, p);
if (k < 0 && r >= 0)
r = k;

View File

@ -1,11 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "ether-addr-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
#include "netif-naming-scheme.h"
#include "network-generator.h"
#include "parse-util.h"
#include "proc-cmdline.h"
@ -26,6 +26,7 @@
# .link
ifname=<interface>:<MAC>
net.ifname-policy=policy1[,policy2,...][,<MAC>] # This is an original rule, not supported by other tools.
# .netdev
vlan=<vlanname>:<phydevice>
@ -264,36 +265,59 @@ static Link *link_free(Link *link) {
if (!link)
return NULL;
free(link->filename);
free(link->ifname);
strv_free(link->policies);
strv_free(link->alt_policies);
return mfree(link);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
static int link_new(Context *context, const char *name, struct ether_addr *mac, Link **ret) {
static int link_new(
Context *context,
const char *name,
const struct hw_addr_data *mac,
Link **ret) {
_cleanup_(link_freep) Link *link = NULL;
_cleanup_free_ char *ifname = NULL;
_cleanup_free_ char *ifname = NULL, *filename = NULL;
int r;
assert(context);
assert(mac);
if (!ifname_valid(name))
return -EINVAL;
if (name) {
if (!ifname_valid(name))
return -EINVAL;
ifname = strdup(name);
if (!ifname)
return -ENOMEM;
ifname = strdup(name);
if (!ifname)
return -ENOMEM;
filename = strdup(name);
if (!filename)
return -ENOMEM;
}
if (!filename) {
filename = strdup(hw_addr_is_null(mac) ? "default" :
HW_ADDR_TO_STR_FULL(mac, HW_ADDR_TO_STRING_NO_COLON));
if (!filename)
return -ENOMEM;
}
link = new(Link, 1);
if (!link)
return -ENOMEM;
*link = (Link) {
.filename = TAKE_PTR(filename),
.ifname = TAKE_PTR(ifname),
.mac = *mac,
};
r = hashmap_ensure_put(&context->links_by_name, &string_hash_ops, link->ifname, link);
r = hashmap_ensure_put(&context->links_by_filename, &string_hash_ops, link->filename, link);
if (r < 0)
return r;
@ -304,8 +328,10 @@ static int link_new(Context *context, const char *name, struct ether_addr *mac,
return 0;
}
Link *link_get(Context *context, const char *ifname) {
return hashmap_get(context->links_by_name, ifname);
Link *link_get(Context *context, const char *filename) {
assert(context);
assert(filename);
return hashmap_get(context->links_by_filename, filename);
}
static int network_set_dhcp_type(Context *context, const char *ifname, const char *dhcp_type) {
@ -896,7 +922,7 @@ static int parse_cmdline_bond(Context *context, const char *key, const char *val
}
static int parse_cmdline_ifname(Context *context, const char *key, const char *value) {
struct ether_addr mac;
struct hw_addr_data mac;
const char *name, *p;
int r;
@ -911,13 +937,72 @@ static int parse_cmdline_ifname(Context *context, const char *key, const char *v
name = strndupa_safe(value, p - value);
r = parse_ether_addr(p + 1, &mac);
r = parse_hw_addr(p + 1, &mac);
if (r < 0)
return r;
return link_new(context, name, &mac, NULL);
}
static int parse_cmdline_ifname_policy(Context *context, const char *key, const char *value) {
_cleanup_strv_free_ char **policies = NULL, **alt_policies = NULL;
struct hw_addr_data mac = HW_ADDR_NULL;
Link *link;
int r;
/* net.ifname-policy=policy1[,policy2,...][,<MAC>] */
if (proc_cmdline_value_missing(key, value))
return -EINVAL;
for (const char *q = value; ; ) {
_cleanup_free_ char *word = NULL;
NamePolicy p;
r = extract_first_word(&q, &word, ",", 0);
if (r == 0)
break;
if (r < 0)
return r;
p = name_policy_from_string(word);
if (p < 0) {
r = parse_hw_addr(word, &mac);
if (r < 0)
return r;
if (hw_addr_is_null(&mac))
return -EINVAL;
if (!isempty(q))
return -EINVAL;
break;
}
if (alternative_names_policy_from_string(word) >= 0) {
r = strv_extend(&alt_policies, word);
if (r < 0)
return r;
}
r = strv_consume(&policies, TAKE_PTR(word));
if (r < 0)
return r;
}
if (strv_isempty(policies))
return -EINVAL;
r = link_new(context, NULL, &mac, &link);
if (r < 0)
return r;
link->policies = TAKE_PTR(policies);
link->alt_policies = TAKE_PTR(alt_policies);
return 0;
}
int parse_cmdline_item(const char *key, const char *value, void *data) {
Context *context = data;
@ -940,6 +1025,8 @@ int parse_cmdline_item(const char *key, const char *value, void *data) {
return parse_cmdline_bond(context, key, value);
if (streq(key, "ifname"))
return parse_cmdline_ifname(context, key, value);
if (streq(key, "net.ifname-policy"))
return parse_cmdline_ifname_policy(context, key, value);
return 0;
}
@ -991,7 +1078,7 @@ void context_clear(Context *context) {
hashmap_free_with_destructor(context->networks_by_name, network_free);
hashmap_free_with_destructor(context->netdevs_by_name, netdev_free);
hashmap_free_with_destructor(context->links_by_name, link_free);
hashmap_free_with_destructor(context->links_by_filename, link_free);
}
static int address_dump(Address *address, FILE *f) {
@ -1117,13 +1204,27 @@ void link_dump(Link *link, FILE *f) {
fputs("[Match]\n", f);
if (!ether_addr_is_null(&link->mac))
fprintf(f, "MACAddress=%s\n", ETHER_ADDR_TO_STR(&link->mac));
if (!hw_addr_is_null(&link->mac))
fprintf(f, "MACAddress=%s\n", HW_ADDR_TO_STR(&link->mac));
else
fputs("OriginalName=*\n", f);
fprintf(f,
"\n[Link]\n"
"Name=%s\n",
link->ifname);
fputs("\n[Link]\n", f);
if (!isempty(link->ifname))
fprintf(f, "Name=%s\n", link->ifname);
if (!strv_isempty(link->policies)) {
fputs("NamePolicy=", f);
fputstrv(f, link->policies, " ", NULL);
fputc('\n', f);
}
if (!strv_isempty(link->alt_policies)) {
fputs("AlternativeNamesPolicy=", f);
fputstrv(f, link->alt_policies, " ", NULL);
fputc('\n', f);
}
}
int network_format(Network *network, char **ret) {

View File

@ -1,9 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <net/ethernet.h>
#include <stdio.h>
#include "ether-addr-util.h"
#include "hashmap.h"
#include "in-addr-util.h"
#include "list.h"
@ -81,15 +81,21 @@ struct NetDev {
};
struct Link {
char *filename;
/* [Match] */
struct hw_addr_data mac;
/* [Link] */
char *ifname;
struct ether_addr mac;
char **policies;
char **alt_policies;
};
typedef struct Context {
Hashmap *networks_by_name;
Hashmap *netdevs_by_name;
Hashmap *links_by_name;
Hashmap *links_by_filename;
} Context;
int parse_cmdline_item(const char *key, const char *value, void *data);
@ -104,6 +110,6 @@ NetDev *netdev_get(Context *context, const char *ifname);
void netdev_dump(NetDev *netdev, FILE *f);
int netdev_format(NetDev *netdev, char **ret);
Link *link_get(Context *context, const char *ifname);
Link *link_get(Context *context, const char *filename);
void link_dump(Link *link, FILE *f);
int link_format(Link *link, char **ret);

View File

@ -49,14 +49,14 @@ static void test_netdev_one(const char *ifname, const char *key, const char *val
assert_se(streq(output, expected));
}
static void test_link_one(const char *ifname, const char *key, const char *value, const char *expected) {
static void test_link_one(const char *filename, const char *key, const char *value, const char *expected) {
_cleanup_(context_clear) Context context = {};
_cleanup_free_ char *output = NULL;
Link *link;
printf("# %s=%s\n", key, value);
assert_se(parse_cmdline_item(key, value, &context) >= 0);
assert_se(link = link_get(&context, ifname));
assert_se(link = link_get(&context, filename));
assert_se(link_format(link, &output) >= 0);
puts(output);
assert_se(streq(output, expected));
@ -334,6 +334,22 @@ int main(int argc, char *argv[]) {
"Name=hogehoge\n"
);
test_link_one("001122334455", "net.ifname-policy", "keep,kernel,database,onboard,slot,path,mac,00:11:22:33:44:55",
"[Match]\n"
"MACAddress=00:11:22:33:44:55\n"
"\n[Link]\n"
"NamePolicy=keep kernel database onboard slot path mac\n"
"AlternativeNamesPolicy=database onboard slot path mac\n"
);
test_link_one("default", "net.ifname-policy", "keep,kernel,database,onboard,slot,path,mac",
"[Match]\n"
"OriginalName=*\n"
"\n[Link]\n"
"NamePolicy=keep kernel database onboard slot path mac\n"
"AlternativeNamesPolicy=database onboard slot path mac\n"
);
test_network_two("eth0",
"ip", "192.168.0.10:192.168.0.2:192.168.0.1:255.255.255.0:hogehoge:eth0:on:10.10.10.10:10.10.10.11",
"rd.route", "10.1.2.3/16:10.0.2.3",

View File

@ -4,6 +4,7 @@
#include "netif-naming-scheme.h"
#include "proc-cmdline.h"
#include "string-util.h"
#include "string-table.h"
#ifdef _DEFAULT_NET_NAMING_SCHEME_TEST
/* The primary purpose of this check is to verify that _DEFAULT_NET_NAMING_SCHEME_TEST
@ -80,3 +81,25 @@ const NamingScheme* naming_scheme(void) {
return cache;
}
static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
[NAMEPOLICY_KERNEL] = "kernel",
[NAMEPOLICY_KEEP] = "keep",
[NAMEPOLICY_DATABASE] = "database",
[NAMEPOLICY_ONBOARD] = "onboard",
[NAMEPOLICY_SLOT] = "slot",
[NAMEPOLICY_PATH] = "path",
[NAMEPOLICY_MAC] = "mac",
};
DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
[NAMEPOLICY_DATABASE] = "database",
[NAMEPOLICY_ONBOARD] = "onboard",
[NAMEPOLICY_SLOT] = "slot",
[NAMEPOLICY_PATH] = "path",
[NAMEPOLICY_MAC] = "mac",
};
DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);

View File

@ -64,3 +64,21 @@ const NamingScheme* naming_scheme(void);
static inline bool naming_scheme_has(NamingSchemeFlags flags) {
return FLAGS_SET(naming_scheme()->flags, flags);
}
typedef enum NamePolicy {
NAMEPOLICY_KERNEL,
NAMEPOLICY_KEEP,
NAMEPOLICY_DATABASE,
NAMEPOLICY_ONBOARD,
NAMEPOLICY_SLOT,
NAMEPOLICY_PATH,
NAMEPOLICY_MAC,
_NAMEPOLICY_MAX,
_NAMEPOLICY_INVALID = -EINVAL,
} NamePolicy;
const char *name_policy_to_string(NamePolicy p) _const_;
NamePolicy name_policy_from_string(const char *p) _pure_;
const char *alternative_names_policy_to_string(NamePolicy p) _const_;
NamePolicy alternative_names_policy_from_string(const char *p) _pure_;

View File

@ -22,7 +22,6 @@
#include "log-link.h"
#include "memory-util.h"
#include "net-condition.h"
#include "netif-naming-scheme.h"
#include "netif-util.h"
#include "netlink-util.h"
#include "parse-util.h"
@ -1032,30 +1031,10 @@ DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
MAC_ADDRESS_POLICY_NONE,
"Failed to parse MAC address policy");
static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
[NAMEPOLICY_KERNEL] = "kernel",
[NAMEPOLICY_KEEP] = "keep",
[NAMEPOLICY_DATABASE] = "database",
[NAMEPOLICY_ONBOARD] = "onboard",
[NAMEPOLICY_SLOT] = "slot",
[NAMEPOLICY_PATH] = "path",
[NAMEPOLICY_MAC] = "mac",
};
DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
_NAMEPOLICY_INVALID,
"Failed to parse interface name policy");
static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
[NAMEPOLICY_DATABASE] = "database",
[NAMEPOLICY_ONBOARD] = "onboard",
[NAMEPOLICY_SLOT] = "slot",
[NAMEPOLICY_PATH] = "path",
[NAMEPOLICY_MAC] = "mac",
};
DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
_NAMEPOLICY_INVALID,
"Failed to parse alternative names policy");

View File

@ -9,6 +9,7 @@
#include "ethtool-util.h"
#include "list.h"
#include "net-condition.h"
#include "netif-naming-scheme.h"
typedef struct LinkConfigContext LinkConfigContext;
typedef struct LinkConfig LinkConfig;
@ -21,18 +22,6 @@ typedef enum MACAddressPolicy {
_MAC_ADDRESS_POLICY_INVALID = -EINVAL,
} MACAddressPolicy;
typedef enum NamePolicy {
NAMEPOLICY_KERNEL,
NAMEPOLICY_KEEP,
NAMEPOLICY_DATABASE,
NAMEPOLICY_ONBOARD,
NAMEPOLICY_SLOT,
NAMEPOLICY_PATH,
NAMEPOLICY_MAC,
_NAMEPOLICY_MAX,
_NAMEPOLICY_INVALID = -EINVAL,
} NamePolicy;
typedef struct Link {
int ifindex;
const char *ifname;
@ -105,12 +94,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
int link_get_config(LinkConfigContext *ctx, Link *link);
int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link);
const char *name_policy_to_string(NamePolicy p) _const_;
NamePolicy name_policy_from_string(const char *p) _pure_;
const char *alternative_names_policy_to_string(NamePolicy p) _const_;
NamePolicy alternative_names_policy_from_string(const char *p) _pure_;
const char *mac_address_policy_to_string(MACAddressPolicy p) _const_;
MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_;

View File

@ -217,7 +217,7 @@ in_units = [
'dbus-org.freedesktop.machine1.service'],
['systemd-modules-load.service', 'HAVE_KMOD',
'sysinit.target.wants/'],
['systemd-network-generator.service', 'ENABLE_NETWORKD'],
['systemd-network-generator.service', ''],
['systemd-networkd.service', 'ENABLE_NETWORKD'],
['systemd-networkd-wait-online.service', 'ENABLE_NETWORKD'],
['systemd-nspawn@.service', ''],

View File

@ -11,7 +11,7 @@
Description=Generate network units from Kernel command line
Documentation=man:systemd-network-generator.service(8)
DefaultDependencies=no
Before=network-pre.target
Before=network-pre.target systemd-udevd.service
Wants=network-pre.target
[Service]