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:
commit
8b52860b86
@ -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, \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user