Merge pull request #14448 from yuwata/network-permanent-mac-address

network, udev: support permanent mac address
This commit is contained in:
Lennart Poettering 2020-01-08 15:36:27 +01:00 committed by GitHub
commit 0aa9bffe10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 148 additions and 15 deletions

View File

@ -80,6 +80,17 @@
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PermanentMACAddress=</varname></term>
<listitem>
<para>A whitespace-separated list of hardware's permanent addresses. While
<varname>MACAddress=</varname> matches the device's current MAC address, this matches the
device's permanent MAC address, which may be different from the current one. Use full
colon-, hyphen- or dot-delimited hexadecimal. 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>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>OriginalName=</varname></term>
<listitem>

View File

@ -97,6 +97,17 @@
<programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PermanentMACAddress=</varname></term>
<listitem>
<para>A whitespace-separated list of hardware's permanent addresses. While
<varname>MACAddress=</varname> matches the device's current MAC address, this matches the
device's permanent MAC address, which may be different from the current one. Use full
colon-, hyphen- or dot-delimited hexadecimal. 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>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Path=</varname></term>
<listitem>

View File

@ -167,6 +167,7 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
bool net_match_config(Set *match_mac,
Set *match_permanent_mac,
char * const *match_paths,
char * const *match_drivers,
char * const *match_types,
@ -177,6 +178,7 @@ bool net_match_config(Set *match_mac,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
const char *dev_name,
char * const *alternative_names,
enum nl80211_iftype wifi_iftype,
@ -200,6 +202,12 @@ bool net_match_config(Set *match_mac,
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
return false;
if (match_permanent_mac &&
(!dev_permanent_mac ||
ether_addr_is_null(dev_permanent_mac) ||
!set_contains(match_permanent_mac, dev_permanent_mac)))
return false;
if (!net_condition_test_strv(match_paths, dev_path))
return false;

View File

@ -16,6 +16,7 @@
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
bool net_match_config(Set *match_mac,
Set *match_permanent_mac,
char * const *match_path,
char * const *match_driver,
char * const *match_type,
@ -26,6 +27,7 @@ bool net_match_config(Set *match_mac,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
const char *dev_name,
char * const *alternative_names,
enum nl80211_iftype wifi_iftype,

View File

@ -138,6 +138,7 @@ typedef struct LinkInfo {
int ifindex;
unsigned short iftype;
struct ether_addr mac_address;
struct ether_addr permanent_mac_address;
uint32_t mtu;
uint32_t min_mtu;
uint32_t max_mtu;
@ -177,6 +178,7 @@ typedef struct LinkInfo {
struct ether_addr bssid;
bool has_mac_address:1;
bool has_permanent_mac_address:1;
bool has_tx_queues:1;
bool has_rx_queues:1;
bool has_stats64:1;
@ -322,6 +324,12 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
_cleanup_close_ int fd = -1;
info->has_permanent_mac_address =
ethtool_get_permanent_macaddr(&fd, info->name, &info->permanent_mac_address) >= 0 &&
memcmp(&info->permanent_mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0 &&
memcmp(&info->permanent_mac_address, &info->mac_address, sizeof(struct ether_addr)) != 0;
(void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
(void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
(void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
@ -1295,6 +1303,26 @@ static int link_status_one(
return r;
}
if (info->has_permanent_mac_address) {
_cleanup_free_ char *description = NULL;
char ea[ETHER_ADDR_TO_STRING_MAX];
(void) ieee_oui(hwdb, &info->permanent_mac_address, &description);
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "HW Permanent Address:");
if (r < 0)
return r;
r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
ether_addr_to_string(&info->permanent_mac_address, ea),
description ? " (" : "",
strempty(description),
description ? ")" : "");
if (r < 0)
return r;
}
if (info->mtu > 0) {
char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];

View File

@ -12,6 +12,7 @@
#include "dhcp-identifier.h"
#include "dhcp-lease-internal.h"
#include "env-file.h"
#include "ethtool-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "ipvlan.h"
@ -617,6 +618,11 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
if (r < 0)
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
_cleanup_close_ int fd = -1;
r = ethtool_get_permanent_macaddr(&fd, link->ifname, &link->permanent_mac);
if (r < 0)
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &link->alternative_names);
if (r < 0 && r != -ENODATA)
return r;
@ -2963,7 +2969,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
}
r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
&link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
&link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
@ -3095,7 +3101,7 @@ static int link_initialized_and_synced(Link *link) {
return r;
r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
&link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
&link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;

View File

@ -53,6 +53,7 @@ typedef struct Link {
unsigned short iftype;
char *state_file;
struct ether_addr mac;
struct ether_addr permanent_mac;
struct in6_addr ipv6ll_address;
uint32_t mtu;
sd_device *sd_device;

View File

@ -28,6 +28,7 @@ struct ConfigPerfItem;
%includes
%%
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac)
Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_permanent_mac)
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)

View File

@ -160,10 +160,10 @@ int network_verify(Network *network) {
assert(network);
assert(network->filename);
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) && strv_isempty(network->match_property) &&
strv_isempty(network->match_ssid) && !network->conditions)
if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) &&
strv_isempty(network->match_path) && strv_isempty(network->match_driver) &&
strv_isempty(network->match_type) && strv_isempty(network->match_name) &&
strv_isempty(network->match_property) && strv_isempty(network->match_ssid) && !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.",
@ -601,6 +601,7 @@ static Network *network_free(Network *network) {
free(network->filename);
set_free_free(network->match_mac);
set_free_free(network->match_permanent_mac);
strv_free(network->match_path);
strv_free(network->match_driver);
strv_free(network->match_type);
@ -721,7 +722,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
}
int network_get(Manager *manager, sd_device *device,
const char *ifname, char * const *alternative_names, const struct ether_addr *address,
const char *ifname, char * const *alternative_names,
const struct ether_addr *address, const struct ether_addr *permanent_address,
enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
Network **ret) {
Network *network;
@ -731,10 +733,12 @@ int network_get(Manager *manager, sd_device *device,
assert(ret);
ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
if (net_match_config(network->match_mac, network->match_path, network->match_driver,
if (net_match_config(network->match_mac, network->match_permanent_mac,
network->match_path, network->match_driver,
network->match_type, network->match_name, network->match_property,
network->match_wlan_iftype, network->match_ssid, network->match_bssid,
device, address, ifname, alternative_names, wlan_iftype, ssid, bssid)) {
device, address, permanent_address,
ifname, alternative_names, wlan_iftype, ssid, bssid)) {
if (network->match_name && device) {
const char *attr;
uint8_t name_assign_type = NET_NAME_UNKNOWN;

View File

@ -64,6 +64,7 @@ struct Network {
unsigned n_ref;
Set *match_mac;
Set *match_permanent_mac;
char **match_path;
char **match_driver;
char **match_type;
@ -302,7 +303,8 @@ int network_verify(Network *network);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, sd_device *device, const char *ifname, char * const *alternative_names,
const struct ether_addr *mac, enum nl80211_iftype wlan_iftype, const char *ssid,
const struct ether_addr *mac, const struct ether_addr *permanent_mac,
enum nl80211_iftype wlan_iftype, const char *ssid,
const struct ether_addr *bssid, Network **ret);
int network_apply(Network *network, Link *link);
void network_apply_anonymize_if_set(Network *network);

View File

@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) {
/* let's assume that the test machine does not have a .network file
that applies to the loopback device... */
assert_se(network_get(manager, loopback, "lo", NULL, &mac, 0, NULL, NULL, &network) == -ENOENT);
assert_se(network_get(manager, loopback, "lo", NULL, &mac, &mac, 0, NULL, NULL, &network) == -ENOENT);
assert_se(!network);
}

View File

@ -3,6 +3,7 @@
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/sockios.h>
#include "conf-parser.h"
@ -217,6 +218,46 @@ int ethtool_get_link_info(int *fd, const char *ifname,
return 0;
}
int ethtool_get_permanent_macaddr(int *fd, const char *ifname, struct ether_addr *ret) {
_cleanup_free_ struct ethtool_perm_addr *epaddr = NULL;
struct ifreq ifr;
int r;
assert(fd);
assert(ifname);
assert(ret);
if (*fd < 0) {
r = ethtool_connect_or_warn(fd, false);
if (r < 0)
return r;
}
epaddr = malloc(offsetof(struct ethtool_perm_addr, data) + MAX_ADDR_LEN);
if (!epaddr)
return -ENOMEM;
epaddr->cmd = ETHTOOL_GPERMADDR;
epaddr->size = MAX_ADDR_LEN;
ifr = (struct ifreq) {
.ifr_data = (caddr_t) epaddr,
};
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = ioctl(*fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
if (epaddr->size != 6)
return -EOPNOTSUPP;
for (size_t i = 0; i < epaddr->size; i++)
ret->ether_addr_octet[i] = epaddr->data[i];
return 0;
}
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex) {
struct ethtool_cmd ecmd = {
.cmd = ETHTOOL_GSET

View File

@ -2,6 +2,7 @@
#pragma once
#include <macro.h>
#include <net/ethernet.h>
#include <linux/ethtool.h>
#include "conf-parser.h"
@ -91,6 +92,7 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret);
int ethtool_get_link_info(int *fd, const char *ifname,
int *ret_autonegotiation, size_t *ret_speed,
Duplex *ret_duplex, NetDevPort *ret_port);
int ethtool_get_permanent_macaddr(int *fd, const char *ifname, struct ether_addr *ret);
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex);
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
int ethtool_set_nic_buffer_size(int *fd, const char *ifname, netdev_ring_param *ring);

View File

@ -20,6 +20,7 @@ struct ConfigPerfItem;
%includes
%%
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac)
Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_permanent_mac)
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)

View File

@ -47,6 +47,7 @@ static void link_config_free(link_config *link) {
free(link->filename);
set_free_free(link->match_mac);
set_free_free(link->match_permanent_mac);
strv_free(link->match_path);
strv_free(link->match_driver);
strv_free(link->match_type);
@ -162,8 +163,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
if (link->speed > UINT_MAX)
return -ERANGE;
if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) &&
strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
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. "
@ -236,16 +237,27 @@ bool link_config_should_reload(link_config_ctx *ctx) {
}
int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
struct ether_addr permanent_mac = {};
link_config *link;
const char *name;
int r;
assert(ctx);
assert(device);
assert(ret);
r = sd_device_get_sysname(device, &name);
if (r < 0)
return r;
r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
if (r < 0)
log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
LIST_FOREACH(links, link, ctx->links) {
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
device, NULL, NULL, NULL, 0, NULL, NULL)) {
device, NULL, &permanent_mac, NULL, NULL, 0, NULL, NULL)) {
if (link->match_name && !strv_contains(link->match_name, "*")) {
unsigned name_assign_type = NET_NAME_UNKNOWN;

View File

@ -36,6 +36,7 @@ struct link_config {
char *filename;
Set *match_mac;
Set *match_permanent_mac;
char **match_path;
char **match_driver;
char **match_type;

View File

@ -1,5 +1,6 @@
[Match]
MACAddress=
PermanentMACAddress=
OriginalName=
Path=
Driver=

View File

@ -28,6 +28,7 @@ Virtualization=
KernelCommandLine=
Host=
MACAddress=
PermanentMACAddress=
[Link]
RequiredForOnline=
ARP=