udev: link-config - add mac address policy
This introduces a new key MACAddressPolicy. The possible policies are 'persistent' and 'random'. 'persistent' will do nothing if the current address is the hardware address, but if the hardware does not have an address (or another address is set for whatever reason), we will generate an address which will be random, but persistent between boots (based on machineid and persistent netif name). 'random' will do nothing if the kernel already set a random address, otherwise it will generate a random one and use that instead. This patch sets MACAddressPolicy=persistent in the default .link file.
This commit is contained in:
parent
a7792fecc3
commit
16b9b87aee
|
@ -2347,6 +2347,7 @@ libudev_core_la_LIBADD = \
|
|||
libsystemd-daemon-internal.la \
|
||||
libsystemd-shared.la \
|
||||
libsystemd-rtnl.la \
|
||||
libsystemd-id128.la \
|
||||
$(BLKID_LIBS) \
|
||||
$(KMOD_LIBS)
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
[Link]
|
||||
NamePolicy=onboard slot path
|
||||
MACAddressPolicy=persistent
|
||||
|
|
|
@ -19,6 +19,7 @@ Match.Path, config_parse_string, 0, offsetof(link
|
|||
Match.Driver, config_parse_string, 0, offsetof(link_config, match_driver)
|
||||
Match.Type, config_parse_string, 0, offsetof(link_config, match_type)
|
||||
Link.Description, config_parse_string, 0, offsetof(link_config, description)
|
||||
Link.MACAddressPolicy, config_parse_string, 0, offsetof(link_config, mac_policy)
|
||||
Link.MACAddress, config_parse_string, 0, offsetof(link_config, mac)
|
||||
Link.NamePolicy, config_parse_strv, 0, offsetof(link_config, name_policy)
|
||||
Link.Name, config_parse_string, 0, offsetof(link_config, name)
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
#include <netinet/ether.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "link-config.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "link-config.h"
|
||||
#include "ethtool-util.h"
|
||||
|
||||
#include "libudev-private.h"
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include "conf-parser.h"
|
||||
#include "conf-files.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
struct link_config_ctx {
|
||||
LIST_HEAD(link_config, links);
|
||||
|
@ -252,11 +254,9 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_confi
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, const char *mac, unsigned int mtu) {
|
||||
static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, const struct ether_addr *mac, unsigned int mtu) {
|
||||
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
|
||||
char new_name[IFNAMSIZ];
|
||||
struct ether_addr new_mac;
|
||||
bool need_update;
|
||||
bool need_update = false;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
|
@ -267,8 +267,7 @@ static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, con
|
|||
return r;
|
||||
|
||||
if (name) {
|
||||
strscpy(new_name, IFNAMSIZ, name);
|
||||
r = sd_rtnl_message_append(message, IFLA_IFNAME, new_name);
|
||||
r = sd_rtnl_message_append(message, IFLA_IFNAME, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -276,16 +275,7 @@ static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, con
|
|||
}
|
||||
|
||||
if (mac) {
|
||||
r = sscanf(mac, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
&new_mac.ether_addr_octet[0],
|
||||
&new_mac.ether_addr_octet[1],
|
||||
&new_mac.ether_addr_octet[2],
|
||||
&new_mac.ether_addr_octet[3],
|
||||
&new_mac.ether_addr_octet[4],
|
||||
&new_mac.ether_addr_octet[5]);
|
||||
if (r != 6)
|
||||
return -EINVAL;
|
||||
r = sd_rtnl_message_append(message, IFLA_ADDRESS, &new_mac);
|
||||
r = sd_rtnl_message_append(message, IFLA_ADDRESS, mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -301,7 +291,7 @@ static int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, con
|
|||
}
|
||||
|
||||
if (need_update) {
|
||||
r = sd_rtnl_send_with_reply_and_block(rtnl, message, 250 * USEC_PER_MSEC, NULL);
|
||||
r = sd_rtnl_send_with_reply_and_block(rtnl, message, 5 * USEC_PER_SEC, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -328,8 +318,90 @@ static bool enable_name_policy(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool mac_is_random(struct udev_device *device) {
|
||||
const char *s;
|
||||
int type;
|
||||
|
||||
s = udev_device_get_sysattr_value(device, "addr_assign_type");
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
type = strtoul(s, NULL, 0);
|
||||
|
||||
/* check for NET_ADDR_RANDOM */
|
||||
return type == 1;
|
||||
}
|
||||
|
||||
static bool mac_is_permanent(struct udev_device *device) {
|
||||
const char *s;
|
||||
int type;
|
||||
|
||||
s = udev_device_get_sysattr_value(device, "addr_assign_type");
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
type = strtoul(s, NULL, 0);
|
||||
|
||||
/* check for NET_ADDR_PERM */
|
||||
return type == 0;
|
||||
}
|
||||
|
||||
static int get_mac(struct udev_device *device, bool want_random, struct ether_addr **ret) {
|
||||
struct ether_addr *mac;
|
||||
unsigned int seed;
|
||||
int r, i;
|
||||
|
||||
mac = calloc(1, sizeof(struct ether_addr));
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
|
||||
if (want_random)
|
||||
seed = random_u();
|
||||
else {
|
||||
const char *name;
|
||||
sd_id128_t machine;
|
||||
char machineid_buf[33];
|
||||
const char *seed_str;
|
||||
|
||||
/* fetch some persistent data unique (on this machine) to this device */
|
||||
name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
|
||||
if (!name) {
|
||||
name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
|
||||
if (!name) {
|
||||
name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
|
||||
if (!name)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* fetch some persistent data unique to this machine */
|
||||
r = sd_id128_get_machine(&machine);
|
||||
if (r < 0)
|
||||
return -1;
|
||||
|
||||
/* combine the data */
|
||||
seed_str = strappenda(name, sd_id128_to_string(machine, machineid_buf));
|
||||
|
||||
/* hash to get seed */
|
||||
seed = string_hash_func(seed_str);
|
||||
}
|
||||
|
||||
srandom(seed);
|
||||
|
||||
for(i = 0; i < ETH_ALEN; i++) {
|
||||
mac->ether_addr_octet[i] = random();
|
||||
}
|
||||
|
||||
/* see eth_random_addr in the kernel */
|
||||
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
|
||||
mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
|
||||
|
||||
*ret = mac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
|
||||
const char *name, *new_name = NULL;
|
||||
const char *name;
|
||||
char *new_name = NULL;
|
||||
struct ether_addr *mac = NULL;
|
||||
int r, ifindex;
|
||||
|
||||
name = udev_device_get_sysname(device);
|
||||
|
@ -380,19 +452,27 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_dev
|
|||
|
||||
STRV_FOREACH(policy, config->name_policy) {
|
||||
if (streq(*policy, "onboard")) {
|
||||
new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
|
||||
r = strdup_or_null(udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD"), &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (new_name)
|
||||
break;
|
||||
} else if (streq(*policy, "slot")) {
|
||||
new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
|
||||
r = strdup_or_null(udev_device_get_property_value(device, "ID_NET_NAME_SLOT"), &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (new_name)
|
||||
break;
|
||||
} else if (streq(*policy, "path")) {
|
||||
new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
|
||||
r = strdup_or_null(udev_device_get_property_value(device, "ID_NET_NAME_PATH"), &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (new_name)
|
||||
break;
|
||||
} else if (streq(*policy, "mac")) {
|
||||
new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
|
||||
r = strdup_or_null(udev_device_get_property_value(device, "ID_NET_NAME_MAC"), &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (new_name)
|
||||
break;
|
||||
} else
|
||||
|
@ -400,14 +480,52 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_dev
|
|||
}
|
||||
}
|
||||
|
||||
if (!new_name && config->name)
|
||||
new_name = config->name;
|
||||
if (!new_name && config->name) {
|
||||
new_name = calloc(1, IFNAMSIZ);
|
||||
strscpy(new_name, IFNAMSIZ, config->name);
|
||||
}
|
||||
|
||||
r = rtnl_set_properties(ctx->rtnl, ifindex, new_name, config->mac, config->mtu);
|
||||
if (r < 0) {
|
||||
log_warning("Could not set Name, MACAddress or MTU on %s", name);
|
||||
if (config->mac_policy) {
|
||||
if (streq(config->mac_policy, "persistent")) {
|
||||
if (!mac_is_permanent(device)) {
|
||||
r = get_mac(device, false, &mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else if (streq(config->mac_policy, "random")) {
|
||||
if (!mac_is_random(device)) {
|
||||
r = get_mac(device, true, &mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
log_warning("Invalid MACAddress policy '%s', ignoring.", config->mac_policy);
|
||||
}
|
||||
|
||||
if (!mac && config->mac) {
|
||||
mac = calloc(1, sizeof(struct ether_addr));
|
||||
r = sscanf(config->mac, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
&mac->ether_addr_octet[0],
|
||||
&mac->ether_addr_octet[1],
|
||||
&mac->ether_addr_octet[2],
|
||||
&mac->ether_addr_octet[3],
|
||||
&mac->ether_addr_octet[4],
|
||||
&mac->ether_addr_octet[5]);
|
||||
if (r != 6) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = rtnl_set_properties(ctx->rtnl, ifindex, new_name, mac, config->mtu);
|
||||
if (r < 0) {
|
||||
log_warning("Could not set Name, MACAddress or MTU on %s: %s", name, strerror(-r));
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
free(new_name);
|
||||
free(mac);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ struct link_config {
|
|||
|
||||
char *description;
|
||||
char *mac;
|
||||
char *mac_policy;
|
||||
char **name_policy;
|
||||
char *name;
|
||||
unsigned int mtu;
|
||||
|
|
Loading…
Reference in a new issue