Merge pull request #14448 from yuwata/network-permanent-mac-address
network, udev: support permanent mac address
This commit is contained in:
commit
0aa9bffe10
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, ÐER_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, ÐER_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)];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[Match]
|
||||
MACAddress=
|
||||
PermanentMACAddress=
|
||||
OriginalName=
|
||||
Path=
|
||||
Driver=
|
||||
|
|
|
@ -28,6 +28,7 @@ Virtualization=
|
|||
KernelCommandLine=
|
||||
Host=
|
||||
MACAddress=
|
||||
PermanentMACAddress=
|
||||
[Link]
|
||||
RequiredForOnline=
|
||||
ARP=
|
||||
|
|
Loading…
Reference in New Issue