1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-28 02:50:16 +03:00

Merge pull request #28572 from yuwata/network-ipv4acd

network: split-out sd_ipv4acd object management from Address object
This commit is contained in:
Yu Watanabe 2023-07-31 00:58:54 +09:00 committed by GitHub
commit 8b52860b86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 100 deletions

View File

@ -195,6 +195,16 @@ extern const struct hash_ops in_addr_data_hash_ops_free;
extern const struct hash_ops in6_addr_hash_ops;
extern const struct hash_ops in6_addr_hash_ops_free;
static inline void PTR_TO_IN4_ADDR(const void *p, struct in_addr *ret) {
assert(ret);
ret->s_addr = (uint32_t) ((uintptr_t) p);
}
static inline void* IN4_ADDR_TO_PTR(const struct in_addr *a) {
assert(a);
return (void*) ((uintptr_t) a->s_addr);
}
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
#define IPV4_ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \

View File

@ -569,6 +569,12 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
return acd->state != IPV4ACD_STATE_INIT;
}
int sd_ipv4acd_is_bound(sd_ipv4acd *acd) {
assert_return(acd, false);
return IN_SET(acd->state, IPV4ACD_STATE_ANNOUNCING, IPV4ACD_STATE_RUNNING);
}
int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) {
int r;

View File

@ -133,9 +133,9 @@ Address *address_free(Address *address) {
if (address->family == AF_INET6 &&
in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address))
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
}
sd_ipv4acd_unref(address->acd);
ipv4acd_detach(address->link, address);
}
config_section_free(address->section);
free(address->label);
@ -153,8 +153,9 @@ static bool address_lifetime_is_valid(const Address *a) {
bool address_is_ready(const Address *a) {
assert(a);
assert(a->link);
if (!ipv4acd_bound(a))
if (!ipv4acd_bound(a->link, a))
return false;
if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
@ -476,7 +477,6 @@ int address_dup(const Address *src, Address **ret) {
dest->section = NULL;
dest->link = NULL;
dest->label = NULL;
dest->acd = NULL;
dest->netlabel = NULL;
if (src->family == AF_INET) {
@ -1231,7 +1231,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) {
if (!link_is_ready_to_configure(link, false))
return false;
if (!ipv4acd_bound(address))
if (!ipv4acd_bound(link, address))
return false;
/* Refuse adding more than the limit */
@ -1322,7 +1322,7 @@ int link_request_address(
existing->lifetime_preferred_usec = address->lifetime_preferred_usec;
}
r = ipv4acd_configure(existing);
r = ipv4acd_configure(link, existing);
if (r < 0)
return r;

View File

@ -5,8 +5,6 @@
#include <stdbool.h>
#include <stdio.h>
#include "sd-ipv4acd.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "networkd-link.h"
@ -58,8 +56,6 @@ struct Address {
/* duplicate_address_detection is only used by static or IPv4 dynamic addresses.
* To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
AddressFamily duplicate_address_detection;
sd_ipv4acd *acd;
bool acd_bound;
/* Called when address become ready */
address_ready_callback_t callback;

View File

@ -13,6 +13,11 @@
#include "networkd-link.h"
#include "networkd-manager.h"
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
ipv4acd_hash_ops,
void, trivial_hash_func, trivial_compare_func,
sd_ipv4acd, sd_ipv4acd_unref);
bool link_ipv4acd_supported(Link *link) {
assert(link);
@ -40,9 +45,9 @@ bool link_ipv4acd_supported(Link *link) {
return true;
}
static bool address_ipv4acd_enabled(Address *address) {
static bool address_ipv4acd_enabled(Link *link, const Address *address) {
assert(link);
assert(address);
assert(address->link);
if (address->family != AF_INET)
return false;
@ -54,19 +59,23 @@ static bool address_ipv4acd_enabled(Address *address) {
if (!IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4))
return false;
if (!link_ipv4acd_supported(address->link))
return false;
return true;
return link_ipv4acd_supported(link);
}
bool ipv4acd_bound(const Address *address) {
bool ipv4acd_bound(Link *link, const Address *address) {
sd_ipv4acd *acd;
assert(link);
assert(address);
if (!address->acd)
if (address->family != AF_INET)
return true;
return address->acd_bound;
acd = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in));
if (!acd)
return true;
return sd_ipv4acd_is_bound(acd) > 0;
}
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
@ -79,21 +88,18 @@ static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_c
return 0; /* Not assigned. */
if (on_conflict)
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
log_link_warning(link, "Dropping address %s, as an address conflict was detected.", IN4_ADDR_TO_STRING(&address->in_addr.in));
else
log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
log_link_debug(link, "Removing address %s, as the ACD client is stopped.", IN4_ADDR_TO_STRING(&address->in_addr.in));
r = address_remove(address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return log_link_warning_errno(link, r, "Failed to remove address %s: %m", IN4_ADDR_TO_STRING(&address->in_addr.in));
return 0;
}
static int dhcp4_address_on_conflict(Link *link, Address *address) {
static int dhcp4_address_on_conflict(Link *link) {
int r;
assert(link);
@ -117,21 +123,25 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
}
static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
Address *address = ASSERT_PTR(userdata);
Link *link;
Link *link = ASSERT_PTR(userdata);
Address *address = NULL;
struct in_addr a;
int r;
assert(acd);
assert(address->acd == acd);
assert(address->link);
assert(address->family == AF_INET);
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
link = address->link;
r = sd_ipv4acd_get_address(acd, &a);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to get address from IPv4ACD: %m");
link_enter_failed(link);
}
(void) link_get_ipv4_address(link, &a, 0, &address);
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
address->acd_bound = false;
if (!address)
break;
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
@ -144,22 +154,19 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
break;
case SD_IPV4ACD_EVENT_BIND:
address->acd_bound = true;
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
log_link_debug(link, "Successfully claimed address %s", IN4_ADDR_TO_STRING(&a));
break;
case SD_IPV4ACD_EVENT_CONFLICT:
address->acd_bound = false;
if (!address)
break;
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
log_link_warning(link, "Dropping address %s, as an address conflict was detected.", IN4_ADDR_TO_STRING(&a));
if (address->source == NETWORK_CONFIG_SOURCE_STATIC)
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ true);
else
r = dhcp4_address_on_conflict(link, address);
r = dhcp4_address_on_conflict(link);
if (r < 0)
link_enter_failed(link);
break;
@ -183,76 +190,89 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
static int address_ipv4acd_start(Address *address) {
assert(address);
assert(address->link);
static int ipv4acd_start_one(Link *link, sd_ipv4acd *acd) {
assert(link);
assert(acd);
if (!address->acd)
if (sd_ipv4acd_is_running(acd))
return 0;
if (sd_ipv4acd_is_running(address->acd))
if (!link_has_carrier(link))
return 0;
if (!link_has_carrier(address->link))
return 0;
return sd_ipv4acd_start(address->acd, true);
return sd_ipv4acd_start(acd, /* reset_conflicts = */ true);
}
int ipv4acd_configure(Address *address) {
Link *link;
int ipv4acd_configure(Link *link, const Address *address) {
_cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL;
sd_ipv4acd *existing;
int r;
assert(link);
assert(link->manager);
assert(address);
link = ASSERT_PTR(address->link);
if (!address_ipv4acd_enabled(address)) {
address->acd = sd_ipv4acd_unref(address->acd);
address->acd_bound = false;
if (address->family != AF_INET)
return 0;
}
if (address->acd)
return address_ipv4acd_start(address);
existing = hashmap_get(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in));
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
if (!address_ipv4acd_enabled(link, address))
return sd_ipv4acd_stop(existing);
r = sd_ipv4acd_new(&address->acd);
if (existing)
return ipv4acd_start_one(link, existing);
log_link_debug(link, "Configuring IPv4ACD for address %s.", IN4_ADDR_TO_STRING(&address->in_addr.in));
r = sd_ipv4acd_new(&acd);
if (r < 0)
return r;
r = sd_ipv4acd_attach_event(address->acd, link->manager->event, 0);
r = sd_ipv4acd_attach_event(acd, link->manager->event, 0);
if (r < 0)
return r;
r = sd_ipv4acd_set_ifindex(address->acd, link->ifindex);
r = sd_ipv4acd_set_ifindex(acd, link->ifindex);
if (r < 0)
return r;
r = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
r = sd_ipv4acd_set_mac(acd, &link->hw_addr.ether);
if (r < 0)
return r;
r = sd_ipv4acd_set_address(address->acd, &address->in_addr.in);
r = sd_ipv4acd_set_address(acd, &address->in_addr.in);
if (r < 0)
return r;
r = sd_ipv4acd_set_callback(address->acd, on_acd, address);
r = sd_ipv4acd_set_callback(acd, on_acd, link);
if (r < 0)
return r;
r = sd_ipv4acd_set_check_mac_callback(address->acd, ipv4acd_check_mac, link->manager);
r = sd_ipv4acd_set_check_mac_callback(acd, ipv4acd_check_mac, link->manager);
if (r < 0)
return r;
return address_ipv4acd_start(address);
r = hashmap_ensure_put(&link->ipv4acd_by_address, &ipv4acd_hash_ops, IN4_ADDR_TO_PTR(&address->in_addr.in), acd);
if (r < 0)
return r;
return ipv4acd_start_one(link, TAKE_PTR(acd));
}
void ipv4acd_detach(Link *link, const Address *address) {
assert(link);
assert(address);
if (address->family != AF_INET)
return;
sd_ipv4acd_unref(hashmap_remove(link->ipv4acd_by_address, IN4_ADDR_TO_PTR(&address->in_addr.in)));
}
int ipv4acd_update_mac(Link *link) {
Address *address;
int k, r = 0;
sd_ipv4acd *acd;
int r;
assert(link);
@ -261,28 +281,23 @@ int ipv4acd_update_mac(Link *link) {
if (ether_addr_is_null(&link->hw_addr.ether))
return 0;
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
if (k < 0)
r = k;
HASHMAP_FOREACH(acd, link->ipv4acd_by_address) {
r = sd_ipv4acd_set_mac(acd, &link->hw_addr.ether);
if (r < 0)
return r;
}
if (r < 0)
link_enter_failed(link);
return r;
return 0;
}
int ipv4acd_start(Link *link) {
Address *address;
sd_ipv4acd *acd;
int r;
assert(link);
SET_FOREACH(address, link->addresses) {
r = address_ipv4acd_start(address);
HASHMAP_FOREACH(acd, link->ipv4acd_by_address) {
r = ipv4acd_start_one(link, acd);
if (r < 0)
return r;
}
@ -291,16 +306,13 @@ int ipv4acd_start(Link *link) {
}
int ipv4acd_stop(Link *link) {
Address *address;
sd_ipv4acd *acd;
int k, r = 0;
assert(link);
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
k = sd_ipv4acd_stop(address->acd);
HASHMAP_FOREACH(acd, link->ipv4acd_by_address) {
k = sd_ipv4acd_stop(acd);
if (k < 0)
r = k;
}
@ -309,16 +321,13 @@ int ipv4acd_stop(Link *link) {
}
int ipv4acd_set_ifname(Link *link) {
Address *address;
sd_ipv4acd *acd;
int r;
assert(link);
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
r = sd_ipv4acd_set_ifname(address->acd, link->ifname);
HASHMAP_FOREACH(acd, link->ipv4acd_by_address) {
r = sd_ipv4acd_set_ifname(acd, link->ifname);
if (r < 0)
return r;
}

View File

@ -5,8 +5,9 @@ typedef struct Address Address;
typedef struct Link Link;
bool link_ipv4acd_supported(Link *link);
bool ipv4acd_bound(const Address *address);
int ipv4acd_configure(Address *address);
bool ipv4acd_bound(Link *link, const Address *address);
int ipv4acd_configure(Link *link, const Address *address);
void ipv4acd_detach(Link *link, const Address *address);
int ipv4acd_update_mac(Link *link);
int ipv4acd_start(Link *link);
int ipv4acd_stop(Link *link);

View File

@ -160,6 +160,8 @@ static void link_free_engines(Link *link) {
link->lldp_rx = sd_lldp_rx_unref(link->lldp_rx);
link->lldp_tx = sd_lldp_tx_unref(link->lldp_tx);
link->ipv4acd_by_address = hashmap_free(link->ipv4acd_by_address);
link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll);
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);

View File

@ -130,6 +130,8 @@ typedef struct Link {
bool dhcp4_configured:1;
char *dhcp4_6rd_tunnel_name;
Hashmap *ipv4acd_by_address;
sd_ipv4ll *ipv4ll;
bool ipv4ll_address_configured:1;

View File

@ -50,6 +50,7 @@ int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *interface_name);
int sd_ipv4acd_get_ifname(sd_ipv4acd *acd, const char **ret);
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
int sd_ipv4acd_is_bound(sd_ipv4acd *acd);
__extension__ int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts);
int sd_ipv4acd_stop(sd_ipv4acd *acd);
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd);