summaryrefslogtreecommitdiff
path: root/src/network/networkd-address.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-address.c')
-rw-r--r--src/network/networkd-address.c152
1 files changed, 147 insertions, 5 deletions
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 2810a6420e..23a970a13f 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -32,6 +32,7 @@ int address_new(Address **ret) {
.scope = RT_SCOPE_UNIVERSE,
.cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME,
.cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME,
+ .duplicate_address_detection = ADDRESS_FAMILY_IPV6,
};
*ret = TAKE_PTR(address);
@@ -102,7 +103,7 @@ void address_free(Address *address) {
hashmap_remove(address->network->addresses_by_section, address->section);
}
- if (address->link) {
+ if (address->link && !address->acd) {
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
@@ -110,6 +111,8 @@ void address_free(Address *address) {
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
}
+ sd_ipv4acd_unref(address->acd);
+
network_config_section_free(address->section);
free(address->label);
free(address);
@@ -587,7 +590,7 @@ int address_configure(
if (address->home_address)
address->flags |= IFA_F_HOMEADDRESS;
- if (address->duplicate_address_detection)
+ if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6))
address->flags |= IFA_F_NODAD;
if (address->manage_temporary_address)
@@ -658,9 +661,101 @@ int address_configure(
return log_link_error_errno(link, r, "Could not add address: %m");
}
+ if (address->acd) {
+ assert(address->family == AF_INET);
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *pretty = NULL;
+
+ (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
+ log_debug("Starting IPv4ACD client. Probing address %s", strna(pretty));
+ }
+
+ r = sd_ipv4acd_start(address->acd);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to start IPv4ACD client, ignoring: %m");
+ }
+
return 1;
}
+static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+ _cleanup_free_ char *pretty = NULL;
+ Address *address;
+ Link *link;
+ int r;
+
+ assert(acd);
+ assert(userdata);
+
+ address = (Address *) userdata;
+ link = address->link;
+
+ (void) in_addr_to_string(address->family, &address->in_addr, &pretty);
+ switch (event) {
+ case SD_IPV4ACD_EVENT_STOP:
+ log_link_debug(link, "Stopping ACD client...");
+ return;
+
+ case SD_IPV4ACD_EVENT_BIND:
+ log_link_debug(link, "Successfully claimed address %s", strna(pretty));
+ link_check_ready(link);
+ break;
+
+ case SD_IPV4ACD_EVENT_CONFLICT:
+ log_link_warning(link, "DAD conflict. Dropping address %s", strna(pretty));
+ r = address_remove(address, link, NULL);
+ if (r < 0)
+ log_link_error_errno(link, r, "Failed to drop DAD conflicted address %s", strna(pretty));;
+
+ link_check_ready(link);
+ break;
+
+ default:
+ assert_not_reached("Invalid IPv4ACD event.");
+ }
+
+ sd_ipv4acd_stop(acd);
+
+ return;
+}
+
+int configure_ipv4_duplicate_address_detection(Link *link, Address *address) {
+ int r;
+
+ assert(link);
+ assert(address);
+ assert(address->family == AF_INET);
+ assert(!address->link && address->network);
+
+ address->link = link;
+
+ r = sd_ipv4acd_new(&address->acd);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_attach_event(address->acd, NULL, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_mac(address->acd, &link->mac);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
+ if (r < 0)
+ return r;
+
+ r = sd_ipv4acd_set_callback(address->acd, static_address_on_acd, address);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int config_parse_broadcast(
const char *unit,
const char *filename,
@@ -897,14 +992,12 @@ int config_parse_address_flags(const char *unit,
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse address flag, ignoring: %s", rvalue);
+ "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
return 0;
}
if (streq(lvalue, "HomeAddress"))
n->home_address = r;
- else if (streq(lvalue, "DuplicateAddressDetection"))
- n->duplicate_address_detection = r;
else if (streq(lvalue, "ManageTemporaryAddress"))
n->manage_temporary_address = r;
else if (streq(lvalue, "PrefixRoute"))
@@ -961,6 +1054,55 @@ int config_parse_address_scope(const char *unit,
return 0;
}
+int config_parse_duplicate_address_detection(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Network *network = userdata;
+ _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
+ AddressFamily a;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = address_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(rvalue);
+ if (r >= 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "For historical reasons, %s=%s means %s=%s. "
+ "Please use 'both', 'ipv4', 'ipv6' or 'none' instead.",
+ lvalue, rvalue, lvalue, r ? "none" : "both");
+ n->duplicate_address_detection = r ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_YES;
+ n = NULL;
+ return 0;
+ }
+
+ a = duplicate_address_detection_address_family_from_string(rvalue);
+ if (a < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ n->duplicate_address_detection = a;
+ n = NULL;
+ return 0;
+}
+
bool address_is_ready(const Address *a) {
assert(a);