Merge pull request #8902 from yuwata/link-multiple-mac

network,link: make MACAddress= in [Match] section can take multiple MAC addresses
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2018-05-09 08:35:26 +02:00
committed by GitHub
14 changed files with 207 additions and 59 deletions
+6 -1
View File
@@ -88,7 +88,12 @@
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
<para>The hardware address.</para>
<para>A whitespace-separated list of hardware addresses. Use full colon-, hyphen- or dot-delimited hexadecimal. See the example below.
This option may appear more than once, in which case the lists are merged. If the empty string is assigned to this option, the list
of hardware addresses defined prior to this is reset.</para>
<para>Example:
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
+6 -2
View File
@@ -103,8 +103,12 @@
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
<para>The hardware address of the interface (use full colon-delimited hexadecimal, e.g.,
01:23:45:67:89:ab).</para>
<para>A whitespace-separated list of hardware addresses. Use full colon-, hyphen- or dot-delimited hexadecimal. See the example below.
This option may appear more than one, in which case the lists are merged. If the empty string is assigned to this option, the list
of hardware addresses defined prior to this is reset.</para>
<para>Example:
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
+25 -17
View File
@@ -33,19 +33,23 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
int ether_addr_compare(const void *a, const void *b) {
assert(a);
assert(b);
return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
a->ether_addr_octet[5] == b->ether_addr_octet[5];
return memcmp(a, b, ETH_ALEN);
}
int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) {
static void ether_addr_hash_func(const void *p, struct siphash *state) {
siphash24_compress(p, sizeof(struct ether_addr), state);
}
const struct hash_ops ether_addr_hash_ops = {
.hash = ether_addr_hash_func,
.compare = ether_addr_compare
};
int ether_addr_from_string(const char *s, struct ether_addr *ret) {
size_t pos = 0, n, field;
char sep = '\0';
const char *hex = HEXDIGITS, *hexoff;
@@ -84,31 +88,35 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
sep = s[strspn(s, hex)];
if (sep == '\n')
return -EINVAL;
if (!strchr(":.-", sep))
return -EINVAL;
if (sep == '.') {
uint16_t shorts[3] = { 0 };
parse_fields(shorts);
if (s[pos] != '\0')
return -EINVAL;
for (n = 0; n < ELEMENTSOF(shorts); n++) {
ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
}
} else {
struct ether_addr out = { .ether_addr_octet = { 0 } };
} else if (IN_SET(sep, ':', '-')) {
struct ether_addr out = ETHER_ADDR_NULL;
parse_fields(out.ether_addr_octet);
if (s[pos] != '\0')
return -EINVAL;
for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
ret->ether_addr_octet[n] = out.ether_addr_octet[n];
}
if (offset)
*offset = pos;
} else
return -EINVAL;
return 0;
}
+9 -2
View File
@@ -10,13 +10,18 @@
#include <net/ethernet.h>
#include <stdbool.h>
#include "hash-funcs.h"
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
#define ETHER_ADDR_TO_STRING_MAX (3*6)
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);
int ether_addr_compare(const void *a, const void *b);
static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
return ether_addr_compare(a, b) == 0;
}
#define ETHER_ADDR_NULL ((const struct ether_addr){})
@@ -24,4 +29,6 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) {
return ether_addr_equal(addr, &ETHER_ADDR_NULL);
}
int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset);
int ether_addr_from_string(const char *s, struct ether_addr *ret);
extern const struct hash_ops ether_addr_hash_ops;
+81 -13
View File
@@ -97,7 +97,7 @@ static bool net_condition_test_strv(char * const *raw_patterns,
return string && strv_fnmatch(raw_patterns, string, 0);
}
bool net_match_config(const struct ether_addr *match_mac,
bool net_match_config(Set *match_mac,
char * const *match_paths,
char * const *match_drivers,
char * const *match_types,
@@ -129,7 +129,7 @@ bool net_match_config(const struct ether_addr *match_mac,
if (match_arch && condition_test(match_arch) <= 0)
return false;
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
if (match_mac && dev_mac && !set_contains(match_mac, dev_mac))
return false;
if (!net_condition_test_strv(match_paths, dev_path))
@@ -281,10 +281,9 @@ int config_parse_hwaddr(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ struct ether_addr *n = NULL;
struct ether_addr **hwaddr = data;
struct ether_addr *n;
const char *start;
size_t offset;
int r;
assert(filename);
@@ -296,17 +295,86 @@ int config_parse_hwaddr(const char *unit,
if (!n)
return log_oom();
start = rvalue + strspn(rvalue, WHITESPACE);
r = ether_addr_from_string(start, n, &offset);
if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
r = ether_addr_from_string(rvalue, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0;
}
free(*hwaddr);
*hwaddr = n;
*hwaddr = TAKE_PTR(n);
return 0;
}
int config_parse_hwaddrs(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) {
_cleanup_set_free_free_ Set *s = NULL;
const char *p = rvalue;
Set **hwaddrs = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
*hwaddrs = set_free_free(*hwaddrs);
return 0;
}
s = set_new(&ether_addr_hash_ops);
if (!s)
return log_oom();
for (;;) {
_cleanup_free_ char *word = NULL;
_cleanup_free_ struct ether_addr *n = NULL;
r = extract_first_word(&p, &word, NULL, 0);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
n = new(struct ether_addr, 1);
if (!n)
return log_oom();
r = ether_addr_from_string(word, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
continue;
}
r = set_put(s, n);
if (r < 0)
return log_oom();
if (r > 0)
n = NULL; /* avoid cleanup */
}
r = set_ensure_allocated(hwaddrs, &ether_addr_hash_ops);
if (r < 0)
return log_oom();
r = set_move(*hwaddrs, s);
if (r < 0)
return log_oom();
return 0;
}
+6 -1
View File
@@ -12,12 +12,13 @@
#include "sd-dhcp-lease.h"
#include "condition.h"
#include "set.h"
#include "udev.h"
#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
bool net_match_config(const struct ether_addr *match_mac,
bool net_match_config(Set *match_mac,
char * const *match_path,
char * const *match_driver,
char * const *match_type,
@@ -42,6 +43,10 @@ int config_parse_hwaddr(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);
int config_parse_hwaddrs(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);
int config_parse_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);
+10 -8
View File
@@ -6,6 +6,7 @@
***/
#include "alloc-util.h"
#include "ether-addr-util.h"
#include "networkd-manager.h"
#include "string-util.h"
#include "strv.h"
@@ -19,23 +20,24 @@ static int property_get_ether_addrs(
void *userdata,
sd_bus_error *error) {
Network *n = userdata;
const char *ether = NULL;
char buf[ETHER_ADDR_TO_STRING_MAX];
const struct ether_addr *p;
Iterator i;
Set *s;
int r;
assert(bus);
assert(reply);
assert(n);
assert(userdata);
if (n->match_mac)
ether = ether_ntoa(n->match_mac);
s = *(Set **) userdata;
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
if (ether) {
r = sd_bus_message_append(reply, "s", strempty(ether));
SET_FOREACH(p, s, i) {
r = sd_bus_message_append(reply, "s", ether_addr_to_string(p, buf));
if (r < 0)
return r;
}
@@ -48,7 +50,7 @@ const sd_bus_vtable network_vtable[] = {
SD_BUS_PROPERTY("Description", "s", NULL, offsetof(Network, description), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Network, filename), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match_mac), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match_driver), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match_type), SD_BUS_VTABLE_PROPERTY_CONST),
+2 -2
View File
@@ -4,9 +4,9 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#endif
#include <stddef.h>
#include "conf-parser.h"
#include "network-internal.h"
#include "networkd-conf.h"
#include "networkd-network.h"
#include "network-internal.h"
#include "vlan-util.h"
%}
struct ConfigPerfItem;
@@ -20,7 +20,7 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
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)
+1 -1
View File
@@ -353,7 +353,7 @@ void network_free(Network *network) {
free(network->filename);
free(network->match_mac);
set_free_free(network->match_mac);
strv_free(network->match_path);
strv_free(network->match_driver);
strv_free(network->match_type);
+1 -1
View File
@@ -103,7 +103,7 @@ struct Network {
char *filename;
char *name;
struct ether_addr *match_mac;
Set *match_mac;
char **match_path;
char **match_driver;
char **match_type;
+54 -6
View File
@@ -5,15 +5,16 @@
Copyright 2016 Zbigniew Jędrzejewski-Szmek
***/
#include "ether-addr-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "set.h"
#include "string-util.h"
#include "ether-addr-util.h"
#include "network-internal.h"
#include "networkd-conf.h"
#include "networkd-network.h"
#include "network-internal.h"
static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) {
DUIDType actual = 0;
@@ -58,13 +59,29 @@ static void test_config_parse_hwaddr_one(const char *rvalue, int ret, const stru
assert_se(ret == r);
if (expected) {
assert_se(actual);
assert(ether_addr_equal(expected, actual));
} else {
assert_se(ether_addr_equal(expected, actual));
} else
assert_se(actual == NULL);
}
free(actual);
}
static void test_config_parse_hwaddrs_one(const char *rvalue, const struct ether_addr* list, size_t n) {
_cleanup_set_free_free_ Set *s = NULL;
size_t m;
assert_se(config_parse_hwaddrs("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &s, NULL) == 0);
assert_se(set_size(s) == n);
for (m = 0; m < n; m++) {
_cleanup_free_ struct ether_addr *q = NULL;
assert_se(q = set_remove(s, &list[m]));
}
assert_se(set_size(s) == 0);
}
#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80"
#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80}
@@ -90,12 +107,13 @@ static void test_config_parse_hwaddr(void) {
{ .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } },
{ .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } },
};
test_config_parse_hwaddr_one("", 0, NULL);
test_config_parse_hwaddr_one("no:ta:ma:ca:dd:re", 0, NULL);
test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:fx", 0, NULL);
test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff", 0, &t[0]);
test_config_parse_hwaddr_one(" aa:bb:cc:dd:ee:ff", 0, &t[0]);
test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\n", 0, &t[0]);
test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\n", 0, NULL);
test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\nxxx", 0, NULL);
test_config_parse_hwaddr_one("aa:bb:cc: dd:ee:ff", 0, NULL);
test_config_parse_hwaddr_one("aa:bb:cc:d d:ee:ff", 0, NULL);
@@ -116,6 +134,36 @@ static void test_config_parse_hwaddr(void) {
test_config_parse_hwaddr_one("aabbccddee:ff", 0, NULL);
test_config_parse_hwaddr_one("012345.6789ab", 0, NULL);
test_config_parse_hwaddr_one("123.4567.89ab", 0, &t[1]);
test_config_parse_hwaddrs_one("", t, 0);
test_config_parse_hwaddrs_one("no:ta:ma:ca:dd:re", t, 0);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee:fx", t, 0);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee:ff", t, 1);
test_config_parse_hwaddrs_one(" aa:bb:cc:dd:ee:ff", t, 1);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee:ff \t\n", t, 1);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee:ff \t\nxxx", t, 1);
test_config_parse_hwaddrs_one("aa:bb:cc: dd:ee:ff", t, 0);
test_config_parse_hwaddrs_one("aa:bb:cc:d d:ee:ff", t, 0);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee", t, 0);
test_config_parse_hwaddrs_one("9:aa:bb:cc:dd:ee:ff", t, 0);
test_config_parse_hwaddrs_one("aa:bb:cc:dd:ee:ff:gg", t, 0);
test_config_parse_hwaddrs_one("aa:Bb:CC:dd:ee:ff", t, 1);
test_config_parse_hwaddrs_one("01:23:45:67:89:aB", &t[1], 1);
test_config_parse_hwaddrs_one("1:23:45:67:89:aB", &t[1], 1);
test_config_parse_hwaddrs_one("aa-bb-cc-dd-ee-ff", t, 1);
test_config_parse_hwaddrs_one("AA-BB-CC-DD-EE-FF", t, 1);
test_config_parse_hwaddrs_one("01-23-45-67-89-ab", &t[1], 1);
test_config_parse_hwaddrs_one("aabb.ccdd.eeff", t, 1);
test_config_parse_hwaddrs_one("0123.4567.89ab", &t[1], 1);
test_config_parse_hwaddrs_one("123.4567.89ab.", t, 0);
test_config_parse_hwaddrs_one("aabbcc.ddeeff", t, 0);
test_config_parse_hwaddrs_one("aabbccddeeff", t, 0);
test_config_parse_hwaddrs_one("aabbccddee:ff", t, 0);
test_config_parse_hwaddrs_one("012345.6789ab", t, 0);
test_config_parse_hwaddrs_one("123.4567.89ab", &t[1], 1);
test_config_parse_hwaddrs_one("123.4567.89ab aa:bb:cc:dd:ee:ff 01-23-45-67-89-ab aa:Bb:CC:dd:ee:ff", t, 2);
test_config_parse_hwaddrs_one("123.4567.89ab aa:bb:cc:dd:ee:fx hogehoge 01-23-45-67-89-ab aaaa aa:Bb:CC:dd:ee:ff", t, 2);
}
int main(int argc, char **argv) {
+3 -3
View File
@@ -4,9 +4,9 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#endif
#include <stddef.h>
#include "conf-parser.h"
#include "network-internal.h"
#include "link-config.h"
#include "ethtool-util.h"
#include "link-config.h"
#include "network-internal.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -19,7 +19,7 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Match.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, match_mac)
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)
+1 -1
View File
@@ -57,7 +57,7 @@ static void link_config_free(link_config *link) {
free(link->filename);
free(link->match_mac);
set_free_free(link->match_mac);
strv_free(link->match_path);
strv_free(link->match_driver);
strv_free(link->match_type);
+2 -1
View File
@@ -12,6 +12,7 @@
#include "condition.h"
#include "ethtool-util.h"
#include "list.h"
#include "set.h"
typedef struct link_config_ctx link_config_ctx;
typedef struct link_config link_config;
@@ -38,7 +39,7 @@ typedef enum NamePolicy {
struct link_config {
char *filename;
struct ether_addr *match_mac;
Set *match_mac;
char **match_path;
char **match_driver;
char **match_type;