mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
dhcp4: fix DHCP on InfiniBand interfaces
With these patches applied, networkd is successfully able to get an address from a DHCP server on an IPoIB interface. 1) Makes networkd pass the actual interface type to the dhcp client, instead of hardcoding it to Ethernet. 2) Fixes some issues in handling the larger (20 Byte) IB MAC addresses in the dhcp code. 3) Add a new field to networkds Link struct, which holds the interface broadcast address. 3.1) Modify the DHCP code to also expect the broadcast address as parameter. On an Ethernet-Interface the Broadcast address never changes and is always all 6 bytes set to 0xFF. On an IB one however it is not neccesarily always the same, thus fetching the actual address from the interface is neccesary. 4) Only the last 8 bytes of an IB MAC are stable, so when using an IB MAC to generate a client ID, only pass those 8 bytes.
This commit is contained in:
parent
b8162cd200
commit
14b66dbc92
@ -29,10 +29,10 @@ typedef struct DHCPServerData {
|
||||
|
||||
extern const struct hash_ops dhcp_option_hash_ops;
|
||||
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len, uint16_t arp_type,
|
||||
uint16_t port);
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
|
||||
const uint8_t *mac_addr, size_t mac_addr_len,
|
||||
const uint8_t *bcast_addr, size_t bcast_addr_len,
|
||||
uint16_t arp_type, uint16_t port);
|
||||
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
|
||||
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
|
||||
const void *packet, size_t len);
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "unaligned.h"
|
||||
|
||||
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len,
|
||||
uint32_t xid,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t bcast_addr_len,
|
||||
const struct ether_addr *eth_mac,
|
||||
uint16_t arp_type, uint8_t dhcp_hlen,
|
||||
uint16_t port) {
|
||||
@ -104,9 +104,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
.sll_protocol = htobe16(ETH_P_IP),
|
||||
.sll_ifindex = ifindex,
|
||||
.sll_hatype = htobe16(arp_type),
|
||||
.sll_halen = mac_addr_len,
|
||||
.sll_halen = bcast_addr_len,
|
||||
};
|
||||
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
|
||||
memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len);
|
||||
|
||||
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
|
||||
if (r < 0)
|
||||
@ -115,34 +115,44 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
size_t mac_addr_len, uint16_t arp_type,
|
||||
uint16_t port) {
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
|
||||
const uint8_t *mac_addr, size_t mac_addr_len,
|
||||
const uint8_t *bcast_addr, size_t bcast_addr_len,
|
||||
uint16_t arp_type, uint16_t port) {
|
||||
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* Default broadcast address for IPoIB */
|
||||
static const uint8_t ib_bcast[] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
};
|
||||
struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
|
||||
const uint8_t *bcast_addr = NULL;
|
||||
const uint8_t *default_bcast_addr;
|
||||
size_t expected_bcast_addr_len;
|
||||
uint8_t dhcp_hlen = 0;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER) {
|
||||
assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
|
||||
memcpy(ð_mac, mac_addr, ETH_ALEN);
|
||||
bcast_addr = eth_bcast;
|
||||
dhcp_hlen = ETH_ALEN;
|
||||
|
||||
default_bcast_addr = eth_bcast;
|
||||
expected_bcast_addr_len = ETH_ALEN;
|
||||
} else if (arp_type == ARPHRD_INFINIBAND) {
|
||||
assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
|
||||
bcast_addr = ib_bcast;
|
||||
default_bcast_addr = ib_bcast;
|
||||
expected_bcast_addr_len = INFINIBAND_ALEN;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
|
||||
bcast_addr, ð_mac, arp_type, dhcp_hlen, port);
|
||||
if (bcast_addr && bcast_addr_len > 0)
|
||||
assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
|
||||
else {
|
||||
bcast_addr = default_bcast_addr;
|
||||
bcast_addr_len = expected_bcast_addr_len;
|
||||
}
|
||||
|
||||
return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
|
||||
ð_mac, arp_type, dhcp_hlen, port);
|
||||
}
|
||||
|
||||
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
|
||||
|
@ -82,6 +82,8 @@ struct sd_dhcp_client {
|
||||
be32_t last_addr;
|
||||
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t mac_addr_len;
|
||||
uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t bcast_addr_len;
|
||||
uint16_t arp_type;
|
||||
sd_dhcp_client_id client_id;
|
||||
size_t client_id_len;
|
||||
@ -277,6 +279,7 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
|
||||
int sd_dhcp_client_set_mac(
|
||||
sd_dhcp_client *client,
|
||||
const uint8_t *addr,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t addr_len,
|
||||
uint16_t arp_type) {
|
||||
|
||||
@ -297,7 +300,9 @@ int sd_dhcp_client_set_mac(
|
||||
return -EINVAL;
|
||||
|
||||
if (client->mac_addr_len == addr_len &&
|
||||
memcmp(&client->mac_addr, addr, addr_len) == 0)
|
||||
memcmp(&client->mac_addr, addr, addr_len) == 0 &&
|
||||
(client->bcast_addr_len > 0) == !!bcast_addr &&
|
||||
(!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
|
||||
return 0;
|
||||
|
||||
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
|
||||
@ -309,6 +314,12 @@ int sd_dhcp_client_set_mac(
|
||||
memcpy(&client->mac_addr, addr, addr_len);
|
||||
client->mac_addr_len = addr_len;
|
||||
client->arp_type = arp_type;
|
||||
client->bcast_addr_len = 0;
|
||||
|
||||
if (bcast_addr) {
|
||||
memcpy(&client->bcast_addr, bcast_addr, addr_len);
|
||||
client->bcast_addr_len = addr_len;
|
||||
}
|
||||
|
||||
if (need_restart && client->state != DHCP_STATE_STOPPED) {
|
||||
r = sd_dhcp_client_start(client);
|
||||
@ -1381,9 +1392,10 @@ static int client_start_delayed(sd_dhcp_client *client) {
|
||||
|
||||
client->xid = random_u32();
|
||||
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
|
||||
client->xid, client->mac_addr,
|
||||
client->mac_addr_len, client->arp_type, client->port);
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
|
||||
client->mac_addr, client->mac_addr_len,
|
||||
client->bcast_addr, client->bcast_addr_len,
|
||||
client->arp_type, client->port);
|
||||
if (r < 0) {
|
||||
client_stop(client, r);
|
||||
return r;
|
||||
@ -1431,10 +1443,10 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
client->state = DHCP_STATE_REBINDING;
|
||||
client->attempt = 0;
|
||||
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
|
||||
client->xid, client->mac_addr,
|
||||
client->mac_addr_len, client->arp_type,
|
||||
client->port);
|
||||
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
|
||||
client->mac_addr, client->mac_addr_len,
|
||||
client->bcast_addr, client->bcast_addr_len,
|
||||
client->arp_type, client->port);
|
||||
if (r < 0) {
|
||||
client_stop(client, r);
|
||||
return 0;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "util.h"
|
||||
|
||||
static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
|
||||
static uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
|
||||
|
||||
@ -247,6 +248,7 @@ int dhcp_network_bind_raw_socket(
|
||||
union sockaddr_union *link,
|
||||
uint32_t id,
|
||||
const uint8_t *addr, size_t addr_len,
|
||||
const uint8_t *bcaddr, size_t bcaddr_len,
|
||||
uint16_t arp_type, uint16_t port) {
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
|
||||
@ -296,7 +298,7 @@ static void test_discover_message(sd_event *e) {
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
|
||||
|
||||
@ -513,7 +515,7 @@ static void test_addr_acq(sd_event *e) {
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
|
||||
|
||||
assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
|
||||
|
||||
|
@ -1271,14 +1271,24 @@ static int dhcp4_set_client_identifier(Link *link) {
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
|
||||
break;
|
||||
}
|
||||
case DHCP_CLIENT_ID_MAC:
|
||||
case DHCP_CLIENT_ID_MAC: {
|
||||
const uint8_t *hw_addr = link->hw_addr.addr.bytes;
|
||||
size_t hw_addr_len = link->hw_addr.length;
|
||||
|
||||
if (link->iftype == ARPHRD_INFINIBAND && hw_addr_len == INFINIBAND_ALEN) {
|
||||
/* set_client_id expects only last 8 bytes of an IB address */
|
||||
hw_addr += INFINIBAND_ALEN - 8;
|
||||
hw_addr_len -= INFINIBAND_ALEN - 8;
|
||||
}
|
||||
|
||||
r = sd_dhcp_client_set_client_id(link->dhcp_client,
|
||||
ARPHRD_ETHER,
|
||||
link->hw_addr.addr.bytes,
|
||||
link->hw_addr.length);
|
||||
link->iftype,
|
||||
hw_addr,
|
||||
hw_addr_len);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert_not_reached("Unknown client identifier type.");
|
||||
}
|
||||
@ -1326,7 +1336,8 @@ int dhcp4_configure(Link *link) {
|
||||
|
||||
r = sd_dhcp_client_set_mac(link->dhcp_client,
|
||||
link->hw_addr.addr.bytes,
|
||||
link->hw_addr.length, ARPHRD_ETHER);
|
||||
link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
|
||||
link->hw_addr.length, link->iftype);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
|
||||
|
||||
@ -1484,7 +1495,9 @@ int dhcp4_update_mac(Link *link) {
|
||||
if (!link->dhcp_client)
|
||||
return 0;
|
||||
|
||||
r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes, link->hw_addr.length, ARPHRD_ETHER);
|
||||
r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes,
|
||||
link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
|
||||
link->hw_addr.length, link->iftype);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1357,7 +1357,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
|
||||
assert(link->network);
|
||||
assert(client);
|
||||
|
||||
r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, ARPHRD_ETHER);
|
||||
r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, link->iftype);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -425,6 +425,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Hardware address not found for new device, continuing without");
|
||||
|
||||
r = netlink_message_read_hw_addr(message, IFLA_BROADCAST, &link->bcast_addr);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Broadcast address not found for new device, continuing without");
|
||||
|
||||
r = ethtool_get_permanent_macaddr(&manager->ethtool_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");
|
||||
|
@ -54,6 +54,7 @@ typedef struct Link {
|
||||
unsigned short iftype;
|
||||
char *state_file;
|
||||
hw_addr_data hw_addr;
|
||||
hw_addr_data bcast_addr;
|
||||
struct ether_addr permanent_mac;
|
||||
struct in6_addr ipv6ll_address;
|
||||
uint32_t mtu;
|
||||
|
@ -126,6 +126,7 @@ int sd_dhcp_client_set_ifindex(
|
||||
int sd_dhcp_client_set_mac(
|
||||
sd_dhcp_client *client,
|
||||
const uint8_t *addr,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t addr_len,
|
||||
uint16_t arp_type);
|
||||
int sd_dhcp_client_set_client_id(
|
||||
|
Loading…
Reference in New Issue
Block a user