1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-31 14:50:15 +03:00

Merge pull request #21517 from yuwata/network-long-hw-addr

network: make MACAddress= can take longer address
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-11-25 20:21:38 +01:00 committed by GitHub
commit 55a044dece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 118 additions and 15 deletions

View File

@ -56,6 +56,7 @@ typedef struct Link {
struct hw_addr_data hw_addr;
struct hw_addr_data bcast_addr;
struct hw_addr_data permanent_hw_addr;
struct hw_addr_data requested_hw_addr;
struct in6_addr ipv6ll_address;
uint32_t mtu;
uint32_t min_mtu;

View File

@ -61,7 +61,7 @@ Match.KernelCommandLine, config_parse_net_condition,
Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(Network, conditions)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, conditions)
Match.Firmware, config_parse_net_condition, CONDITION_FIRMWARE, offsetof(Network, conditions)
Link.MACAddress, config_parse_ether_addr, 0, offsetof(Network, mac)
Link.MACAddress, config_parse_hw_addr, 0, offsetof(Network, hw_addr)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(Network, mtu)
Link.Group, config_parse_link_group, 0, 0
Link.ARP, config_parse_tristate, 0, offsetof(Network, arp)

View File

@ -674,7 +674,6 @@ static Network *network_free(Network *network) {
set_free(network->dhcp_allow_listed_ip);
set_free(network->dhcp_request_options);
set_free(network->dhcp6_request_options);
free(network->mac);
free(network->dhcp6_mudurl);
strv_free(network->dhcp6_user_class);
strv_free(network->dhcp6_vendor_class);

View File

@ -94,7 +94,7 @@ struct Network {
Hashmap *stacked_netdev_names;
/* [Link] section */
struct ether_addr *mac;
struct hw_addr_data hw_addr;
uint32_t mtu;
int32_t group;
int arp;

View File

@ -6,6 +6,7 @@
#include <linux/if_bridge.h>
#include "missing_network.h"
#include "netif-util.h"
#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-can.h"
@ -183,7 +184,7 @@ static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message
return 0;
}
/* set_link_mac_handler() also decrement set_link_messages, so once increment the value. */
/* set_link_mac_handler() also decrements set_link_messages, so increment the value once. */
link->set_link_messages++;
return link_set_mac_handler(rtnl, m, link);
}
@ -463,7 +464,7 @@ static int link_configure(
return log_link_debug_errno(link, r, "Could not append IFLA_GROUP attribute: %m");
break;
case SET_LINK_MAC:
r = sd_netlink_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
r = netlink_message_append_hw_addr(req, IFLA_ADDRESS, &link->requested_hw_addr);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append IFLA_ADDRESS attribute: %m");
break;
@ -542,7 +543,7 @@ static bool link_is_ready_to_call_set_link(Request *req) {
break;
case SET_LINK_MAC:
if (req->netlink_handler == link_set_mac_handler) {
/* This is the second trial to set MTU. On the first attempt
/* This is the second trial to set hardware address. On the first attempt
* req->netlink_handler points to link_set_mac_allow_retry_handler().
* The first trial failed as the interface was up. */
r = link_down(link);
@ -777,20 +778,21 @@ int link_request_to_set_group(Link *link) {
}
int link_request_to_set_mac(Link *link, bool allow_retry) {
int r;
assert(link);
assert(link->network);
if (!link->network->mac)
if (link->network->hw_addr.length == 0)
return 0;
if (link->hw_addr.length != sizeof(struct ether_addr)) {
/* Note that for now we only support changing hardware addresses on Ethernet. */
log_link_debug(link, "Size of the hardware address (%zu) does not match the size of MAC address (%zu), ignoring.",
link->hw_addr.length, sizeof(struct ether_addr));
return 0;
}
link->requested_hw_addr = link->network->hw_addr;
r = net_verify_hardware_address(link->ifname, /* warn_invalid = */ true,
link->iftype, &link->hw_addr, &link->requested_hw_addr);
if (r < 0)
return r;
if (ether_addr_equal(&link->hw_addr.ether, link->network->mac))
if (hw_addr_equal(&link->hw_addr, &link->requested_hw_addr))
return 0;
return link_request_set_link(link, SET_LINK_MAC,

View File

@ -1,7 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/if_arp.h>
#include "arphrd-util.h"
#include "device-util.h"
#include "log-link.h"
#include "memory-util.h"
#include "netif-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
@ -99,3 +103,91 @@ int net_get_unique_predictable_data_from_name(
*ret = htole64(siphash24(v, sz, key->bytes));
return 0;
}
typedef struct Link {
const char *ifname;
} Link;
int net_verify_hardware_address(
const char *ifname,
bool warn_invalid,
uint16_t iftype,
const struct hw_addr_data *ib_hw_addr, /* current or parent HW address */
struct hw_addr_data *new_hw_addr) {
Link link = { .ifname = ifname };
assert(new_hw_addr);
if (new_hw_addr->length == 0)
return 0;
if (new_hw_addr->length != arphrd_to_hw_addr_len(iftype)) {
if (warn_invalid)
log_link_warning(&link,
"Specified MAC address with invalid length (%zu, expected %zu), refusing.",
new_hw_addr->length, arphrd_to_hw_addr_len(iftype));
return -EINVAL;
}
switch (iftype) {
case ARPHRD_ETHER:
/* see eth_random_addr() in the kernel */
if (ether_addr_is_null(&new_hw_addr->ether)) {
if (warn_invalid)
log_link_warning(&link, "Specified MAC address is null, refusing.");
return -EINVAL;
}
if (ether_addr_is_broadcast(&new_hw_addr->ether)) {
if (warn_invalid)
log_link_warning(&link, "Specified MAC address is broadcast, refusing.");
return -EINVAL;
}
if (ether_addr_is_multicast(&new_hw_addr->ether)) {
if (warn_invalid)
log_link_warning(&link, "Specified MAC address has multicast bit set, clearing the bit.");
new_hw_addr->bytes[0] &= 0xfe;
}
if (!ether_addr_is_local(&new_hw_addr->ether)) {
if (warn_invalid)
log_link_warning(&link, "Specified MAC address has not local assignment bit set, setting the bit.");
new_hw_addr->bytes[0] |= 0x02;
}
break;
case ARPHRD_INFINIBAND:
/* see ipoib_check_lladdr() in the kernel */
assert(ib_hw_addr);
assert(ib_hw_addr->length == INFINIBAND_ALEN);
if (warn_invalid &&
(!memeqzero(new_hw_addr->bytes, INFINIBAND_ALEN - 8) ||
memcmp(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8) != 0))
log_link_warning(&link, "Only the last 8 bytes of the InifniBand MAC address can be changed, ignoring the first 12 bytes.");
if (memeqzero(new_hw_addr->bytes + INFINIBAND_ALEN - 8, 8)) {
if (warn_invalid)
log_link_warning(&link, "The last 8 bytes of the InfiniBand MAC address cannot be null, refusing.");
return -EINVAL;
}
memcpy(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8);
break;
default:
if (warn_invalid)
log_link_warning(&link, "Unsupported interface type %s%u to set MAC address, refusing.",
strna(arphrd_to_name(iftype)), iftype);
return -EINVAL;
}
return 0;
}

View File

@ -7,7 +7,15 @@
#include "sd-device.h"
#include "sd-id128.h"
#include "ether-addr-util.h"
int net_get_type_string(sd_device *device, uint16_t iftype, char **ret);
const char *net_get_persistent_name(sd_device *device);
int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret);
int net_get_unique_predictable_data_from_name(const char *name, const sd_id128_t *key, uint64_t *ret);
int net_verify_hardware_address(
const char *ifname,
bool warn_invalid,
uint16_t iftype,
const struct hw_addr_data *ib_hw_addr,
struct hw_addr_data *new_hw_addr);

View File

@ -2704,7 +2704,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
output = check_output('ip link show dummy98')
print(output)
self.assertRegex(output, '00:01:02:aa:bb:cc')
# 00:01:02:aa:bb:cc was requested, and the local bit is set by networkd.
self.assertRegex(output, '02:01:02:aa:bb:cc')
def test_ip_link_unmanaged(self):
copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')