Skip to content

Commit 14b66db

Browse files
committed
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.
1 parent b8162cd commit 14b66db

File tree

9 files changed

+79
-36
lines changed

9 files changed

+79
-36
lines changed

src/libsystemd-network/dhcp-internal.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ typedef struct DHCPServerData {
2929

3030
extern const struct hash_ops dhcp_option_hash_ops;
3131

32-
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
33-
uint32_t xid, const uint8_t *mac_addr,
34-
size_t mac_addr_len, uint16_t arp_type,
35-
uint16_t port);
32+
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
33+
const uint8_t *mac_addr, size_t mac_addr_len,
34+
const uint8_t *bcast_addr, size_t bcast_addr_len,
35+
uint16_t arp_type, uint16_t port);
3636
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
3737
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
3838
const void *packet, size_t len);

src/libsystemd-network/dhcp-network.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
#include "unaligned.h"
2020

2121
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
22-
uint32_t xid, const uint8_t *mac_addr,
23-
size_t mac_addr_len,
22+
uint32_t xid,
2423
const uint8_t *bcast_addr,
24+
size_t bcast_addr_len,
2525
const struct ether_addr *eth_mac,
2626
uint16_t arp_type, uint8_t dhcp_hlen,
2727
uint16_t port) {
@@ -104,9 +104,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
104104
.sll_protocol = htobe16(ETH_P_IP),
105105
.sll_ifindex = ifindex,
106106
.sll_hatype = htobe16(arp_type),
107-
.sll_halen = mac_addr_len,
107+
.sll_halen = bcast_addr_len,
108108
};
109-
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
109+
memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len);
110110

111111
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
112112
if (r < 0)
@@ -115,34 +115,44 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
115115
return TAKE_FD(s);
116116
}
117117

118-
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
119-
uint32_t xid, const uint8_t *mac_addr,
120-
size_t mac_addr_len, uint16_t arp_type,
121-
uint16_t port) {
118+
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
119+
const uint8_t *mac_addr, size_t mac_addr_len,
120+
const uint8_t *bcast_addr, size_t bcast_addr_len,
121+
uint16_t arp_type, uint16_t port) {
122122
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
123123
/* Default broadcast address for IPoIB */
124124
static const uint8_t ib_bcast[] = {
125125
0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
126126
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127127
0xff, 0xff, 0xff, 0xff
128-
};
128+
};
129129
struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
130-
const uint8_t *bcast_addr = NULL;
130+
const uint8_t *default_bcast_addr;
131+
size_t expected_bcast_addr_len;
131132
uint8_t dhcp_hlen = 0;
132133

133134
if (arp_type == ARPHRD_ETHER) {
134135
assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
135136
memcpy(&eth_mac, mac_addr, ETH_ALEN);
136-
bcast_addr = eth_bcast;
137137
dhcp_hlen = ETH_ALEN;
138+
139+
default_bcast_addr = eth_bcast;
140+
expected_bcast_addr_len = ETH_ALEN;
138141
} else if (arp_type == ARPHRD_INFINIBAND) {
139-
assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
140-
bcast_addr = ib_bcast;
142+
default_bcast_addr = ib_bcast;
143+
expected_bcast_addr_len = INFINIBAND_ALEN;
141144
} else
142145
return -EINVAL;
143146

144-
return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
145-
bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
147+
if (bcast_addr && bcast_addr_len > 0)
148+
assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
149+
else {
150+
bcast_addr = default_bcast_addr;
151+
bcast_addr_len = expected_bcast_addr_len;
152+
}
153+
154+
return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
155+
&eth_mac, arp_type, dhcp_hlen, port);
146156
}
147157

148158
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {

src/libsystemd-network/sd-dhcp-client.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ struct sd_dhcp_client {
8282
be32_t last_addr;
8383
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
8484
size_t mac_addr_len;
85+
uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
86+
size_t bcast_addr_len;
8587
uint16_t arp_type;
8688
sd_dhcp_client_id client_id;
8789
size_t client_id_len;
@@ -277,6 +279,7 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
277279
int sd_dhcp_client_set_mac(
278280
sd_dhcp_client *client,
279281
const uint8_t *addr,
282+
const uint8_t *bcast_addr,
280283
size_t addr_len,
281284
uint16_t arp_type) {
282285

@@ -297,7 +300,9 @@ int sd_dhcp_client_set_mac(
297300
return -EINVAL;
298301

299302
if (client->mac_addr_len == addr_len &&
300-
memcmp(&client->mac_addr, addr, addr_len) == 0)
303+
memcmp(&client->mac_addr, addr, addr_len) == 0 &&
304+
(client->bcast_addr_len > 0) == !!bcast_addr &&
305+
(!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
301306
return 0;
302307

303308
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
@@ -309,6 +314,12 @@ int sd_dhcp_client_set_mac(
309314
memcpy(&client->mac_addr, addr, addr_len);
310315
client->mac_addr_len = addr_len;
311316
client->arp_type = arp_type;
317+
client->bcast_addr_len = 0;
318+
319+
if (bcast_addr) {
320+
memcpy(&client->bcast_addr, bcast_addr, addr_len);
321+
client->bcast_addr_len = addr_len;
322+
}
312323

313324
if (need_restart && client->state != DHCP_STATE_STOPPED) {
314325
r = sd_dhcp_client_start(client);
@@ -1381,9 +1392,10 @@ static int client_start_delayed(sd_dhcp_client *client) {
13811392

13821393
client->xid = random_u32();
13831394

1384-
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
1385-
client->xid, client->mac_addr,
1386-
client->mac_addr_len, client->arp_type, client->port);
1395+
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
1396+
client->mac_addr, client->mac_addr_len,
1397+
client->bcast_addr, client->bcast_addr_len,
1398+
client->arp_type, client->port);
13871399
if (r < 0) {
13881400
client_stop(client, r);
13891401
return r;
@@ -1431,10 +1443,10 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
14311443
client->state = DHCP_STATE_REBINDING;
14321444
client->attempt = 0;
14331445

1434-
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
1435-
client->xid, client->mac_addr,
1436-
client->mac_addr_len, client->arp_type,
1437-
client->port);
1446+
r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
1447+
client->mac_addr, client->mac_addr_len,
1448+
client->bcast_addr, client->bcast_addr_len,
1449+
client->arp_type, client->port);
14381450
if (r < 0) {
14391451
client_stop(client, r);
14401452
return 0;

src/libsystemd-network/test-dhcp-client.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "util.h"
2424

2525
static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
26+
static uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2627

2728
typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
2829

@@ -247,6 +248,7 @@ int dhcp_network_bind_raw_socket(
247248
union sockaddr_union *link,
248249
uint32_t id,
249250
const uint8_t *addr, size_t addr_len,
251+
const uint8_t *bcaddr, size_t bcaddr_len,
250252
uint16_t arp_type, uint16_t port) {
251253

252254
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) {
296298
assert_se(r >= 0);
297299

298300
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
299-
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
301+
assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
300302

301303
assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
302304

@@ -513,7 +515,7 @@ static void test_addr_acq(sd_event *e) {
513515
assert_se(r >= 0);
514516

515517
assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
516-
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
518+
assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
517519

518520
assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
519521

src/network/networkd-dhcp4.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,14 +1271,24 @@ static int dhcp4_set_client_identifier(Link *link) {
12711271
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
12721272
break;
12731273
}
1274-
case DHCP_CLIENT_ID_MAC:
1274+
case DHCP_CLIENT_ID_MAC: {
1275+
const uint8_t *hw_addr = link->hw_addr.addr.bytes;
1276+
size_t hw_addr_len = link->hw_addr.length;
1277+
1278+
if (link->iftype == ARPHRD_INFINIBAND && hw_addr_len == INFINIBAND_ALEN) {
1279+
/* set_client_id expects only last 8 bytes of an IB address */
1280+
hw_addr += INFINIBAND_ALEN - 8;
1281+
hw_addr_len -= INFINIBAND_ALEN - 8;
1282+
}
1283+
12751284
r = sd_dhcp_client_set_client_id(link->dhcp_client,
1276-
ARPHRD_ETHER,
1277-
link->hw_addr.addr.bytes,
1278-
link->hw_addr.length);
1285+
link->iftype,
1286+
hw_addr,
1287+
hw_addr_len);
12791288
if (r < 0)
12801289
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
12811290
break;
1291+
}
12821292
default:
12831293
assert_not_reached("Unknown client identifier type.");
12841294
}
@@ -1326,7 +1336,8 @@ int dhcp4_configure(Link *link) {
13261336

13271337
r = sd_dhcp_client_set_mac(link->dhcp_client,
13281338
link->hw_addr.addr.bytes,
1329-
link->hw_addr.length, ARPHRD_ETHER);
1339+
link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
1340+
link->hw_addr.length, link->iftype);
13301341
if (r < 0)
13311342
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
13321343

@@ -1484,7 +1495,9 @@ int dhcp4_update_mac(Link *link) {
14841495
if (!link->dhcp_client)
14851496
return 0;
14861497

1487-
r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes, link->hw_addr.length, ARPHRD_ETHER);
1498+
r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes,
1499+
link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
1500+
link->hw_addr.length, link->iftype);
14881501
if (r < 0)
14891502
return r;
14901503

src/network/networkd-dhcp6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) {
13571357
assert(link->network);
13581358
assert(client);
13591359

1360-
r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, ARPHRD_ETHER);
1360+
r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, link->iftype);
13611361
if (r < 0)
13621362
return r;
13631363

src/network/networkd-link.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
425425
if (r < 0)
426426
log_link_debug_errno(link, r, "Hardware address not found for new device, continuing without");
427427

428+
r = netlink_message_read_hw_addr(message, IFLA_BROADCAST, &link->bcast_addr);
429+
if (r < 0)
430+
log_link_debug_errno(link, r, "Broadcast address not found for new device, continuing without");
431+
428432
r = ethtool_get_permanent_macaddr(&manager->ethtool_fd, link->ifname, &link->permanent_mac);
429433
if (r < 0)
430434
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");

src/network/networkd-link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef struct Link {
5454
unsigned short iftype;
5555
char *state_file;
5656
hw_addr_data hw_addr;
57+
hw_addr_data bcast_addr;
5758
struct ether_addr permanent_mac;
5859
struct in6_addr ipv6ll_address;
5960
uint32_t mtu;

src/systemd/sd-dhcp-client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ int sd_dhcp_client_set_ifindex(
126126
int sd_dhcp_client_set_mac(
127127
sd_dhcp_client *client,
128128
const uint8_t *addr,
129+
const uint8_t *bcast_addr,
129130
size_t addr_len,
130131
uint16_t arp_type);
131132
int sd_dhcp_client_set_client_id(

0 commit comments

Comments
 (0)