X Tutup
Skip to content

Commit 76a86ff

Browse files
committed
network: ipv4acd: first probe address and then assign it
Previously, if IPv4 ACD is enabled on an address, then we first assign the address, and start sd-ipv4acd daemon for the address. This is not only RFC incompliant, but also the address is always dropped, as the daemon always considers the address is conflicted. This commit makes networkd first starts sd-ipv4acd daemon to probe the address, and then the address is configured if no conflict is detected. Fixes systemd#17235.
1 parent 475ec33 commit 76a86ff

File tree

8 files changed

+326
-342
lines changed

8 files changed

+326
-342
lines changed

src/network/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ sources = files('''
7979
networkd-dhcp4.h
8080
networkd-dhcp6.c
8181
networkd-dhcp6.h
82+
networkd-ipv4acd.c
83+
networkd-ipv4acd.h
8284
networkd-ipv4ll.c
8385
networkd-ipv4ll.h
8486
networkd-ipv6-proxy-ndp.c

src/network/networkd-address.c

Lines changed: 9 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "netlink-util.h"
1010
#include "networkd-address-pool.h"
1111
#include "networkd-address.h"
12+
#include "networkd-ipv4acd.h"
1213
#include "networkd-manager.h"
1314
#include "networkd-network.h"
1415
#include "networkd-queue.h"
@@ -129,6 +130,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
129130

130131
address->network = network;
131132
address->section = TAKE_PTR(n);
133+
address->is_static = true;
132134

133135
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
134136
if (r < 0)
@@ -152,6 +154,7 @@ Address *address_free(Address *address) {
152154

153155
set_remove(address->link->addresses, address);
154156
set_remove(address->link->addresses_foreign, address);
157+
set_remove(address->link->addresses_ipv4acd, address);
155158
set_remove(address->link->static_addresses, address);
156159
if (address->link->dhcp_address == address)
157160
address->link->dhcp_address = NULL;
@@ -994,8 +997,6 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m,
994997
return 1;
995998
}
996999

997-
static int ipv4_dad_configure(Address *address);
998-
9991000
static int address_configure(
10001001
const Address *address,
10011002
Link *link,
@@ -1242,6 +1243,12 @@ static int address_is_ready_to_configure(Link *link, const Address *address) {
12421243
return log_link_warning_errno(link, SYNTHETIC_ERRNO(E2BIG),
12431244
"Too many addresses are configured, refusing: %m");
12441245

1246+
if (address->family == AF_INET &&
1247+
address->duplicate_address_detection & ADDRESS_FAMILY_IPV4 &&
1248+
link->hw_addr.length == ETH_ALEN &&
1249+
!ether_addr_is_null(&link->hw_addr.ether))
1250+
return ipv4acd_address_is_ready_to_configure(link, address);
1251+
12451252
r = address_add(link, address, NULL);
12461253
if (r < 0)
12471254
return log_link_warning_errno(link, r, "Could not add address: %m");;
@@ -1286,12 +1293,6 @@ int request_process_address(Request *req) {
12861293
if (r < 0)
12871294
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
12881295

1289-
if (FLAGS_SET(a->duplicate_address_detection, ADDRESS_FAMILY_IPV4)) {
1290-
r = ipv4_dad_configure(a);
1291-
if (r < 0)
1292-
log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
1293-
}
1294-
12951296
return 1;
12961297
}
12971298

@@ -1475,157 +1476,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
14751476
return 1;
14761477
}
14771478

1478-
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
1479-
Address *address;
1480-
Link *link;
1481-
int r;
1482-
1483-
assert(acd);
1484-
assert(userdata);
1485-
1486-
address = (Address *) userdata;
1487-
link = address->link;
1488-
1489-
assert(address->family == AF_INET);
1490-
1491-
switch (event) {
1492-
case SD_IPV4ACD_EVENT_STOP:
1493-
log_link_debug(link, "Stopping ACD client...");
1494-
return;
1495-
1496-
case SD_IPV4ACD_EVENT_BIND:
1497-
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
1498-
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
1499-
link_check_ready(link);
1500-
break;
1501-
1502-
case SD_IPV4ACD_EVENT_CONFLICT:
1503-
log_link_warning(link, "DAD conflict. Dropping address "IPV4_ADDRESS_FMT_STR,
1504-
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
1505-
r = address_remove(address, link);
1506-
if (r < 0)
1507-
log_link_error_errno(link, r, "Failed to drop DAD conflicted address "IPV4_ADDRESS_FMT_STR,
1508-
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
1509-
1510-
link_check_ready(link);
1511-
break;
1512-
1513-
default:
1514-
assert_not_reached("Invalid IPv4ACD event.");
1515-
}
1516-
1517-
(void) sd_ipv4acd_stop(acd);
1518-
1519-
return;
1520-
}
1521-
1522-
static int ipv4_dad_configure(Address *address) {
1523-
int r;
1524-
1525-
assert(address);
1526-
assert(address->link);
1527-
1528-
if (address->family != AF_INET)
1529-
return 0;
1530-
1531-
log_address_debug(address, "Starting IPv4ACD client. Probing", address->link);
1532-
1533-
if (!address->acd) {
1534-
r = sd_ipv4acd_new(&address->acd);
1535-
if (r < 0)
1536-
return r;
1537-
1538-
r = sd_ipv4acd_attach_event(address->acd, address->link->manager->event, 0);
1539-
if (r < 0)
1540-
return r;
1541-
}
1542-
1543-
r = sd_ipv4acd_set_ifindex(address->acd, address->link->ifindex);
1544-
if (r < 0)
1545-
return r;
1546-
1547-
r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.ether);
1548-
if (r < 0)
1549-
return r;
1550-
1551-
r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
1552-
if (r < 0)
1553-
return r;
1554-
1555-
r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
1556-
if (r < 0)
1557-
return r;
1558-
1559-
return sd_ipv4acd_start(address->acd, true);
1560-
}
1561-
1562-
static int ipv4_dad_update_mac_one(Address *address) {
1563-
bool running;
1564-
int r;
1565-
1566-
assert(address);
1567-
1568-
if (!address->acd)
1569-
return 0;
1570-
1571-
running = sd_ipv4acd_is_running(address->acd);
1572-
1573-
r = sd_ipv4acd_stop(address->acd);
1574-
if (r < 0)
1575-
return r;
1576-
1577-
r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.ether);
1578-
if (r < 0)
1579-
return r;
1580-
1581-
if (running) {
1582-
r = sd_ipv4acd_start(address->acd, true);
1583-
if (r < 0)
1584-
return r;
1585-
}
1586-
1587-
return 0;
1588-
}
1589-
1590-
int ipv4_dad_update_mac(Link *link) {
1591-
Address *address;
1592-
int k, r = 0;
1593-
1594-
assert(link);
1595-
1596-
SET_FOREACH(address, link->addresses) {
1597-
k = ipv4_dad_update_mac_one(address);
1598-
if (k < 0 && r >= 0)
1599-
r = k;
1600-
}
1601-
1602-
return r;
1603-
}
1604-
1605-
int ipv4_dad_stop(Link *link) {
1606-
Address *address;
1607-
int k, r = 0;
1608-
1609-
assert(link);
1610-
1611-
SET_FOREACH(address, link->addresses) {
1612-
k = sd_ipv4acd_stop(address->acd);
1613-
if (k < 0 && r >= 0)
1614-
r = k;
1615-
}
1616-
1617-
return r;
1618-
}
1619-
1620-
void ipv4_dad_unref(Link *link) {
1621-
Address *address;
1622-
1623-
assert(link);
1624-
1625-
SET_FOREACH(address, link->addresses)
1626-
address->acd = sd_ipv4acd_unref(address->acd);
1627-
}
1628-
16291479
int config_parse_broadcast(
16301480
const char *unit,
16311481
const char *filename,

src/network/networkd-address.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ typedef struct Address {
4141

4242
bool scope_set:1;
4343
bool ip_masquerade_done:1;
44+
bool is_static:1; /* currently only used by IPv4ACD */
45+
bool acd_announced:1;
4446
AddressFamily duplicate_address_detection;
47+
sd_ipv4acd *acd;
4548

4649
/* Called when address become ready */
4750
address_ready_callback_t callback;
48-
49-
sd_ipv4acd *acd;
5051
} Address;
5152

5253
int address_new(Address **ret);
@@ -71,10 +72,6 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
7172
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);
7273
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
7374

74-
void ipv4_dad_unref(Link *link);
75-
int ipv4_dad_stop(Link *link);
76-
int ipv4_dad_update_mac(Link *link);
77-
7875
int link_request_address(
7976
Link *link,
8077
Address *address,

0 commit comments

Comments
 (0)
X Tutup