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:
commit
55a044dece
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user