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:
Timo Rothenpieler
2020-10-28 14:44:43 +01:00
parent b8162cd200
commit 14b66dbc92
9 changed files with 79 additions and 36 deletions
+4 -4
View File
@@ -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);
+25 -15
View File
@@ -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(&eth_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, &eth_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,
&eth_mac, arp_type, dhcp_hlen, port);
}
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
+20 -8
View File
@@ -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;
+4 -2
View File
@@ -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);