mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-28 17:57:25 +03:00
Merge pull request #12888 from yuwata/network-udev-property-support
network,udev: add Property= setting in [Match] section
This commit is contained in:
commit
0330cb57ab
@ -103,7 +103,7 @@
|
||||
<term><varname>Driver=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of shell-style globs matching the driver currently bound to the
|
||||
device, as exposed by the udev property <varname>DRIVER</varname> of its parent device, or if that
|
||||
device, as exposed by the udev property <varname>ID_NET_DRIVER</varname> of its parent device, or if that
|
||||
is not set, the driver as exposed by <command>ethtool -i</command> of the device itself.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -115,6 +115,21 @@
|
||||
property <varname>DEVTYPE</varname>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Property=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of udev property name with its value after a equal
|
||||
(<literal>=</literal>). If multiple properties are specified, the test results are ANDed.
|
||||
If the list is prefixed with a "!", the test is inverted. If a value contains white
|
||||
spaces, then please quote whole key and value pair. If a value contains quotation, then
|
||||
please escape the quotation with <literal>\</literal>.</para>
|
||||
|
||||
<para>Example: if a .link file has the following:
|
||||
<programlisting>Property=ID_MODEL_ID=9999 "ID_VENDOR_FROM_DATABASE=vendor name" "KEY=with \"quotation\""</programlisting>
|
||||
then, the .link file matches only when an interface has all the above three properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Host=</varname></term>
|
||||
<listitem>
|
||||
|
@ -113,7 +113,7 @@
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of shell-style globs
|
||||
matching the driver currently bound to the device, as
|
||||
exposed by the udev property <literal>DRIVER</literal>
|
||||
exposed by the udev property <literal>ID_NET_DRIVER</literal>
|
||||
of its parent device, or if that is not set the driver
|
||||
as exposed by <literal>ethtool -i</literal> of the
|
||||
device itself. If the list is prefixed with a "!", the
|
||||
@ -138,6 +138,21 @@
|
||||
with a "!", the test is inverted.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Property=</varname></term>
|
||||
<listitem>
|
||||
<para>A whitespace-separated list of udev property name with its value after a equal
|
||||
(<literal>=</literal>). If multiple properties are specified, the test results are ANDed.
|
||||
If the list is prefixed with a "!", the test is inverted. If a value contains white
|
||||
spaces, then please quote whole key and value pair. If a value contains quotation, then
|
||||
please escape the quotation with <literal>\</literal>.</para>
|
||||
|
||||
<para>Example: if a .network file has the following:
|
||||
<programlisting>Property=ID_MODEL_ID=9999 "ID_VENDOR_FROM_DATABASE=vendor name" "KEY=with \"quotation\""</programlisting>
|
||||
then, the .network file matches only when an interface has all the above three properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Host=</varname></term>
|
||||
<listitem>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "conf-parser.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "env-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "log.h"
|
||||
@ -73,26 +74,66 @@ int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool net_condition_test_strv(char * const *raw_patterns,
|
||||
const char *string) {
|
||||
if (strv_isempty(raw_patterns))
|
||||
static bool net_condition_test_strv(char * const *patterns, const char *string) {
|
||||
char * const *p;
|
||||
bool match = false, has_positive_rule = false;
|
||||
|
||||
if (strv_isempty(patterns))
|
||||
return true;
|
||||
|
||||
/* If the patterns begin with "!", edit it out and negate the test. */
|
||||
if (raw_patterns[0][0] == '!') {
|
||||
char **patterns;
|
||||
size_t i, length;
|
||||
STRV_FOREACH(p, patterns) {
|
||||
const char *q = *p;
|
||||
bool invert;
|
||||
|
||||
length = strv_length(raw_patterns) + 1; /* Include the NULL. */
|
||||
patterns = newa(char*, length);
|
||||
patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */
|
||||
for (i = 1; i < length; i++)
|
||||
patterns[i] = raw_patterns[i];
|
||||
invert = *q == '!';
|
||||
q += invert;
|
||||
|
||||
return !string || !strv_fnmatch(patterns, string, 0);
|
||||
if (!invert)
|
||||
has_positive_rule = true;
|
||||
|
||||
if (string && fnmatch(q, string, 0) == 0) {
|
||||
if (invert)
|
||||
return false;
|
||||
else
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
return string && strv_fnmatch(raw_patterns, string, 0);
|
||||
return has_positive_rule ? match : true;
|
||||
}
|
||||
|
||||
static int net_condition_test_property(char * const *match_property, sd_device *device) {
|
||||
char * const *p;
|
||||
|
||||
if (strv_isempty(match_property))
|
||||
return true;
|
||||
|
||||
STRV_FOREACH(p, match_property) {
|
||||
_cleanup_free_ char *key = NULL;
|
||||
const char *val, *dev_val;
|
||||
bool invert, v;
|
||||
|
||||
invert = **p == '!';
|
||||
|
||||
val = strchr(*p + invert, '=');
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
key = strndup(*p + invert, val - *p - invert);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
val++;
|
||||
|
||||
v = device &&
|
||||
sd_device_get_property_value(device, key, &dev_val) >= 0 &&
|
||||
fnmatch(val, dev_val, 0) == 0;
|
||||
|
||||
if (invert ? v : !v)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool net_match_config(Set *match_mac,
|
||||
@ -100,12 +141,25 @@ bool net_match_config(Set *match_mac,
|
||||
char * const *match_drivers,
|
||||
char * const *match_types,
|
||||
char * const *match_names,
|
||||
char * const *match_property,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name) {
|
||||
|
||||
const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
|
||||
|
||||
if (device) {
|
||||
(void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
|
||||
(void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
|
||||
(void) sd_device_get_devtype(device, &dev_type);
|
||||
|
||||
if (!dev_name)
|
||||
(void) sd_device_get_sysname(device, &dev_name);
|
||||
if (!dev_mac &&
|
||||
sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
|
||||
dev_mac = ether_aton(mac_str);
|
||||
}
|
||||
|
||||
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
|
||||
return false;
|
||||
|
||||
@ -121,6 +175,9 @@ bool net_match_config(Set *match_mac,
|
||||
if (!net_condition_test_strv(match_names, dev_name))
|
||||
return false;
|
||||
|
||||
if (!net_condition_test_property(match_property, device))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -164,7 +221,7 @@ int config_parse_net_condition(const char *unit,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifnames(
|
||||
int config_parse_match_strv(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@ -176,7 +233,9 @@ int config_parse_ifnames(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
@ -184,30 +243,154 @@ int config_parse_ifnames(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!ifname_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = strv_push(sv, word);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
word = NULL;
|
||||
if (isempty(rvalue)) {
|
||||
*sv = strv_free(*sv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_match_ifnames(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Failed to parse interface name list: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ifname_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Interface name is not valid or too long, ignoring assignment: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_match_property(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!env_assignment_is_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid property or value, ignoring assignment: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_ifalias(const char *unit,
|
||||
|
@ -19,16 +19,17 @@ bool net_match_config(Set *match_mac,
|
||||
char * const *match_driver,
|
||||
char * const *match_type,
|
||||
char * const *match_name,
|
||||
char * const *match_property,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_strv);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_property);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
|
||||
|
||||
|
@ -22,10 +22,11 @@ struct ConfigPerfItem;
|
||||
%includes
|
||||
%%
|
||||
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac)
|
||||
Match.Path, config_parse_strv, 0, offsetof(Network, match_path)
|
||||
Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver)
|
||||
Match.Type, config_parse_strv, 0, offsetof(Network, match_type)
|
||||
Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
|
||||
Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path)
|
||||
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver)
|
||||
Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type)
|
||||
Match.Name, config_parse_match_ifnames, 0, offsetof(Network, match_name)
|
||||
Match.Property, config_parse_match_property, 0, offsetof(Network, match_property)
|
||||
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
|
||||
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions)
|
||||
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions)
|
||||
|
@ -157,7 +157,8 @@ int network_verify(Network *network) {
|
||||
|
||||
if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
|
||||
strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
|
||||
strv_isempty(network->match_name) && !network->conditions)
|
||||
strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
|
||||
!network->conditions)
|
||||
log_warning("%s: No valid settings found in the [Match] section. "
|
||||
"The file will match all interfaces. "
|
||||
"If that is intended, please add Name=* in the [Match] section.",
|
||||
@ -507,6 +508,7 @@ static Network *network_free(Network *network) {
|
||||
strv_free(network->match_driver);
|
||||
strv_free(network->match_type);
|
||||
strv_free(network->match_name);
|
||||
strv_free(network->match_property);
|
||||
condition_free_list(network->conditions);
|
||||
|
||||
free(network->description);
|
||||
@ -607,26 +609,16 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
|
||||
int network_get(Manager *manager, sd_device *device,
|
||||
const char *ifname, const struct ether_addr *address,
|
||||
Network **ret) {
|
||||
const char *path = NULL, *driver = NULL, *devtype = NULL;
|
||||
Network *network;
|
||||
Iterator i;
|
||||
|
||||
assert(manager);
|
||||
assert(ret);
|
||||
|
||||
if (device) {
|
||||
(void) sd_device_get_property_value(device, "ID_PATH", &path);
|
||||
|
||||
(void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
|
||||
|
||||
(void) sd_device_get_devtype(device, &devtype);
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
|
||||
if (net_match_config(network->match_mac, network->match_path,
|
||||
network->match_driver, network->match_type,
|
||||
network->match_name,
|
||||
address, path, driver, devtype, ifname)) {
|
||||
if (net_match_config(network->match_mac, network->match_path, network->match_driver,
|
||||
network->match_type, network->match_name, network->match_property,
|
||||
device, address, ifname)) {
|
||||
if (network->match_name && device) {
|
||||
const char *attr;
|
||||
uint8_t name_assign_type = NET_NAME_UNKNOWN;
|
||||
|
@ -104,6 +104,7 @@ struct Network {
|
||||
char **match_driver;
|
||||
char **match_type;
|
||||
char **match_name;
|
||||
char **match_property;
|
||||
LIST_HEAD(Condition, conditions);
|
||||
|
||||
char *description;
|
||||
|
@ -174,7 +174,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
|
||||
assert_se(network = new0(Network, 1));
|
||||
network->n_ref = 1;
|
||||
assert_se(network->filename = strdup("hogehoge.network"));
|
||||
assert_se(config_parse_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
|
||||
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
|
||||
assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
|
||||
assert_se(network->n_static_addresses == 1);
|
||||
assert_se(network_verify(network) >= 0);
|
||||
@ -215,6 +215,27 @@ static void test_config_parse_address(void) {
|
||||
test_config_parse_address_one("::1/-1", AF_INET6, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static void test_config_parse_match_ifnames(void) {
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
|
||||
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0);
|
||||
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "!baz", &names, NULL) == 0);
|
||||
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "aaa bbb ccc", &names, NULL) == 0);
|
||||
|
||||
strv_equal(names, STRV_MAKE("!hoge", "!hogehoge", "!foo", "!baz", "aaa", "bbb", "ccc"));
|
||||
}
|
||||
|
||||
static void test_config_parse_match_strv(void) {
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
|
||||
assert_se(config_parse_match_strv("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0);
|
||||
assert_se(config_parse_match_strv("network", "filename", 1, "section", 1, "Name", 0, "!baz", &names, NULL) == 0);
|
||||
assert_se(config_parse_match_strv("network", "filename", 1, "section", 1, "Name", 0,
|
||||
"KEY=val \"KEY2=val with space\" \"KEY3=val with \\\"quotation\\\"\"", &names, NULL) == 0);
|
||||
|
||||
strv_equal(names, STRV_MAKE("!hoge", "!hogehoge", "!foo", "!baz", "KEY=val", "KEY2=val with space", "KEY3=val with \"quotation\""));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
@ -223,6 +244,8 @@ int main(int argc, char **argv) {
|
||||
test_config_parse_duid_rawdata();
|
||||
test_config_parse_hwaddr();
|
||||
test_config_parse_address();
|
||||
test_config_parse_match_ifnames();
|
||||
test_config_parse_match_strv();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ struct ConfigPerfItem;
|
||||
%includes
|
||||
%%
|
||||
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac)
|
||||
Match.OriginalName, config_parse_ifnames, 0, offsetof(link_config, match_name)
|
||||
Match.Path, config_parse_strv, 0, offsetof(link_config, match_path)
|
||||
Match.Driver, config_parse_strv, 0, offsetof(link_config, match_driver)
|
||||
Match.Type, config_parse_strv, 0, offsetof(link_config, match_type)
|
||||
Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match_name)
|
||||
Match.Path, config_parse_match_strv, 0, offsetof(link_config, match_path)
|
||||
Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match_driver)
|
||||
Match.Type, config_parse_match_strv, 0, offsetof(link_config, match_type)
|
||||
Match.Property, config_parse_match_property, 0, offsetof(link_config, match_property)
|
||||
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions)
|
||||
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions)
|
||||
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions)
|
||||
|
@ -51,6 +51,7 @@ static void link_config_free(link_config *link) {
|
||||
strv_free(link->match_driver);
|
||||
strv_free(link->match_type);
|
||||
strv_free(link->match_name);
|
||||
strv_free(link->match_property);
|
||||
condition_free_list(link->conditions);
|
||||
|
||||
free(link->description);
|
||||
@ -161,7 +162,7 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
|
||||
|
||||
if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
|
||||
strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
|
||||
strv_isempty(link->match_name) && !link->conditions)
|
||||
strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions)
|
||||
log_warning("%s: No valid settings found in the [Match] section. "
|
||||
"The file will match all interfaces. "
|
||||
"If that is intended, please add OriginalName=* in the [Match] section.",
|
||||
@ -240,42 +241,29 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
|
||||
assert(ret);
|
||||
|
||||
LIST_FOREACH(links, link, ctx->links) {
|
||||
const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
|
||||
|
||||
(void) sd_device_get_sysattr_value(device, "address", &address);
|
||||
(void) sd_device_get_property_value(device, "ID_PATH", &id_path);
|
||||
(void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
|
||||
(void) sd_device_get_devtype(device, &devtype);
|
||||
(void) sd_device_get_sysname(device, &sysname);
|
||||
|
||||
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
|
||||
link->match_type, link->match_name,
|
||||
address ? ether_aton(address) : NULL,
|
||||
id_path,
|
||||
id_net_driver,
|
||||
devtype,
|
||||
sysname)) {
|
||||
link->match_type, link->match_name, link->match_property,
|
||||
device, NULL, NULL)) {
|
||||
if (link->match_name) {
|
||||
unsigned name_assign_type = NET_NAME_UNKNOWN;
|
||||
|
||||
(void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
|
||||
|
||||
if (name_assign_type == NET_NAME_ENUM && !strv_contains(link->match_name, "*")) {
|
||||
log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
|
||||
link->filename, sysname);
|
||||
log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
|
||||
link->filename);
|
||||
*ret = link;
|
||||
|
||||
return 0;
|
||||
} else if (name_assign_type == NET_NAME_RENAMED) {
|
||||
log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
|
||||
link->filename, sysname);
|
||||
log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
|
||||
link->filename);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Config file %s applies to device %s",
|
||||
link->filename, sysname);
|
||||
log_device_debug(device, "Config file %s is applied", link->filename);
|
||||
|
||||
*ret = link;
|
||||
return 0;
|
||||
|
@ -40,6 +40,7 @@ struct link_config {
|
||||
char **match_driver;
|
||||
char **match_type;
|
||||
char **match_name;
|
||||
char **match_property;
|
||||
LIST_HEAD(Condition, conditions);
|
||||
|
||||
char *description;
|
||||
|
@ -4,6 +4,7 @@ OriginalName=
|
||||
Path=
|
||||
Driver=
|
||||
Type=
|
||||
Property=
|
||||
Host=
|
||||
Virtualization=
|
||||
KernelCommandLine=
|
||||
|
@ -20,6 +20,7 @@ Driver=
|
||||
Architecture=
|
||||
Path=
|
||||
Name=
|
||||
Property=
|
||||
Virtualization=
|
||||
KernelCommandLine=
|
||||
Host=
|
||||
|
@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=dummy98
|
||||
Property=INTERFACE=hoge
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=false
|
7
test/test-network/conf/14-match-udev-property.network
Normal file
7
test/test-network/conf/14-match-udev-property.network
Normal file
@ -0,0 +1,7 @@
|
||||
[Match]
|
||||
Name=dummy98
|
||||
Property=INTERFACE=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=false
|
||||
Address=10.1.2.3/16
|
@ -463,6 +463,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
||||
'11-dummy.netdev',
|
||||
'11-dummy.network',
|
||||
'12-dummy.netdev',
|
||||
'13-not-match-udev-property.network',
|
||||
'14-match-udev-property.network',
|
||||
'15-name-conflict-test.netdev',
|
||||
'21-macvlan.netdev',
|
||||
'21-macvtap.netdev',
|
||||
@ -578,6 +580,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
||||
print(output)
|
||||
self.assertRegex(output, '00:50:56:c0:00:28')
|
||||
|
||||
def test_match_udev_property(self):
|
||||
copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
|
||||
start_networkd()
|
||||
wait_online(['dummy98:routable'])
|
||||
|
||||
output = check_output('networkctl status dummy98')
|
||||
print(output)
|
||||
self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
|
||||
|
||||
def test_wait_online_any(self):
|
||||
copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
|
||||
start_networkd()
|
||||
|
Loading…
x
Reference in New Issue
Block a user