network: introduce link_set_addresses()

This commit is contained in:
Yu Watanabe 2020-10-02 11:17:49 +09:00
parent e2263711ba
commit 682c65b04c
3 changed files with 180 additions and 165 deletions

View File

@ -747,6 +747,177 @@ int address_configure(
return 1;
}
static int static_address_ready_callback(Address *address) {
Address *a;
Link *link;
assert(address);
assert(address->link);
link = address->link;
if (!link->addresses_configured)
return 0;
SET_FOREACH(a, link->static_addresses)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(a->family, &a->in_addr, &str);
log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
return 0;
}
/* This should not be called again */
SET_FOREACH(a, link->static_addresses)
a->callback = NULL;
link->addresses_ready = true;
return link_set_routes(link);
}
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->address_messages > 0);
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
LINK_STATE_FAILED, LINK_STATE_LINGER));
link->address_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_messages == 0) {
Address *a;
log_link_debug(link, "Addresses set");
link->addresses_configured = true;
/* When all static addresses are already ready, then static_address_ready_callback()
* will not be called automatically. So, call it here. */
a = set_first(link->static_addresses);
if (!a) {
log_link_warning(link, "No static address is stored.");
link_enter_failed(link);
return 1;
}
if (!a->callback) {
log_link_warning(link, "Address ready callback is not set.");
link_enter_failed(link);
return 1;
}
r = a->callback(a);
if (r < 0)
link_enter_failed(link);
}
return 1;
}
static int static_address_configure(Address *address, Link *link, bool update) {
Address *ret;
int r;
assert(address);
assert(link);
r = address_configure(address, link, address_handler, update, &ret);
if (r < 0)
return log_link_warning_errno(link, r, "Could not configure static address: %m");
link->address_messages++;
r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store static address: %m");
ret->callback = static_address_ready_callback;
return 0;
}
int link_set_addresses(Link *link) {
Address *ad;
int r;
assert(link);
assert(link->network);
if (link->address_remove_messages != 0) {
log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
link->request_static_addresses = true;
return 0;
}
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
bool update;
if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
else
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
r = static_address_configure(ad, link, update);
if (r < 0)
return r;
}
if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
Prefix *p;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
_cleanup_(address_freep) Address *address = NULL;
if (!p->assign)
continue;
r = address_new(&address);
if (r < 0)
return log_oom();
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
if (r < 0)
return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
address->family = AF_INET6;
r = static_address_configure(address, link, true);
if (r < 0)
return r;
}
}
if (link->address_messages == 0) {
link->addresses_configured = true;
link->addresses_ready = true;
r = link_set_routes(link);
if (r < 0)
return r;
} else {
log_link_debug(link, "Setting addresses");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
_cleanup_free_ char *pretty = NULL;
Address *address;

View File

@ -75,6 +75,8 @@ int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
int link_set_addresses(Link *link);
void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops;

View File

@ -1051,123 +1051,13 @@ void link_check_ready(Link *link) {
return;
}
static int static_address_ready_callback(Address *address) {
Address *a;
Link *link;
assert(address);
assert(address->link);
link = address->link;
if (!link->addresses_configured)
return 0;
SET_FOREACH(a, link->static_addresses)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(a->family, &a->in_addr, &str);
log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen);
return 0;
}
/* This should not be called again */
SET_FOREACH(a, link->static_addresses)
a->callback = NULL;
link->addresses_ready = true;
return link_set_routes(link);
}
static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->ifname);
assert(link->address_messages > 0);
assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
LINK_STATE_FAILED, LINK_STATE_LINGER));
link->address_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
log_link_message_warning_errno(link, m, r, "Could not set address");
link_enter_failed(link);
return 1;
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_messages == 0) {
Address *a;
log_link_debug(link, "Addresses set");
link->addresses_configured = true;
/* When all static addresses are already ready, then static_address_ready_callback()
* will not be called automatically. So, call it here. */
a = set_first(link->static_addresses);
if (!a) {
log_link_warning(link, "No static address is stored.");
link_enter_failed(link);
return 1;
}
if (!a->callback) {
log_link_warning(link, "Address ready callback is not set.");
link_enter_failed(link);
return 1;
}
r = a->callback(a);
if (r < 0)
link_enter_failed(link);
}
return 1;
}
static int static_address_configure(Address *address, Link *link, bool update) {
Address *ret;
int r;
assert(address);
assert(link);
r = address_configure(address, link, address_handler, update, &ret);
if (r < 0)
return log_link_warning_errno(link, r, "Could not configure static address: %m");
link->address_messages++;
r = set_ensure_put(&link->static_addresses, &address_hash_ops, ret);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store static address: %m");
ret->callback = static_address_ready_callback;
return 0;
}
static int link_request_set_addresses(Link *link) {
Address *ad;
static int link_set_static_configs(Link *link) {
int r;
assert(link);
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
if (link->address_remove_messages != 0) {
log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
link->request_static_addresses = true;
return 0;
}
/* Reset all *_configured flags we are configuring. */
link->request_static_addresses = false;
link->addresses_configured = false;
@ -1189,46 +1079,9 @@ static int link_request_set_addresses(Link *link) {
if (r < 0)
return r;
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
bool update;
if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
else
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
r = static_address_configure(ad, link, update);
if (r < 0)
return r;
}
if (link->network->router_prefix_delegation & RADV_PREFIX_DELEGATION_STATIC) {
Prefix *p;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
_cleanup_(address_freep) Address *address = NULL;
if (!p->assign)
continue;
r = address_new(&address);
if (r < 0)
return log_oom();
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
if (r < 0)
return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
address->family = AF_INET6;
r = static_address_configure(address, link, true);
if (r < 0)
return r;
}
}
r = link_set_addresses(link);
if (r < 0)
return r;
r = link_set_address_labels(link);
if (r < 0)
@ -1242,17 +1095,6 @@ static int link_request_set_addresses(Link *link) {
log_link_debug(link, "Offering DHCPv4 leases");
}
if (link->address_messages == 0) {
link->addresses_configured = true;
link->addresses_ready = true;
r = link_set_routes(link);
if (r < 0)
return r;
} else {
log_link_debug(link, "Setting addresses");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
@ -2165,7 +2007,7 @@ static int link_joined(Link *link) {
return 0;
link_set_state(link, LINK_STATE_CONFIGURING);
return link_request_set_addresses(link);
return link_set_static_configs(link);
}
static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@ -2627,7 +2469,7 @@ static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m
if (link->address_remove_messages == 0 && link->request_static_addresses) {
link_set_state(link, LINK_STATE_CONFIGURING);
r = link_request_set_addresses(link);
r = link_set_addresses(link);
if (r < 0)
link_enter_failed(link);
}
@ -3555,7 +3397,7 @@ static int link_carrier_gained(Link *link) {
}
link_set_state(link, LINK_STATE_CONFIGURING);
r = link_request_set_addresses(link);
r = link_set_static_configs(link);
if (r < 0)
return r;
}