mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-25 23:21:33 +03:00
Merge pull request #20226 from yuwata/network-introduce-source-and-status
network: introduce NetworkConfigSource and NetworkConfigState
This commit is contained in:
commit
ca6bc7ce0d
@ -285,10 +285,6 @@ static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_u
|
||||
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
|
||||
return 1;
|
||||
|
||||
SET_FOREACH(a, link->addresses_foreign)
|
||||
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
|
||||
return 1;
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
|
@ -106,24 +106,6 @@ static bool address_pool_prefix_is_taken(
|
||||
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Don't clash with assigned foreign addresses */
|
||||
SET_FOREACH(a, l->addresses_foreign) {
|
||||
if (a->family != p->family)
|
||||
continue;
|
||||
|
||||
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Don't clash with addresses already pulled from the pool, but not assigned yet */
|
||||
SET_FOREACH(a, l->pool_addresses) {
|
||||
if (a->family != p->family)
|
||||
continue;
|
||||
|
||||
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* And don't clash with configured but un-assigned addresses either */
|
||||
|
@ -9,10 +9,12 @@
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-address-pool.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-dhcp-server.h"
|
||||
#include "networkd-ipv4acd.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -131,7 +133,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
|
||||
|
||||
address->network = network;
|
||||
address->section = TAKE_PTR(n);
|
||||
address->is_static = true;
|
||||
address->source = NETWORK_CONFIG_SOURCE_STATIC;
|
||||
|
||||
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
|
||||
if (r < 0)
|
||||
@ -151,23 +153,7 @@ Address *address_free(Address *address) {
|
||||
}
|
||||
|
||||
if (address->link) {
|
||||
NDiscAddress *n;
|
||||
|
||||
set_remove(address->link->addresses, address);
|
||||
set_remove(address->link->addresses_foreign, address);
|
||||
set_remove(address->link->addresses_ipv4acd, address);
|
||||
set_remove(address->link->static_addresses, address);
|
||||
if (address->link->dhcp_address == address)
|
||||
address->link->dhcp_address = NULL;
|
||||
if (address->link->dhcp_address_old == address)
|
||||
address->link->dhcp_address_old = NULL;
|
||||
set_remove(address->link->dhcp6_addresses, address);
|
||||
set_remove(address->link->dhcp6_addresses_old, address);
|
||||
set_remove(address->link->dhcp6_pd_addresses, address);
|
||||
set_remove(address->link->dhcp6_pd_addresses_old, address);
|
||||
SET_FOREACH(n, address->link->ndisc_addresses)
|
||||
if (address_equal(n->address, address))
|
||||
free(set_remove(address->link->ndisc_addresses, n));
|
||||
|
||||
if (address->family == AF_INET6 &&
|
||||
in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address))
|
||||
@ -181,6 +167,41 @@ Address *address_free(Address *address) {
|
||||
return mfree(address);
|
||||
}
|
||||
|
||||
bool address_is_ready(const Address *a) {
|
||||
assert(a);
|
||||
|
||||
if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
|
||||
return false;
|
||||
|
||||
if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router) {
|
||||
Address *a;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (a->source != source)
|
||||
continue;
|
||||
|
||||
if (source == NETWORK_CONFIG_SOURCE_NDISC &&
|
||||
router && !in6_addr_equal(router, &a->provider.in6))
|
||||
continue;
|
||||
|
||||
address_mark(a);
|
||||
}
|
||||
}
|
||||
|
||||
static bool address_may_have_broadcast(const Address *a) {
|
||||
assert(a);
|
||||
|
||||
@ -295,16 +316,6 @@ int address_compare_func(const Address *a1, const Address *a2) {
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
|
||||
|
||||
bool address_equal(const Address *a1, const Address *a2) {
|
||||
if (a1 == a2)
|
||||
return true;
|
||||
|
||||
if (!a1 || !a2)
|
||||
return false;
|
||||
|
||||
return address_compare_func(a1, a2) == 0;
|
||||
}
|
||||
|
||||
int address_dup(const Address *src, Address **ret) {
|
||||
_cleanup_(address_freep) Address *dest = NULL;
|
||||
int r;
|
||||
@ -371,67 +382,19 @@ static int address_set_masquerade(Address *address, bool add) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int address_add_internal(Link *link, Set **addresses, const Address *in, Address **ret) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
static int address_add(Link *link, Address *address) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(addresses);
|
||||
assert(in);
|
||||
assert(address);
|
||||
|
||||
r = address_dup(in, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Consider address tentative until we get the real flags from the kernel */
|
||||
address->flags |= IFA_F_TENTATIVE;
|
||||
|
||||
r = set_ensure_put(addresses, &address_hash_ops, address);
|
||||
r = set_ensure_put(&link->addresses, &address_hash_ops, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EEXIST;
|
||||
|
||||
address->link = link;
|
||||
|
||||
if (ret)
|
||||
*ret = address;
|
||||
TAKE_PTR(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int address_add_foreign(Link *link, const Address *in, Address **ret) {
|
||||
return address_add_internal(link, &link->addresses_foreign, in, ret);
|
||||
}
|
||||
|
||||
static int address_add(Link *link, const Address *in, Address **ret) {
|
||||
Address *address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(in);
|
||||
|
||||
r = address_get(link, in, &address);
|
||||
if (r == -ENOENT) {
|
||||
/* Address does not exist, create a new one */
|
||||
r = address_add_internal(link, &link->addresses, in, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
/* Take over a foreign address */
|
||||
r = set_ensure_put(&link->addresses, &address_hash_ops, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
set_remove(link->addresses_foreign, address);
|
||||
} else if (r == 1) {
|
||||
/* Already exists, do nothing */
|
||||
;
|
||||
} else
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -441,13 +404,13 @@ static int address_update(Address *address, const Address *src) {
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
assert(src);
|
||||
|
||||
link = address->link;
|
||||
|
||||
if (src) {
|
||||
address->flags = src->flags;
|
||||
address->scope = src->scope;
|
||||
address->cinfo = src->cinfo;
|
||||
}
|
||||
|
||||
if (address_is_ready(address) &&
|
||||
address->family == AF_INET6 &&
|
||||
@ -484,8 +447,8 @@ static int address_drop(Address *address) {
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
if (!address)
|
||||
return 0;
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
ready = address_is_ready(address);
|
||||
link = address->link;
|
||||
@ -494,6 +457,7 @@ static int address_drop(Address *address) {
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
|
||||
|
||||
if (address->state == 0)
|
||||
address_free(address);
|
||||
|
||||
link_update_operstate(link, true);
|
||||
@ -511,22 +475,14 @@ int address_get(Link *link, const Address *in, Address **ret) {
|
||||
assert(in);
|
||||
|
||||
existing = set_get(link->addresses, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
}
|
||||
if (!existing)
|
||||
return -ENOENT;
|
||||
|
||||
existing = set_get(link->addresses_foreign, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret) {
|
||||
_cleanup_(address_freep) Address *a = NULL;
|
||||
int r;
|
||||
@ -546,27 +502,6 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
|
||||
return address_get(link, a, ret);
|
||||
}
|
||||
|
||||
static int addresses_get_ipv4_address(Set *addresses, const struct in_addr *address, Address **ret) {
|
||||
Address *a;
|
||||
|
||||
assert(address);
|
||||
|
||||
SET_FOREACH(a, addresses) {
|
||||
if (a->family != AF_INET)
|
||||
continue;
|
||||
|
||||
if (!in4_addr_equal(&a->in_addr.in, address))
|
||||
continue;
|
||||
|
||||
if (ret)
|
||||
*ret = a;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret) {
|
||||
int r;
|
||||
|
||||
@ -587,11 +522,24 @@ int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned ch
|
||||
a->prefixlen = prefixlen;
|
||||
|
||||
return address_get(link, a, ret);
|
||||
} else {
|
||||
Address *a;
|
||||
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (a->family != AF_INET)
|
||||
continue;
|
||||
|
||||
if (!in4_addr_equal(&a->in_addr.in, address))
|
||||
continue;
|
||||
|
||||
if (ret)
|
||||
*ret = a;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addresses_get_ipv4_address(link->addresses, address, ret) >= 0)
|
||||
return 0;
|
||||
return addresses_get_ipv4_address(link->addresses_foreign, address, ret);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
|
||||
@ -606,7 +554,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
|
||||
if (family == AF_INET) {
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
if (link_get_ipv4_address(link, &address->in, 0, &a) >= 0)
|
||||
return !check_ready || address_is_ready(a);
|
||||
return check_ready ? address_is_ready(a) : address_exists(a);
|
||||
} else {
|
||||
_cleanup_(address_freep) Address *tmp = NULL;
|
||||
|
||||
@ -619,7 +567,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||
if (address_get(link, tmp, &a) >= 0)
|
||||
return !check_ready || address_is_ready(a);
|
||||
return check_ready ? address_is_ready(a) : address_exists(a);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -639,7 +587,7 @@ const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) {
|
||||
}
|
||||
|
||||
static void log_address_debug(const Address *address, const char *str, const Link *link) {
|
||||
_cleanup_free_ char *addr = NULL, *peer = NULL, *flags_str = NULL;
|
||||
_cleanup_free_ char *state = NULL, *addr = NULL, *peer = NULL, *flags_str = NULL;
|
||||
|
||||
assert(address);
|
||||
assert(str);
|
||||
@ -648,14 +596,16 @@ static void log_address_debug(const Address *address, const char *str, const Lin
|
||||
if (!DEBUG_LOGGING)
|
||||
return;
|
||||
|
||||
(void) network_config_state_to_string_alloc(address->state, &state);
|
||||
(void) in_addr_to_string(address->family, &address->in_addr, &addr);
|
||||
if (in_addr_is_set(address->family, &address->in_addr_peer))
|
||||
(void) in_addr_to_string(address->family, &address->in_addr_peer, &peer);
|
||||
|
||||
(void) address_flags_to_string_alloc(address->flags, address->family, &flags_str);
|
||||
|
||||
log_link_debug(link, "%s address: %s%s%s/%u (valid %s, preferred %s), flags: %s",
|
||||
str, strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
|
||||
log_link_debug(link, "%s %s address (%s): %s%s%s/%u (valid %s, preferred %s), flags: %s",
|
||||
str, strna(network_config_source_to_string(address->source)), strna(state),
|
||||
strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
|
||||
FORMAT_LIFETIME(address->cinfo.ifa_valid),
|
||||
FORMAT_LIFETIME(address->cinfo.ifa_prefered),
|
||||
strna(flags_str));
|
||||
@ -698,12 +648,8 @@ static int address_set_netlink_message(const Address *address, sd_netlink_messag
|
||||
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(m);
|
||||
assert(link);
|
||||
assert(link->address_remove_messages > 0);
|
||||
|
||||
link->address_remove_messages--;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 0;
|
||||
@ -715,16 +661,19 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
||||
return 1;
|
||||
}
|
||||
|
||||
int address_remove(const Address *address, Link *link) {
|
||||
int address_remove(Address *address) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
assert(IN_SET(address->family, AF_INET, AF_INET6));
|
||||
assert(link);
|
||||
assert(link->ifindex > 0);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
assert(address->link);
|
||||
assert(address->link->ifindex > 0);
|
||||
assert(address->link->manager);
|
||||
assert(address->link->manager->rtnl);
|
||||
|
||||
link = address->link;
|
||||
|
||||
log_address_debug(address, "Removing", link);
|
||||
|
||||
@ -744,27 +693,11 @@ int address_remove(const Address *address, Link *link) {
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link);
|
||||
link->address_remove_messages++;
|
||||
|
||||
address_enter_removing(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool link_is_static_address_configured(const Link *link, const Address *address) {
|
||||
Address *net_address;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(net_address, link->network->addresses_by_section)
|
||||
if (address_equal(net_address, address))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool link_address_is_dynamic(const Link *link, const Address *address) {
|
||||
Route *route;
|
||||
|
||||
@ -777,7 +710,10 @@ bool link_address_is_dynamic(const Link *link, const Address *address) {
|
||||
/* Even when the address is leased from a DHCP server, networkd assign the address
|
||||
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
|
||||
* corresponding routes with RTPROT_DHCP. */
|
||||
SET_FOREACH(route, link->routes_foreign) {
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
if (route->protocol != RTPROT_DHCP)
|
||||
continue;
|
||||
|
||||
@ -821,6 +757,7 @@ int link_drop_ipv6ll_addresses(Link *link) {
|
||||
_cleanup_(address_freep) Address *a = NULL;
|
||||
unsigned char flags, prefixlen;
|
||||
struct in6_addr address;
|
||||
Address *existing;
|
||||
int ifindex;
|
||||
|
||||
/* NETLINK_GET_STRICT_CHK socket option is supported since kernel 4.20. To support
|
||||
@ -866,7 +803,15 @@ int link_drop_ipv6ll_addresses(Link *link) {
|
||||
a->prefixlen = prefixlen;
|
||||
a->flags = flags;
|
||||
|
||||
r = address_remove(a, link);
|
||||
if (address_get(link, a, &existing) < 0) {
|
||||
r = address_add(link, a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
existing = TAKE_PTR(a);
|
||||
}
|
||||
|
||||
r = address_remove(existing);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -879,63 +824,80 @@ int link_drop_foreign_addresses(Link *link) {
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
SET_FOREACH(address, link->addresses_foreign) {
|
||||
/* First, mark all addresses. */
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
|
||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||
continue;
|
||||
|
||||
/* Ignore addresses we configured. */
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
/* Ignore addresses not assigned yet or already removing. */
|
||||
if (!address_exists(address))
|
||||
continue;
|
||||
|
||||
if (link_address_is_dynamic(link, address)) {
|
||||
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
||||
continue;
|
||||
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
||||
continue;
|
||||
|
||||
if (link_is_static_address_configured(link, address)) {
|
||||
k = address_add(link, address, NULL);
|
||||
if (k < 0) {
|
||||
log_link_error_errno(link, k, "Failed to add address: %m");
|
||||
if (r >= 0)
|
||||
r = k;
|
||||
address_mark(address);
|
||||
}
|
||||
} else {
|
||||
k = address_remove(address, link);
|
||||
|
||||
/* Then, unmark requested addresses. */
|
||||
ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section) {
|
||||
Address *existing;
|
||||
|
||||
if (address_get(link, address, &existing) >= 0)
|
||||
address_unmark(existing);
|
||||
}
|
||||
|
||||
/* Finally, remove all marked addresses. */
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address_is_marked(address))
|
||||
continue;
|
||||
|
||||
k = address_remove(address);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_addresses(Link *link) {
|
||||
Address *address, *pool_address;
|
||||
Address *address;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
/* Ignore addresses not assigned yet or already removing. */
|
||||
if (!address_exists(address))
|
||||
continue;
|
||||
|
||||
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
|
||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||
continue;
|
||||
|
||||
k = address_remove(address, link);
|
||||
k = address_remove(address);
|
||||
if (k < 0 && r >= 0) {
|
||||
r = k;
|
||||
continue;
|
||||
}
|
||||
|
||||
SET_FOREACH(pool_address, link->pool_addresses)
|
||||
if (address_equal(address, pool_address))
|
||||
address_free(set_remove(link->pool_addresses, pool_address));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int address_acquire(Link *link, const Address *original, Address **ret) {
|
||||
union in_addr_union in_addr = IN_ADDR_NULL;
|
||||
_cleanup_(address_freep) Address *na = NULL;
|
||||
union in_addr_union in_addr;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -969,12 +931,6 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
|
||||
na->in_addr = in_addr;
|
||||
address_set_broadcast(na);
|
||||
|
||||
r = set_ensure_put(&link->pool_addresses, &address_hash_ops, na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EEXIST;
|
||||
|
||||
*ret = TAKE_PTR(na);
|
||||
return 1;
|
||||
}
|
||||
@ -1063,6 +1019,25 @@ static int address_configure(
|
||||
return 0;
|
||||
}
|
||||
|
||||
void address_cancel_request(Address *address) {
|
||||
Request req;
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
if (!address_is_requesting(address))
|
||||
return;
|
||||
|
||||
req = (Request) {
|
||||
.link = address->link,
|
||||
.type = REQUEST_TYPE_ADDRESS,
|
||||
.address = address,
|
||||
};
|
||||
|
||||
request_drop(ordered_set_get(address->link->manager->request_queue, &req));
|
||||
address_cancel_requesting(address);
|
||||
}
|
||||
|
||||
static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
@ -1084,25 +1059,6 @@ static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int static_address_after_configure(Request *req, void *object) {
|
||||
Address *address = object;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_ADDRESS);
|
||||
assert(address);
|
||||
|
||||
link = req->link;
|
||||
|
||||
r = set_ensure_put(&link->static_addresses, &address_hash_ops, address);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to store static address: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_request_address(
|
||||
Link *link,
|
||||
Address *address,
|
||||
@ -1111,50 +1067,72 @@ int link_request_address(
|
||||
link_netlink_message_handler_t netlink_handler,
|
||||
Request **ret) {
|
||||
|
||||
Address *acquired;
|
||||
Address *acquired, *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
assert(address->source != NETWORK_CONFIG_SOURCE_FOREIGN);
|
||||
|
||||
r = address_acquire(link, address, &acquired);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
|
||||
if (r > 0) {
|
||||
if (consume_object) {
|
||||
if (consume_object)
|
||||
address_free(address);
|
||||
consume_object = false; /* address from pool is already managed by Link. */
|
||||
}
|
||||
|
||||
address = acquired;
|
||||
consume_object = true;
|
||||
}
|
||||
|
||||
if (address_get(link, address, &existing) < 0) {
|
||||
_cleanup_(address_freep) Address *tmp = NULL;
|
||||
|
||||
r = address_dup(address, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Consider address tentative until we get the real flags from the kernel */
|
||||
tmp->flags |= IFA_F_TENTATIVE;
|
||||
|
||||
r = address_add(link, tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
existing = TAKE_PTR(tmp);
|
||||
} else {
|
||||
existing->source = address->source;
|
||||
existing->provider = address->provider;
|
||||
}
|
||||
|
||||
r = ipv4acd_configure(existing);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_address_debug(address, "Requesting", link);
|
||||
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
|
||||
message_counter, netlink_handler, ret);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to request address: %m");
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
address_enter_requesting(existing);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int link_request_static_address(Link *link, Address *address, bool consume) {
|
||||
Request *req;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
|
||||
|
||||
r = link_request_address(link, address, consume, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
req->after_configure = static_address_after_configure;
|
||||
return 0;
|
||||
return link_request_address(link, address, consume, &link->static_address_messages,
|
||||
static_address_handler, NULL);
|
||||
}
|
||||
|
||||
int link_request_static_addresses(Link *link) {
|
||||
Address *a;
|
||||
Prefix *p;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -1168,52 +1146,13 @@ int link_request_static_addresses(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
address->route_metric = p->route_metric;
|
||||
|
||||
r = link_request_static_address(link, TAKE_PTR(address), true);
|
||||
r = link_request_radv_addresses(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (in4_addr_is_set(&link->network->dhcp_server_address)) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
address->family = AF_INET;
|
||||
address->in_addr.in = link->network->dhcp_server_address;
|
||||
address->prefixlen = link->network->dhcp_server_address_prefixlen;
|
||||
address_set_broadcast(address);
|
||||
|
||||
/* The same address may be explicitly configured in [Address] or [Network] section.
|
||||
* Configure the DHCP server address only when it is not. */
|
||||
if (!link_is_static_address_configured(link, address)) {
|
||||
r = link_request_static_address(link, TAKE_PTR(address), true);
|
||||
r = link_request_dhcp_server_address(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (link->static_address_messages == 0) {
|
||||
link->static_addresses_configured = true;
|
||||
@ -1226,41 +1165,25 @@ int link_request_static_addresses(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int address_is_ready_to_configure(Link *link, const Address *address) {
|
||||
int r;
|
||||
|
||||
static bool address_is_ready_to_configure(Link *link, const Address *address) {
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
if (!link_is_ready_to_configure(link, false))
|
||||
return false;
|
||||
|
||||
if (link->address_remove_messages > 0)
|
||||
if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
|
||||
return false;
|
||||
|
||||
if (address_get(link, address, NULL) >= 0)
|
||||
return true;
|
||||
|
||||
/* If this is a new address, then refuse adding more than the limit */
|
||||
/* Refuse adding more than the limit */
|
||||
if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
|
||||
return log_link_warning_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||
"Too many addresses are configured, refusing: %m");
|
||||
|
||||
if (address->family == AF_INET &&
|
||||
address->duplicate_address_detection & ADDRESS_FAMILY_IPV4 &&
|
||||
link->hw_addr.length == ETH_ALEN &&
|
||||
!ether_addr_is_null(&link->hw_addr.ether))
|
||||
return ipv4acd_address_is_ready_to_configure(link, address);
|
||||
|
||||
r = address_add(link, address, NULL);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not add address: %m");;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int request_process_address(Request *req) {
|
||||
Address *a;
|
||||
Address *existing;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
@ -1271,26 +1194,18 @@ int request_process_address(Request *req) {
|
||||
|
||||
link = req->link;
|
||||
|
||||
r = address_is_ready_to_configure(link, req->address);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
r = address_get(link, req->address, &existing);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to get address: %m");
|
||||
|
||||
if (!address_is_ready_to_configure(link, existing))
|
||||
return 0;
|
||||
|
||||
r = address_configure(req->address, link, req->netlink_handler);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_link_warning_errno(link, r, "Failed to configure address: %m");
|
||||
|
||||
/* To prevent a double decrement on failure in after_configure(). */
|
||||
req->message_counter = NULL;
|
||||
|
||||
r = address_get(link, req->address, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (req->after_configure) {
|
||||
r = req->after_configure(req, a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
address_enter_configuring(existing);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1441,10 +1356,14 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWADDR:
|
||||
log_address_debug(tmp, address ? "Remembering updated" : "Remembering foreign", link);
|
||||
if (!address) {
|
||||
/* An address appeared that we did not request */
|
||||
r = address_add_foreign(link, tmp, &address);
|
||||
if (address) {
|
||||
address_enter_configured(address);
|
||||
log_address_debug(address, "Remembering updated", link);
|
||||
} else {
|
||||
address_enter_configured(tmp);
|
||||
log_address_debug(tmp, "Received new", link);
|
||||
|
||||
r = address_add(link, tmp);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
@ -1453,6 +1372,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
strnull(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
address = TAKE_PTR(tmp);
|
||||
}
|
||||
|
||||
/* address_update() logs internally, so we don't need to here. */
|
||||
@ -1463,8 +1384,12 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
log_address_debug(tmp, address ? "Forgetting" : "Kernel removed unknown", link);
|
||||
if (address) {
|
||||
address_enter_removed(address);
|
||||
log_address_debug(address, address->state == 0 ? "Forgetting" : "Removed", link);
|
||||
(void) address_drop(address);
|
||||
} else
|
||||
log_address_debug(tmp, "Kernel removed unknown", link);
|
||||
|
||||
break;
|
||||
|
||||
@ -1922,12 +1847,6 @@ int config_parse_duplicate_address_detection(
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool address_is_ready(const Address *a) {
|
||||
assert(a);
|
||||
|
||||
return !(a->flags & IFA_F_TENTATIVE);
|
||||
}
|
||||
|
||||
static int address_section_verify(Address *address) {
|
||||
if (section_is_invalid(address->section))
|
||||
return -EINVAL;
|
||||
|
@ -21,10 +21,12 @@ typedef struct Request Request;
|
||||
typedef int (*address_ready_callback_t)(Address *address);
|
||||
|
||||
struct Address {
|
||||
Link *link;
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
|
||||
Link *link;
|
||||
NetworkConfigSource source;
|
||||
NetworkConfigState state;
|
||||
union in_addr_union provider; /* DHCP server or router address */
|
||||
|
||||
int family;
|
||||
unsigned char prefixlen;
|
||||
@ -42,8 +44,6 @@ struct Address {
|
||||
|
||||
bool scope_set:1;
|
||||
bool ip_masquerade_done:1;
|
||||
bool is_static:1; /* currently only used by IPv4ACD */
|
||||
bool acd_announced:1;
|
||||
AddressFamily duplicate_address_detection;
|
||||
sd_ipv4acd *acd;
|
||||
|
||||
@ -62,8 +62,7 @@ int address_new(Address **ret);
|
||||
Address* address_free(Address *address);
|
||||
int address_get(Link *link, const Address *in, Address **ret);
|
||||
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
|
||||
int address_remove(const Address *address, Link *link);
|
||||
bool address_equal(const Address *a1, const Address *a2);
|
||||
int address_remove(Address *address);
|
||||
int address_dup(const Address *src, Address **ret);
|
||||
bool address_is_ready(const Address *a);
|
||||
void address_set_broadcast(Address *a);
|
||||
@ -80,6 +79,7 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
|
||||
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);
|
||||
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
|
||||
|
||||
void address_cancel_request(Address *address);
|
||||
int link_request_address(
|
||||
Link *link,
|
||||
Address *address,
|
||||
@ -99,6 +99,16 @@ 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;
|
||||
|
||||
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
|
||||
static inline void address_enter_probing(Address *address) {
|
||||
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
|
||||
}
|
||||
static inline void address_cancel_probing(Address *address) {
|
||||
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
|
||||
}
|
||||
|
||||
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_label);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route.h"
|
||||
#include "parse-util.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "string-table.h"
|
||||
@ -74,6 +75,40 @@ void network_adjust_dhcp_server(Network *network) {
|
||||
}
|
||||
}
|
||||
|
||||
int link_request_dhcp_server_address(Link *link) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
Address *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link_dhcp4_server_enabled(link))
|
||||
return 0;
|
||||
|
||||
if (!in4_addr_is_set(&link->network->dhcp_server_address))
|
||||
return 0;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
address->source = NETWORK_CONFIG_SOURCE_STATIC;
|
||||
address->family = AF_INET;
|
||||
address->in_addr.in = link->network->dhcp_server_address;
|
||||
address->prefixlen = link->network->dhcp_server_address_prefixlen;
|
||||
address_set_broadcast(address);
|
||||
|
||||
if (address_get(link, address, &existing) >= 0 &&
|
||||
address_exists(existing) &&
|
||||
existing->source == NETWORK_CONFIG_SOURCE_STATIC)
|
||||
/* The same address seems explicitly configured in [Address] or [Network] section.
|
||||
* Configure the DHCP server address only when it is not. */
|
||||
return 0;
|
||||
|
||||
return link_request_static_address(link, TAKE_PTR(address), true);
|
||||
}
|
||||
|
||||
static int link_find_dhcp_server_address(Link *link, Address **ret) {
|
||||
Address *address;
|
||||
|
||||
@ -86,10 +121,18 @@ static int link_find_dhcp_server_address(Link *link, Address **ret) {
|
||||
link->network->dhcp_server_address_prefixlen, ret);
|
||||
|
||||
/* If not, then select one from static addresses. */
|
||||
SET_FOREACH(address, link->static_addresses)
|
||||
if (address->family == AF_INET &&
|
||||
!in4_addr_is_localhost(&address->in_addr.in) &&
|
||||
in4_addr_is_null(&address->in_addr_peer.in)) {
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_STATIC)
|
||||
continue;
|
||||
if (!address_exists(address))
|
||||
continue;
|
||||
if (address->family != AF_INET)
|
||||
continue;
|
||||
if (in4_addr_is_localhost(&address->in_addr.in))
|
||||
continue;
|
||||
if (in4_addr_is_set(&address->in_addr_peer.in))
|
||||
continue;
|
||||
|
||||
*ret = address;
|
||||
return 0;
|
||||
}
|
||||
@ -505,9 +548,6 @@ static bool dhcp_server_is_ready_to_configure(Link *link) {
|
||||
if (!link_has_carrier(link))
|
||||
return false;
|
||||
|
||||
if (link->address_remove_messages > 0)
|
||||
return false;
|
||||
|
||||
if (!link->static_addresses_configured)
|
||||
return false;
|
||||
|
||||
|
@ -9,6 +9,7 @@ typedef struct Request Request;
|
||||
|
||||
void network_adjust_dhcp_server(Network *network);
|
||||
|
||||
int link_request_dhcp_server_address(Link *link);
|
||||
int link_request_dhcp_server(Link *link);
|
||||
int request_process_dhcp_server(Request *req);
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "sysctl-util.h"
|
||||
|
||||
static int dhcp4_request_address_and_routes(Link *link, bool announce);
|
||||
static int dhcp4_remove_all(Link *link);
|
||||
static int dhcp4_check_ready(Link *link);
|
||||
|
||||
void network_adjust_dhcp4(Network *network) {
|
||||
assert(network);
|
||||
@ -54,84 +54,106 @@ void network_adjust_dhcp4(Network *network) {
|
||||
network->dhcp_client_identifier = network->dhcp_anonymize ? DHCP_CLIENT_ID_MAC : DHCP_CLIENT_ID_DUID;
|
||||
}
|
||||
|
||||
static int dhcp4_release_old_lease(Link *link) {
|
||||
static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
|
||||
Address *address;
|
||||
Route *route;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
|
||||
return 0;
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
||||
continue;
|
||||
if (only_marked && !route_is_marked(route))
|
||||
continue;
|
||||
|
||||
log_link_debug(link, "Removing old DHCPv4 address and routes.");
|
||||
|
||||
SET_FOREACH(route, link->dhcp_routes_old) {
|
||||
k = route_remove(route, NULL, link);
|
||||
k = route_remove(route);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
route_cancel_request(route);
|
||||
}
|
||||
|
||||
if (link->dhcp_address_old) {
|
||||
k = address_remove(link->dhcp_address_old, link);
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
||||
continue;
|
||||
if (only_marked && !address_is_marked(address))
|
||||
continue;
|
||||
|
||||
k = address_remove(address);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
address_cancel_request(address);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dhcp4_check_ready(Link *link) {
|
||||
static int dhcp4_address_get(Link *link, Address **ret) {
|
||||
Address *address;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
||||
continue;
|
||||
if (address_is_marked(address))
|
||||
continue;
|
||||
|
||||
if (ret)
|
||||
*ret = address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int dhcp4_address_ready_callback(Address *address) {
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
/* Do not call this again. */
|
||||
address->callback = NULL;
|
||||
|
||||
return dhcp4_check_ready(address->link);
|
||||
}
|
||||
|
||||
static int dhcp4_check_ready(Link *link) {
|
||||
Address *address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (link->dhcp4_messages > 0) {
|
||||
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!link->dhcp_address) {
|
||||
if (dhcp4_address_get(link, &address) < 0) {
|
||||
log_link_debug(link, "%s(): DHCPv4 address is not set.", __func__);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!address_is_ready(link->dhcp_address)) {
|
||||
if (!address_is_ready(address)) {
|
||||
log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
|
||||
return;
|
||||
address->callback = dhcp4_address_ready_callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
link->dhcp4_configured = true;
|
||||
log_link_debug(link, "DHCPv4 address and routes set.");
|
||||
|
||||
/* New address and routes are configured now. Let's release old lease. */
|
||||
r = dhcp4_release_old_lease(link);
|
||||
if (r < 0) {
|
||||
link_enter_failed(link);
|
||||
return;
|
||||
}
|
||||
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4ll_stop(link->ipv4ll);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
|
||||
return log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address: %m");
|
||||
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
static int dhcp4_after_route_configure(Request *req, void *object) {
|
||||
Route *route = object;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_ROUTE);
|
||||
assert(route);
|
||||
|
||||
link = req->link;
|
||||
|
||||
r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, route);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
|
||||
|
||||
set_remove(link->dhcp_routes_old, route);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -140,7 +162,7 @@ static int dhcp4_retry(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
r = dhcp4_remove_all(link);
|
||||
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -192,19 +214,29 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
||||
return 1;
|
||||
}
|
||||
|
||||
dhcp4_check_ready(link);
|
||||
r = dhcp4_check_ready(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dhcp4_request_route(Route *in, Link *link) {
|
||||
_cleanup_(route_freep) Route *route = in;
|
||||
Request *req;
|
||||
struct in_addr server;
|
||||
Route *existing;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(link);
|
||||
assert(link->dhcp_lease);
|
||||
|
||||
r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &server);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
|
||||
|
||||
route->source = NETWORK_CONFIG_SOURCE_DHCP4;
|
||||
route->provider.in = server;
|
||||
route->family = AF_INET;
|
||||
if (!route->protocol_set)
|
||||
route->protocol = RTPROT_DHCP;
|
||||
@ -215,20 +247,13 @@ static int dhcp4_request_route(Route *in, Link *link) {
|
||||
if (route->mtu == 0)
|
||||
route->mtu = link->network->dhcp_route_mtu;
|
||||
|
||||
r = link_has_route(link, route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
|
||||
link->dhcp4_configured = false;
|
||||
else
|
||||
route_unmark(existing);
|
||||
|
||||
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
|
||||
dhcp4_route_handler, &req);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
req->after_configure = dhcp4_after_route_configure;
|
||||
|
||||
return 0;
|
||||
return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
|
||||
dhcp4_route_handler, NULL);
|
||||
}
|
||||
|
||||
static bool link_prefixroute(Link *link) {
|
||||
@ -675,19 +700,10 @@ static int dhcp4_request_routes_to_ntp(Link *link, const struct in_addr *gw) {
|
||||
|
||||
static int dhcp4_request_routes(Link *link) {
|
||||
struct in_addr gw = {};
|
||||
Route *rt;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->dhcp_lease)
|
||||
return 0;
|
||||
|
||||
while ((rt = set_steal_first(link->dhcp_routes))) {
|
||||
r = set_ensure_put(&link->dhcp_routes_old, &route_hash_ops, rt);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
|
||||
}
|
||||
assert(link->dhcp_lease);
|
||||
|
||||
r = dhcp4_request_prefix_route(link);
|
||||
if (r < 0)
|
||||
@ -768,27 +784,6 @@ static int dhcp_reset_hostname(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp4_remove_all(Link *link) {
|
||||
Route *route;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(route, link->dhcp_routes) {
|
||||
k = route_remove(route, NULL, link);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (link->dhcp_address) {
|
||||
k = address_remove(link->dhcp_address, link);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp4_lease_lost(Link *link) {
|
||||
int k, r = 0;
|
||||
|
||||
@ -799,12 +794,7 @@ int dhcp4_lease_lost(Link *link) {
|
||||
|
||||
link->dhcp4_configured = false;
|
||||
|
||||
/* dhcp4_lease_lost() may be called during renewing IP address. */
|
||||
k = dhcp4_release_old_lease(link);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
k = dhcp4_remove_all(link);
|
||||
k = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
@ -819,24 +809,7 @@ int dhcp4_lease_lost(Link *link) {
|
||||
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link_dirty(link);
|
||||
|
||||
if (link->network->dhcp_send_decline) {
|
||||
Address *a;
|
||||
|
||||
/* The acquired address may be still ARP probing and not configured. */
|
||||
|
||||
SET_FOREACH(a, link->addresses_ipv4acd)
|
||||
if (!a->is_static && address_get(link, a, NULL) < 0) {
|
||||
Request req = {
|
||||
.link = link,
|
||||
.address = a,
|
||||
};
|
||||
|
||||
log_link_debug(link, "Canceling the request to configure DHCPv4 address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
|
||||
request_drop(ordered_set_get(link->manager->request_queue, &req));
|
||||
}
|
||||
}
|
||||
|
||||
/* If one of the above failed. Do not request nexthops and routes. */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -847,43 +820,6 @@ int dhcp4_lease_lost(Link *link) {
|
||||
return link_request_static_routes(link, true);
|
||||
}
|
||||
|
||||
static int dhcp4_address_ready_callback(Address *address) {
|
||||
assert(address);
|
||||
|
||||
/* Do not call this again. */
|
||||
address->callback = NULL;
|
||||
|
||||
dhcp4_check_ready(address->link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp4_after_address_configure(Request *req, void *object) {
|
||||
Address *address = object;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_ADDRESS);
|
||||
assert(address);
|
||||
|
||||
link = req->link;
|
||||
|
||||
if (!address_equal(link->dhcp_address, address)) {
|
||||
if (link->dhcp_address_old &&
|
||||
!address_equal(link->dhcp_address_old, link->dhcp_address)) {
|
||||
/* Still too old address exists? Let's remove it immediately. */
|
||||
r = address_remove(link->dhcp_address_old, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
link->dhcp_address_old = link->dhcp_address;
|
||||
}
|
||||
|
||||
link->dhcp_address = address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
@ -896,12 +832,9 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (address_is_ready(link->dhcp_address)) {
|
||||
r = dhcp4_address_ready_callback(link->dhcp_address);
|
||||
r = dhcp4_check_ready(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
} else
|
||||
link->dhcp_address->callback = dhcp4_address_ready_callback;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -911,14 +844,12 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
||||
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||
struct in_addr address, netmask, server;
|
||||
unsigned prefixlen;
|
||||
Request *req;
|
||||
Address *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link->dhcp_lease)
|
||||
return 0;
|
||||
assert(link->dhcp_lease);
|
||||
|
||||
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||
if (r < 0)
|
||||
@ -973,6 +904,8 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
addr->source = NETWORK_CONFIG_SOURCE_DHCP4;
|
||||
addr->provider.in = server;
|
||||
addr->family = AF_INET;
|
||||
addr->in_addr.in.s_addr = address.s_addr;
|
||||
addr->cinfo.ifa_prefered = lifetime;
|
||||
@ -988,17 +921,15 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (address_get(link, addr, NULL) < 0)
|
||||
if (address_get(link, addr, &existing) < 0) /* The address is new. */
|
||||
link->dhcp4_configured = false;
|
||||
else
|
||||
address_unmark(existing);
|
||||
|
||||
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
|
||||
dhcp4_address_handler, &req);
|
||||
dhcp4_address_handler, NULL);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
req->after_configure = dhcp4_after_address_configure;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1008,6 +939,9 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
|
||||
|
||||
assert(link);
|
||||
|
||||
link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
|
||||
link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
|
||||
|
||||
r = dhcp4_request_address(link, announce);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1016,8 +950,10 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!link->dhcp4_configured) {
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1372,7 +1308,9 @@ static int dhcp4_set_request_address(Link *link) {
|
||||
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
||||
return 0;
|
||||
|
||||
SET_FOREACH(a, link->addresses_foreign) {
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (a->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
if (a->family != AF_INET)
|
||||
continue;
|
||||
if (link_address_is_dynamic(link, a))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,18 +16,9 @@ typedef enum DHCP6ClientStartMode {
|
||||
typedef struct Link Link;
|
||||
typedef struct Request Request;
|
||||
|
||||
typedef struct DHCP6DelegatedPrefix {
|
||||
struct in6_addr prefix; /* Prefix assigned to the link */
|
||||
struct in6_addr pd_prefix; /* PD prefix provided by DHCP6 lease */
|
||||
Link *link;
|
||||
} DHCP6DelegatedPrefix;
|
||||
|
||||
DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
|
||||
|
||||
bool link_dhcp6_with_address_enabled(Link *link);
|
||||
bool link_dhcp6_pd_is_enabled(Link *link);
|
||||
int dhcp6_pd_remove(Link *link);
|
||||
int dhcp6_pd_remove(Link *link, bool only_marked);
|
||||
int dhcp6_update_mac(Link *link);
|
||||
int dhcp6_start(Link *link);
|
||||
int dhcp6_request_information(Link *link, int ir);
|
||||
|
@ -9,19 +9,26 @@
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
|
||||
static int static_address_on_stop(Link *link, Address *address) {
|
||||
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
if (address_get(link, address, NULL) < 0)
|
||||
return 0;
|
||||
/* Prevent form the address being freed. */
|
||||
address_enter_probing(address);
|
||||
|
||||
if (!address_exists(address))
|
||||
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));
|
||||
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));
|
||||
|
||||
r = address_remove(address, link);
|
||||
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));
|
||||
@ -29,30 +36,7 @@ static int static_address_on_stop(Link *link, Address *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int static_address_on_conflict(Link *link, Address *address) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
if (address_get(link, address, NULL) < 0) {
|
||||
log_link_warning(link, "Cannot configure requested address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
r = address_remove(address, link);
|
||||
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 0;
|
||||
}
|
||||
|
||||
static int dhcp4_address_on_conflict(Link *link) {
|
||||
static int dhcp4_address_on_conflict(Link *link, Address *address) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -71,11 +55,14 @@ static int dhcp4_address_on_conflict(Link *link) {
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
|
||||
|
||||
/* make the address will be freed. */
|
||||
address_cancel_probing(address);
|
||||
|
||||
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
|
||||
static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
Address *address = userdata;
|
||||
Link *link;
|
||||
int r;
|
||||
@ -85,13 +72,14 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
|
||||
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;
|
||||
|
||||
switch (event) {
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
if (is_static) {
|
||||
r = static_address_on_stop(link, address);
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
|
||||
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
}
|
||||
@ -104,14 +92,17 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
|
||||
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
address->acd_announced = true;
|
||||
address_cancel_probing(address);
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
if (is_static)
|
||||
r = static_address_on_conflict(link, address);
|
||||
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_STATIC)
|
||||
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ true);
|
||||
else
|
||||
r = dhcp4_address_on_conflict(link);
|
||||
r = dhcp4_address_on_conflict(link, address);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
break;
|
||||
@ -121,14 +112,6 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
|
||||
}
|
||||
}
|
||||
|
||||
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
on_acd(acd, event, userdata, true);
|
||||
}
|
||||
|
||||
static void dhcp4_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
on_acd(acd, event, userdata, false);
|
||||
}
|
||||
|
||||
static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
struct hw_addr_data hw_addr;
|
||||
@ -144,27 +127,31 @@ 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 ipv4acd_configure(Link *link, const Address *a) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
int ipv4acd_configure(Address *address) {
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(a);
|
||||
assert(a->family == AF_INET);
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
if (address->family != AF_INET)
|
||||
return 0;
|
||||
|
||||
if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
|
||||
return 0;
|
||||
|
||||
/* Currently, only static and DHCP4 addresses are supported. */
|
||||
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
|
||||
|
||||
if (address->acd) {
|
||||
address_enter_probing(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
link = address->link;
|
||||
|
||||
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
|
||||
|
||||
r = address_dup(a, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = set_ensure_put(&link->addresses_ipv4acd, &address_hash_ops, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EEXIST;
|
||||
address->link = link;
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
r = sd_ipv4acd_new(&address->acd);
|
||||
if (r < 0)
|
||||
@ -186,9 +173,7 @@ static int ipv4acd_configure(Link *link, const Address *a) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_callback(address->acd,
|
||||
address->is_static ? static_address_on_acd : dhcp4_address_on_acd,
|
||||
address);
|
||||
r = sd_ipv4acd_set_callback(address->acd, on_acd, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -202,36 +187,10 @@ static int ipv4acd_configure(Link *link, const Address *a) {
|
||||
return r;
|
||||
}
|
||||
|
||||
TAKE_PTR(address);
|
||||
address_enter_probing(address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address) {
|
||||
Address *acd_address;
|
||||
int r;
|
||||
|
||||
acd_address = set_get(link->addresses_ipv4acd, address);
|
||||
if (!acd_address) {
|
||||
r = ipv4acd_configure(link, address);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to configure IPv4ACD client: %m");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!acd_address->acd_announced)
|
||||
return false;
|
||||
|
||||
r = set_ensure_put(&link->addresses, &address_hash_ops, acd_address);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EEXIST), "Address already exists.");
|
||||
|
||||
acd_address->flags |= IFA_F_TENTATIVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ipv4acd_update_mac(Link *link) {
|
||||
Address *address;
|
||||
int k, r = 0;
|
||||
@ -243,8 +202,9 @@ int ipv4acd_update_mac(Link *link) {
|
||||
if (ether_addr_is_null(&link->hw_addr.ether))
|
||||
return 0;
|
||||
|
||||
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||
assert(address->acd);
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address->acd)
|
||||
continue;
|
||||
|
||||
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
|
||||
if (k < 0)
|
||||
@ -262,7 +222,10 @@ int ipv4acd_start(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address->acd)
|
||||
continue;
|
||||
|
||||
if (sd_ipv4acd_is_running(address->acd))
|
||||
continue;
|
||||
|
||||
@ -280,7 +243,10 @@ int ipv4acd_stop(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address->acd)
|
||||
continue;
|
||||
|
||||
k = sd_ipv4acd_stop(address->acd);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
@ -295,7 +261,10 @@ int ipv4acd_set_ifname(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address->acd)
|
||||
continue;
|
||||
|
||||
r = sd_ipv4acd_set_ifname(address->acd, link->ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -4,7 +4,7 @@
|
||||
typedef struct Address Address;
|
||||
typedef struct Link Link;
|
||||
|
||||
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address);
|
||||
int ipv4acd_configure(Address *address);
|
||||
int ipv4acd_update_mac(Link *link);
|
||||
int ipv4acd_start(Link *link);
|
||||
int ipv4acd_stop(Link *link);
|
||||
|
@ -28,6 +28,7 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
|
||||
address->family = AF_INET;
|
||||
address->in_addr.in = addr;
|
||||
address->prefixlen = 16;
|
||||
@ -41,6 +42,7 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
|
||||
|
||||
static int ipv4ll_address_lost(Link *link) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
Address *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -53,10 +55,19 @@ static int ipv4ll_address_lost(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (address_get(link, address, &existing) < 0)
|
||||
return 0;
|
||||
|
||||
if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
|
||||
return 0;
|
||||
|
||||
if (!address_exists(existing))
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
return address_remove(address, link);
|
||||
return address_remove(existing);
|
||||
}
|
||||
|
||||
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "networkd-nexthop.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-setlink.h"
|
||||
#include "networkd-sriov.h"
|
||||
@ -227,29 +228,12 @@ static Link *link_free(Link *link) {
|
||||
link_dns_settings_clear(link);
|
||||
|
||||
link->routes = set_free(link->routes);
|
||||
link->routes_foreign = set_free(link->routes_foreign);
|
||||
link->dhcp_routes = set_free(link->dhcp_routes);
|
||||
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
|
||||
link->dhcp6_routes = set_free(link->dhcp6_routes);
|
||||
link->dhcp6_routes_old = set_free(link->dhcp6_routes_old);
|
||||
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
|
||||
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
|
||||
link->ndisc_routes = set_free(link->ndisc_routes);
|
||||
|
||||
link->nexthops = set_free(link->nexthops);
|
||||
|
||||
link->neighbors = set_free(link->neighbors);
|
||||
|
||||
link->addresses = set_free(link->addresses);
|
||||
link->addresses_foreign = set_free(link->addresses_foreign);
|
||||
link->addresses_ipv4acd = set_free(link->addresses_ipv4acd);
|
||||
link->pool_addresses = set_free(link->pool_addresses);
|
||||
link->static_addresses = set_free(link->static_addresses);
|
||||
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
|
||||
link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old);
|
||||
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
|
||||
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
|
||||
link->ndisc_addresses = set_free(link->ndisc_addresses);
|
||||
|
||||
link->dhcp6_pd_prefixes = set_free(link->dhcp6_pd_prefixes);
|
||||
|
||||
@ -394,7 +378,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
|
||||
|
||||
k = dhcp6_pd_remove(link);
|
||||
k = dhcp6_pd_remove(link, /* only_marked = */ false);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
|
||||
|
||||
@ -459,7 +443,7 @@ void link_check_ready(Link *link) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
(void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str);
|
||||
return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str));
|
||||
return (void) log_link_debug(link, "%s(): address %s is not ready.", __func__, strna(str));
|
||||
}
|
||||
|
||||
if (!link->static_address_labels_configured)
|
||||
@ -495,44 +479,42 @@ void link_check_ready(Link *link) {
|
||||
!in6_addr_is_set(&link->ipv6ll_address))
|
||||
return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__);
|
||||
|
||||
bool has_ndisc_address = false;
|
||||
NDiscAddress *n;
|
||||
SET_FOREACH(n, link->ndisc_addresses)
|
||||
if (!n->marked) {
|
||||
has_ndisc_address = true;
|
||||
bool has_dynamic_address = false;
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (address_is_marked(a))
|
||||
continue;
|
||||
if (!address_exists(a))
|
||||
continue;
|
||||
if (IN_SET(a->source,
|
||||
NETWORK_CONFIG_SOURCE_IPV4LL, NETWORK_CONFIG_SOURCE_DHCP4,
|
||||
NETWORK_CONFIG_SOURCE_DHCP6, NETWORK_CONFIG_SOURCE_NDISC)) {
|
||||
has_dynamic_address = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) || link_ipv4ll_enabled(link)) &&
|
||||
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
||||
!link->ipv4ll_address_configured)
|
||||
if ((link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) ||
|
||||
(link_dhcp6_pd_is_enabled(link) && link->network->dhcp6_pd_assign)) && !has_dynamic_address)
|
||||
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
||||
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||
|
||||
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
|
||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
||||
(!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link)) ||
|
||||
link_ipv4ll_enabled(link)) {
|
||||
if (link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) ||
|
||||
link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
||||
(!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link))) {
|
||||
|
||||
if (!link->dhcp4_configured &&
|
||||
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
||||
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
||||
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
||||
!link->ipv4ll_address_configured)
|
||||
if (!link->ipv4ll_address_configured && !link->dhcp4_configured &&
|
||||
!link->dhcp6_configured && !link->dhcp6_pd_configured && !link->ndisc_configured)
|
||||
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
||||
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||
|
||||
log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
|
||||
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
|
||||
log_link_debug(link, "%s(): IPv4LL:%s DHCPv4:%s DHCPv6:%s DHCPv6PD:%s NDisc:%s",
|
||||
__func__,
|
||||
yes_no(link->dhcp4_configured),
|
||||
yes_no(link->ipv4ll_address_configured),
|
||||
yes_no(link->dhcp6_address_configured),
|
||||
yes_no(link->dhcp6_route_configured),
|
||||
yes_no(link->dhcp6_pd_address_configured),
|
||||
yes_no(link->dhcp6_pd_route_configured),
|
||||
yes_no(link->ndisc_addresses_configured),
|
||||
yes_no(link->ndisc_routes_configured));
|
||||
yes_no(link->dhcp4_configured),
|
||||
yes_no(link->dhcp6_configured),
|
||||
yes_no(link->dhcp6_pd_configured),
|
||||
yes_no(link->ndisc_configured));
|
||||
}
|
||||
|
||||
link_set_state(link, LINK_STATE_CONFIGURED);
|
||||
@ -1627,11 +1609,7 @@ static int link_carrier_lost(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_drop_config(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_drop_foreign_config(link);
|
||||
return link_drop_config(link);
|
||||
}
|
||||
|
||||
static int link_admin_state_up(Link *link) {
|
||||
@ -1757,18 +1735,6 @@ void link_update_operstate(Link *link, bool also_update_master) {
|
||||
ipv6_scope = MIN(ipv6_scope, address->scope);
|
||||
}
|
||||
|
||||
/* for operstate we also take foreign addresses into account */
|
||||
SET_FOREACH(address, link->addresses_foreign) {
|
||||
if (!address_is_ready(address))
|
||||
continue;
|
||||
|
||||
if (address->family == AF_INET)
|
||||
ipv4_scope = MIN(ipv4_scope, address->scope);
|
||||
|
||||
if (address->family == AF_INET6)
|
||||
ipv6_scope = MIN(ipv6_scope, address->scope);
|
||||
}
|
||||
|
||||
ipv4_address_state = address_state_from_scope(ipv4_scope);
|
||||
ipv6_address_state = address_state_from_scope(ipv6_scope);
|
||||
address_state = address_state_from_scope(MIN(ipv4_scope, ipv6_scope));
|
||||
|
@ -39,7 +39,6 @@ typedef enum LinkState {
|
||||
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Network Network;
|
||||
typedef struct Address Address;
|
||||
typedef struct DUID DUID;
|
||||
|
||||
typedef struct Link {
|
||||
@ -92,8 +91,6 @@ typedef struct Link {
|
||||
unsigned static_nexthop_messages;
|
||||
unsigned static_route_messages;
|
||||
unsigned static_routing_policy_rule_messages;
|
||||
unsigned address_remove_messages;
|
||||
unsigned route_remove_messages;
|
||||
unsigned tc_messages;
|
||||
unsigned sr_iov_messages;
|
||||
unsigned set_link_messages;
|
||||
@ -102,19 +99,12 @@ typedef struct Link {
|
||||
unsigned create_stacked_netdev_after_configured_messages;
|
||||
|
||||
Set *addresses;
|
||||
Set *addresses_foreign;
|
||||
Set *addresses_ipv4acd;
|
||||
Set *pool_addresses;
|
||||
Set *static_addresses;
|
||||
Set *neighbors;
|
||||
Set *routes;
|
||||
Set *routes_foreign;
|
||||
Set *nexthops;
|
||||
|
||||
sd_dhcp_client *dhcp_client;
|
||||
sd_dhcp_lease *dhcp_lease;
|
||||
Address *dhcp_address, *dhcp_address_old;
|
||||
Set *dhcp_routes, *dhcp_routes_old;
|
||||
char *lease_file;
|
||||
unsigned dhcp4_messages;
|
||||
bool dhcp4_route_failed:1;
|
||||
@ -145,31 +135,18 @@ typedef struct Link {
|
||||
sd_ndisc *ndisc;
|
||||
Set *ndisc_rdnss;
|
||||
Set *ndisc_dnssl;
|
||||
Set *ndisc_addresses;
|
||||
Set *ndisc_routes;
|
||||
unsigned ndisc_addresses_messages;
|
||||
unsigned ndisc_routes_messages;
|
||||
bool ndisc_addresses_configured:1;
|
||||
bool ndisc_routes_configured:1;
|
||||
unsigned ndisc_messages;
|
||||
bool ndisc_configured:1;
|
||||
|
||||
sd_radv *radv;
|
||||
|
||||
sd_dhcp6_client *dhcp6_client;
|
||||
sd_dhcp6_lease *dhcp6_lease;
|
||||
Set *dhcp6_addresses, *dhcp6_addresses_old;
|
||||
Set *dhcp6_routes, *dhcp6_routes_old;
|
||||
Set *dhcp6_pd_prefixes;
|
||||
Set *dhcp6_pd_addresses, *dhcp6_pd_addresses_old;
|
||||
Set *dhcp6_pd_routes, *dhcp6_pd_routes_old;
|
||||
unsigned dhcp6_address_messages;
|
||||
unsigned dhcp6_route_messages;
|
||||
unsigned dhcp6_pd_address_messages;
|
||||
unsigned dhcp6_pd_route_messages;
|
||||
bool dhcp6_address_configured:1;
|
||||
bool dhcp6_route_configured:1;
|
||||
bool dhcp6_pd_address_configured:1;
|
||||
bool dhcp6_pd_route_configured:1;
|
||||
bool dhcp6_pd_prefixes_assigned:1;
|
||||
unsigned dhcp6_messages;
|
||||
unsigned dhcp6_pd_messages;
|
||||
bool dhcp6_configured:1;
|
||||
bool dhcp6_pd_configured:1;
|
||||
|
||||
/* This is about LLDP reception */
|
||||
sd_lldp_rx *lldp_rx;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "netlink-util.h"
|
||||
#include "network-internal.h"
|
||||
#include "networkd-address-pool.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-dhcp-server-bus.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-link-bus.h"
|
||||
@ -36,6 +37,7 @@
|
||||
#include "networkd-network-bus.h"
|
||||
#include "networkd-nexthop.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-speed-meter.h"
|
||||
#include "networkd-state-file.h"
|
||||
@ -480,9 +482,6 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
m->request_queue = ordered_set_free(m->request_queue);
|
||||
|
||||
m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
|
||||
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
|
||||
|
||||
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
||||
m->links_by_name = hashmap_free(m->links_by_name);
|
||||
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
||||
|
@ -50,8 +50,6 @@ struct Manager {
|
||||
Hashmap *links_by_hw_addr;
|
||||
Hashmap *netdevs;
|
||||
OrderedHashmap *networks;
|
||||
Hashmap *dhcp6_prefixes;
|
||||
Set *dhcp6_pd_prefixes;
|
||||
OrderedSet *address_pools;
|
||||
|
||||
usec_t network_dirs_ts_usec;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
@ -96,112 +97,62 @@ void network_adjust_ipv6_accept_ra(Network *network) {
|
||||
network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
|
||||
}
|
||||
|
||||
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
|
||||
|
||||
static int ndisc_address_callback(Address *address) {
|
||||
struct in6_addr router = {};
|
||||
NDiscAddress *n;
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
assert(address->family == AF_INET6);
|
||||
|
||||
SET_FOREACH(n, address->link->ndisc_addresses)
|
||||
if (n->address == address) {
|
||||
router = n->router;
|
||||
break;
|
||||
}
|
||||
|
||||
if (in6_addr_is_null(&router)) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buf);
|
||||
log_link_debug(address->link, "%s is called for %s, but it is already removed, ignoring.",
|
||||
__func__, strna(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make this called only once */
|
||||
SET_FOREACH(n, address->link->ndisc_addresses)
|
||||
if (in6_addr_equal(&n->router, &router))
|
||||
n->address->callback = NULL;
|
||||
|
||||
return ndisc_remove_old_one(address->link, &router, true);
|
||||
}
|
||||
|
||||
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force) {
|
||||
NDiscAddress *na;
|
||||
NDiscRoute *nr;
|
||||
static int ndisc_remove(Link *link, struct in6_addr *router) {
|
||||
bool updated = false;
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
Address *address;
|
||||
Route *route;
|
||||
int k, r = 0;
|
||||
bool updated = false;
|
||||
|
||||
assert(link);
|
||||
assert(router);
|
||||
|
||||
if (!force) {
|
||||
bool set_callback = false;
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
if (!route_is_marked(route))
|
||||
continue;
|
||||
if (router && !in6_addr_equal(router, &route->provider.in6))
|
||||
continue;
|
||||
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (!na->marked && in6_addr_equal(&na->router, router)) {
|
||||
set_callback = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (set_callback)
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (!na->marked && address_is_ready(na->address)) {
|
||||
set_callback = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (set_callback) {
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (!na->marked && in6_addr_equal(&na->router, router))
|
||||
na->address->callback = ndisc_address_callback;
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
(void) in6_addr_to_string(router, &buf);
|
||||
log_link_debug(link, "No SLAAC address obtained from %s is ready. "
|
||||
"The old NDisc information will be removed later.",
|
||||
strna(buf));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
(void) in6_addr_to_string(router, &buf);
|
||||
log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
|
||||
}
|
||||
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (na->marked && in6_addr_equal(&na->router, router)) {
|
||||
k = address_remove(na->address, link);
|
||||
k = route_remove(route);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
route_cancel_request(route);
|
||||
}
|
||||
|
||||
SET_FOREACH(nr, link->ndisc_routes)
|
||||
if (nr->marked && in6_addr_equal(&nr->router, router)) {
|
||||
k = route_remove(nr->route, NULL, link);
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
if (!address_is_marked(address))
|
||||
continue;
|
||||
if (router && !in6_addr_equal(router, &address->provider.in6))
|
||||
continue;
|
||||
|
||||
k = address_remove(address);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
address_cancel_request(address);
|
||||
}
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss)
|
||||
if (rdnss->marked && in6_addr_equal(&rdnss->router, router)) {
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss) {
|
||||
if (!rdnss->marked)
|
||||
continue;
|
||||
if (router && !in6_addr_equal(router, &rdnss->router))
|
||||
continue;
|
||||
|
||||
free(set_remove(link->ndisc_rdnss, rdnss));
|
||||
updated = true;
|
||||
}
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||
if (dnssl->marked && in6_addr_equal(&dnssl->router, router)) {
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl) {
|
||||
if (!dnssl->marked)
|
||||
continue;
|
||||
if (router && !in6_addr_equal(router, &dnssl->router))
|
||||
continue;
|
||||
|
||||
free(set_remove(link->ndisc_dnssl, dnssl));
|
||||
updated = true;
|
||||
}
|
||||
@ -212,197 +163,100 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ndisc_remove_old(Link *link) {
|
||||
_cleanup_set_free_free_ Set *routers = NULL;
|
||||
_cleanup_free_ struct in6_addr *router = NULL;
|
||||
struct in6_addr *a;
|
||||
NDiscAddress *na;
|
||||
NDiscRoute *nr;
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
int k, r;
|
||||
static int ndisc_check_ready(Link *link);
|
||||
|
||||
static int ndisc_address_ready_callback(Address *address) {
|
||||
Address *a;
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
SET_FOREACH(a, address->link->addresses)
|
||||
if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
|
||||
a->callback = NULL;
|
||||
|
||||
return ndisc_check_ready(address->link);
|
||||
}
|
||||
|
||||
static int ndisc_check_ready(Link *link) {
|
||||
bool found = false, ready = false;
|
||||
Address *address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (link->ndisc_addresses_messages > 0 ||
|
||||
link->ndisc_routes_messages > 0)
|
||||
if (link->ndisc_messages > 0) {
|
||||
log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
routers = set_new(&in6_addr_hash_ops);
|
||||
if (!routers)
|
||||
return -ENOMEM;
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (!set_contains(routers, &na->router)) {
|
||||
router = newdup(struct in6_addr, &na->router, 1);
|
||||
if (!router)
|
||||
return -ENOMEM;
|
||||
found = true;
|
||||
|
||||
r = set_put(routers, router);
|
||||
if (address_is_ready(address)) {
|
||||
ready = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && !ready) {
|
||||
SET_FOREACH(address, link->addresses)
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
|
||||
address->callback = ndisc_address_ready_callback;
|
||||
|
||||
log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
link->ndisc_configured = true;
|
||||
log_link_debug(link, "SLAAC addresses and routes set.");
|
||||
|
||||
r = ndisc_remove(link, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(r > 0);
|
||||
TAKE_PTR(router);
|
||||
link_check_ready(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SET_FOREACH(nr, link->ndisc_routes)
|
||||
if (!set_contains(routers, &nr->router)) {
|
||||
router = newdup(struct in6_addr, &nr->router, 1);
|
||||
if (!router)
|
||||
return -ENOMEM;
|
||||
|
||||
r = set_put(routers, router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(r > 0);
|
||||
TAKE_PTR(router);
|
||||
}
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss)
|
||||
if (!set_contains(routers, &rdnss->router)) {
|
||||
router = newdup(struct in6_addr, &rdnss->router, 1);
|
||||
if (!router)
|
||||
return -ENOMEM;
|
||||
|
||||
r = set_put(routers, router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(r > 0);
|
||||
TAKE_PTR(router);
|
||||
}
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||
if (!set_contains(routers, &dnssl->router)) {
|
||||
router = newdup(struct in6_addr, &dnssl->router, 1);
|
||||
if (!router)
|
||||
return -ENOMEM;
|
||||
|
||||
r = set_put(routers, router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(r > 0);
|
||||
TAKE_PTR(router);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
SET_FOREACH(a, routers) {
|
||||
k = ndisc_remove_old_one(link, a, false);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ndisc_route_hash_func(const NDiscRoute *x, struct siphash *state) {
|
||||
route_hash_func(x->route, state);
|
||||
}
|
||||
|
||||
static int ndisc_route_compare_func(const NDiscRoute *a, const NDiscRoute *b) {
|
||||
return route_compare_func(a->route, b->route);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
ndisc_route_hash_ops,
|
||||
NDiscRoute,
|
||||
ndisc_route_hash_func,
|
||||
ndisc_route_compare_func,
|
||||
free);
|
||||
|
||||
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->ndisc_routes_messages > 0);
|
||||
assert(link->ndisc_messages > 0);
|
||||
|
||||
link->ndisc_routes_messages--;
|
||||
link->ndisc_messages--;
|
||||
|
||||
r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (link->ndisc_routes_messages == 0) {
|
||||
log_link_debug(link, "NDisc routes set.");
|
||||
link->ndisc_routes_configured = true;
|
||||
|
||||
r = ndisc_remove_old(link);
|
||||
if (r < 0) {
|
||||
r = ndisc_check_ready(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndisc_after_route_configure(Request *req, void *object) {
|
||||
_cleanup_free_ NDiscRoute *nr = NULL;
|
||||
NDiscRoute *nr_exist;
|
||||
struct in6_addr router;
|
||||
Route *route = object;
|
||||
sd_ndisc_router *rt;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_ROUTE);
|
||||
assert(req->userdata);
|
||||
assert(route);
|
||||
|
||||
link = req->link;
|
||||
rt = req->userdata;
|
||||
|
||||
r = sd_ndisc_router_get_address(rt, &router);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
|
||||
|
||||
nr = new(NDiscRoute, 1);
|
||||
if (!nr)
|
||||
return log_oom();
|
||||
|
||||
*nr = (NDiscRoute) {
|
||||
.router = router,
|
||||
.route = route,
|
||||
};
|
||||
|
||||
nr_exist = set_get(link->ndisc_routes, nr);
|
||||
if (nr_exist) {
|
||||
nr_exist->marked = false;
|
||||
nr_exist->router = router;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = set_ensure_put(&link->ndisc_routes, &ndisc_route_hash_ops, nr);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC route: %m");
|
||||
assert(r > 0);
|
||||
TAKE_PTR(nr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ndisc_request_on_free(Request *req) {
|
||||
assert(req);
|
||||
|
||||
sd_ndisc_router_unref(req->userdata);
|
||||
}
|
||||
|
||||
static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
|
||||
_cleanup_(route_freep) Route *route = in;
|
||||
Request *req;
|
||||
struct in6_addr router;
|
||||
Route *existing;
|
||||
int r;
|
||||
|
||||
assert(route);
|
||||
assert(link);
|
||||
assert(rt);
|
||||
|
||||
r = sd_ndisc_router_get_address(rt, &router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->source = NETWORK_CONFIG_SOURCE_NDISC;
|
||||
route->provider.in6 = router;
|
||||
if (!route->table_set)
|
||||
route->table = link_get_ipv6_accept_ra_route_table(link);
|
||||
if (!route->priority_set)
|
||||
@ -410,134 +264,58 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
|
||||
if (!route->protocol_set)
|
||||
route->protocol = RTPROT_RA;
|
||||
|
||||
r = link_has_route(link, route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
link->ndisc_routes_configured = false;
|
||||
if (route_get(NULL, link, route, &existing) < 0)
|
||||
link->ndisc_configured = false;
|
||||
else
|
||||
route_unmark(existing);
|
||||
|
||||
r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_routes_messages,
|
||||
ndisc_route_handler, &req);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
req->userdata = sd_ndisc_router_ref(rt);
|
||||
req->after_configure = ndisc_after_route_configure;
|
||||
req->on_free = ndisc_request_on_free;
|
||||
|
||||
return 0;
|
||||
return link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
|
||||
ndisc_route_handler, NULL);
|
||||
}
|
||||
|
||||
static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
|
||||
address_hash_func(x->address, state);
|
||||
}
|
||||
|
||||
static int ndisc_address_compare_func(const NDiscAddress *a, const NDiscAddress *b) {
|
||||
return address_compare_func(a->address, b->address);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
ndisc_address_hash_ops,
|
||||
NDiscAddress,
|
||||
ndisc_address_hash_func,
|
||||
ndisc_address_compare_func,
|
||||
free);
|
||||
|
||||
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->ndisc_addresses_messages > 0);
|
||||
assert(link->ndisc_messages > 0);
|
||||
|
||||
link->ndisc_addresses_messages--;
|
||||
link->ndisc_messages--;
|
||||
|
||||
r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (link->ndisc_addresses_messages == 0) {
|
||||
log_link_debug(link, "NDisc SLAAC addresses set.");
|
||||
link->ndisc_addresses_configured = true;
|
||||
|
||||
r = ndisc_remove_old(link);
|
||||
if (r < 0) {
|
||||
r = ndisc_check_ready(link);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndisc_after_address_configure(Request *req, void *object) {
|
||||
_cleanup_free_ NDiscAddress *na = NULL;
|
||||
NDiscAddress *na_exist;
|
||||
struct in6_addr router;
|
||||
sd_ndisc_router *rt;
|
||||
Address *address = object;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_ADDRESS);
|
||||
assert(req->userdata);
|
||||
assert(address);
|
||||
|
||||
link = req->link;
|
||||
rt = req->userdata;
|
||||
|
||||
r = sd_ndisc_router_get_address(rt, &router);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
|
||||
|
||||
na = new(NDiscAddress, 1);
|
||||
if (!na)
|
||||
return log_oom();
|
||||
|
||||
*na = (NDiscAddress) {
|
||||
.router = router,
|
||||
.address = address,
|
||||
};
|
||||
|
||||
na_exist = set_get(link->ndisc_addresses, na);
|
||||
if (na_exist) {
|
||||
na_exist->marked = false;
|
||||
na_exist->router = router;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = set_ensure_put(&link->ndisc_addresses, &ndisc_address_hash_ops, na);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
|
||||
assert(r > 0);
|
||||
TAKE_PTR(na);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
|
||||
_cleanup_(address_freep) Address *address = in;
|
||||
Request *req;
|
||||
struct in6_addr router;
|
||||
Address *existing;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
assert(link);
|
||||
assert(rt);
|
||||
|
||||
if (address_get(link, address, NULL) < 0)
|
||||
link->ndisc_addresses_configured = false;
|
||||
|
||||
r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_addresses_messages,
|
||||
ndisc_address_handler, &req);
|
||||
if (r <= 0)
|
||||
r = sd_ndisc_router_get_address(rt, &router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
req->userdata = sd_ndisc_router_ref(rt);
|
||||
req->after_configure = ndisc_after_address_configure;
|
||||
req->on_free = ndisc_request_on_free;
|
||||
address->source = NETWORK_CONFIG_SOURCE_NDISC;
|
||||
address->provider.in6 = router;
|
||||
|
||||
return 0;
|
||||
if (address_get(link, address, &existing) < 0)
|
||||
link->ndisc_configured = false;
|
||||
else
|
||||
address_unmark(existing);
|
||||
|
||||
return link_request_address(link, TAKE_PTR(address), true, &link->ndisc_messages,
|
||||
ndisc_address_handler, NULL);
|
||||
}
|
||||
|
||||
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||
@ -987,7 +765,6 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
uint32_t lifetime;
|
||||
const struct in6_addr *a;
|
||||
struct in6_addr router;
|
||||
NDiscRDNSS *rdnss;
|
||||
usec_t time_now;
|
||||
bool updated = false;
|
||||
int n, r;
|
||||
@ -1011,10 +788,6 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
if (n < 0)
|
||||
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss)
|
||||
if (in6_addr_equal(&rdnss->router, &router))
|
||||
rdnss->marked = true;
|
||||
|
||||
if (lifetime == 0)
|
||||
return 0;
|
||||
|
||||
@ -1025,7 +798,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
for (int j = 0; j < n; j++) {
|
||||
_cleanup_free_ NDiscRDNSS *x = NULL;
|
||||
NDiscRDNSS d = {
|
||||
NDiscRDNSS *rdnss, d = {
|
||||
.address = a[j],
|
||||
};
|
||||
|
||||
@ -1081,7 +854,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
struct in6_addr router;
|
||||
uint32_t lifetime;
|
||||
usec_t time_now;
|
||||
NDiscDNSSL *dnssl;
|
||||
bool updated = false;
|
||||
char **j;
|
||||
int r;
|
||||
@ -1105,10 +877,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||
if (in6_addr_equal(&dnssl->router, &router))
|
||||
dnssl->marked = true;
|
||||
|
||||
if (lifetime == 0)
|
||||
return 0;
|
||||
|
||||
@ -1120,6 +888,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
STRV_FOREACH(j, l) {
|
||||
_cleanup_free_ NDiscDNSSL *s = NULL;
|
||||
NDiscDNSSL *dnssl;
|
||||
|
||||
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
|
||||
if (!s)
|
||||
@ -1242,11 +1011,28 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ndisc_mark(Link *link, const struct in6_addr *router) {
|
||||
NDiscRDNSS *rdnss;
|
||||
NDiscDNSSL *dnssl;
|
||||
|
||||
assert(link);
|
||||
assert(router);
|
||||
|
||||
link_mark_addresses(link, NETWORK_CONFIG_SOURCE_NDISC, router);
|
||||
link_mark_routes(link, NETWORK_CONFIG_SOURCE_NDISC, router);
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss)
|
||||
if (in6_addr_equal(&rdnss->router, router))
|
||||
rdnss->marked = true;
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||
if (in6_addr_equal(&dnssl->router, router))
|
||||
dnssl->marked = true;
|
||||
}
|
||||
|
||||
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
struct in6_addr router;
|
||||
uint64_t flags;
|
||||
NDiscAddress *na;
|
||||
NDiscRoute *nr;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -1271,13 +1057,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SET_FOREACH(na, link->ndisc_addresses)
|
||||
if (in6_addr_equal(&na->router, &router))
|
||||
na->marked = true;
|
||||
|
||||
SET_FOREACH(nr, link->ndisc_routes)
|
||||
if (in6_addr_equal(&nr->router, &router))
|
||||
nr->marked = true;
|
||||
ndisc_mark(link, &router);
|
||||
|
||||
r = sd_ndisc_router_get_flags(rt, &flags);
|
||||
if (r < 0)
|
||||
@ -1307,21 +1087,16 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link->ndisc_addresses_messages == 0)
|
||||
link->ndisc_addresses_configured = true;
|
||||
else
|
||||
log_link_debug(link, "Setting SLAAC addresses.");
|
||||
if (link->ndisc_messages == 0) {
|
||||
link->ndisc_configured = true;
|
||||
|
||||
if (link->ndisc_routes_messages == 0)
|
||||
link->ndisc_routes_configured = true;
|
||||
else
|
||||
log_link_debug(link, "Setting NDisc routes.");
|
||||
|
||||
r = ndisc_remove_old(link);
|
||||
r = ndisc_remove(link, &router);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
log_link_debug(link, "Setting SLAAC addresses and router.");
|
||||
|
||||
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
|
||||
if (!link->ndisc_configured)
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
|
||||
link_check_ready(link);
|
||||
@ -1349,9 +1124,8 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router
|
||||
|
||||
case SD_NDISC_EVENT_TIMEOUT:
|
||||
log_link_debug(link, "NDisc handler get timeout event");
|
||||
if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
|
||||
link->ndisc_addresses_configured = true;
|
||||
link->ndisc_routes_configured = true;
|
||||
if (link->ndisc_messages == 0) {
|
||||
link->ndisc_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
break;
|
||||
@ -1403,6 +1177,9 @@ int ndisc_start(Link *link) {
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
if (in6_addr_is_null(&link->ipv6ll_address))
|
||||
return 0;
|
||||
|
||||
log_link_debug(link, "Discovering IPv6 routers");
|
||||
|
||||
return sd_ndisc_start(link->ndisc);
|
||||
@ -1559,14 +1336,15 @@ int config_parse_address_generation_type(
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
|
||||
"Failed to parse UseDomains= setting");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
|
||||
"Failed to parse DHCPv6Client= setting");
|
||||
static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
|
||||
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
|
||||
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
|
||||
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
|
||||
"Failed to parse UseDomains= setting");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
|
||||
"Failed to parse DHCPv6Client= setting");
|
||||
|
@ -2,11 +2,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-route.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
|
||||
typedef enum IPv6AcceptRAStartDHCP6Client {
|
||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
||||
@ -15,20 +15,6 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
|
||||
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -EINVAL,
|
||||
} IPv6AcceptRAStartDHCP6Client;
|
||||
|
||||
typedef struct NDiscAddress {
|
||||
/* Used when GC'ing old DNS servers when configuration changes. */
|
||||
bool marked;
|
||||
struct in6_addr router;
|
||||
Address *address;
|
||||
} NDiscAddress;
|
||||
|
||||
typedef struct NDiscRoute {
|
||||
/* Used when GC'ing old DNS servers when configuration changes. */
|
||||
bool marked;
|
||||
struct in6_addr router;
|
||||
Route *route;
|
||||
} NDiscRoute;
|
||||
|
||||
typedef struct NDiscRDNSS {
|
||||
/* Used when GC'ing old DNS servers when configuration changes. */
|
||||
bool marked;
|
||||
@ -61,6 +47,3 @@ void ndisc_flush(Link *link);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_use_domains);
|
||||
|
||||
const char* ipv6_accept_ra_start_dhcp6_client_to_string(IPv6AcceptRAStartDHCP6Client i) _const_;
|
||||
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client_from_string(const char *s) _pure_;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-nexthop.h"
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-sriov.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -743,8 +743,6 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
||||
return false;
|
||||
|
||||
if (nexthop_owned_by_link(nexthop)) {
|
||||
Link *l;
|
||||
|
||||
/* TODO: fdb nexthop does not require IFF_UP. The conditions below needs to be updated
|
||||
* when fdb nexthop support is added. See rtm_to_nh_config() in net/ipv4/nexthop.c of
|
||||
* kernel. */
|
||||
@ -752,13 +750,6 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
||||
return false;
|
||||
if (!FLAGS_SET(link->flags, IFF_UP))
|
||||
return false;
|
||||
|
||||
HASHMAP_FOREACH(l, link->manager->links_by_index) {
|
||||
if (l->address_remove_messages > 0)
|
||||
return false;
|
||||
if (l->route_remove_messages > 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* All group members must be configured first. */
|
||||
|
@ -70,9 +70,6 @@ static Request *request_free(Request *req) {
|
||||
/* To prevent from triggering assertions in hash functions, remove this request before
|
||||
* freeing object below. */
|
||||
ordered_set_remove(req->link->manager->request_queue, req);
|
||||
if (req->on_free)
|
||||
/* on_free() may use object. So, let's call this earlier. */
|
||||
req->on_free(req);
|
||||
if (req->consume_object)
|
||||
request_free_object(req->type, req->object);
|
||||
link_unref(req->link);
|
||||
|
@ -15,11 +15,6 @@ typedef struct NextHop NextHop;
|
||||
typedef struct Route Route;
|
||||
typedef struct RoutingPolicyRule RoutingPolicyRule;
|
||||
|
||||
typedef struct Request Request;
|
||||
|
||||
typedef int (*request_after_configure_handler_t)(Request*, void*);
|
||||
typedef void (*request_on_free_handler_t)(Request*);
|
||||
|
||||
typedef enum RequestType {
|
||||
REQUEST_TYPE_ACTIVATE_LINK,
|
||||
REQUEST_TYPE_ADDRESS,
|
||||
@ -63,8 +58,6 @@ typedef struct Request {
|
||||
void *userdata;
|
||||
unsigned *message_counter;
|
||||
link_netlink_message_handler_t netlink_handler;
|
||||
request_after_configure_handler_t after_configure;
|
||||
request_on_free_handler_t on_free;
|
||||
} Request;
|
||||
|
||||
void request_drop(Request *req);
|
||||
|
@ -7,11 +7,13 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "dns-domain.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-route.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
#include "string-table.h"
|
||||
@ -202,6 +204,54 @@ void network_adjust_radv(Network *network) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool link_radv_enabled(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
return false;
|
||||
|
||||
return link->network->router_prefix_delegation;
|
||||
}
|
||||
|
||||
int link_request_radv_addresses(Link *link) {
|
||||
Prefix *p;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link_radv_enabled(link))
|
||||
return 0;
|
||||
|
||||
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 r;
|
||||
|
||||
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
address->source = NETWORK_CONFIG_SOURCE_STATIC;
|
||||
address->family = AF_INET6;
|
||||
address->route_metric = p->route_metric;
|
||||
|
||||
r = link_request_static_address(link, TAKE_PTR(address), true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_prefix(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -660,15 +710,6 @@ static int radv_find_uplink(Link *link, Link **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool link_radv_enabled(Link *link) {
|
||||
assert(link);
|
||||
|
||||
if (!link_ipv6ll_enabled(link))
|
||||
return false;
|
||||
|
||||
return link->network->router_prefix_delegation;
|
||||
}
|
||||
|
||||
static int radv_configure(Link *link) {
|
||||
uint16_t router_lifetime;
|
||||
Link *uplink = NULL;
|
||||
|
@ -51,6 +51,8 @@ void network_drop_invalid_prefixes(Network *network);
|
||||
void network_drop_invalid_route_prefixes(Network *network);
|
||||
void network_adjust_radv(Network *network);
|
||||
|
||||
int link_request_radv_addresses(Link *link);
|
||||
|
||||
int radv_update_mac(Link *link);
|
||||
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
|
||||
uint32_t lifetime_preferred, uint32_t lifetime_valid);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,11 +16,13 @@ typedef struct Network Network;
|
||||
typedef struct Request Request;
|
||||
|
||||
typedef struct Route {
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
|
||||
Link *link;
|
||||
Manager *manager;
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
NetworkConfigSource source;
|
||||
NetworkConfigState state;
|
||||
union in_addr_union provider; /* DHCP server or router address */
|
||||
|
||||
int family;
|
||||
int gw_family;
|
||||
@ -52,7 +54,6 @@ typedef struct Route {
|
||||
bool protocol_set:1;
|
||||
bool pref_set:1;
|
||||
bool gateway_from_dhcp_or_ra:1;
|
||||
bool removing:1;
|
||||
|
||||
union in_addr_union gw;
|
||||
union in_addr_union dst;
|
||||
@ -66,7 +67,6 @@ typedef struct Route {
|
||||
|
||||
void route_hash_func(const Route *route, struct siphash *state);
|
||||
int route_compare_func(const Route *a, const Route *b);
|
||||
bool route_equal(const Route *r1, const Route *r2);
|
||||
extern const struct hash_ops route_hash_ops;
|
||||
|
||||
int route_new(Route **ret);
|
||||
@ -75,15 +75,16 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
|
||||
int route_dup(const Route *src, Route **ret);
|
||||
|
||||
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
|
||||
int route_remove(const Route *route, Manager *manager, Link *link);
|
||||
int route_remove(Route *route);
|
||||
|
||||
int link_has_route(Link *link, const Route *route);
|
||||
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
|
||||
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
|
||||
bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw);
|
||||
|
||||
int link_drop_routes(Link *link);
|
||||
int link_drop_foreign_routes(Link *link);
|
||||
|
||||
void route_cancel_request(Route *route);
|
||||
int link_request_route(
|
||||
Link *link,
|
||||
Route *route,
|
||||
@ -103,6 +104,9 @@ void network_drop_invalid_routes(Network *network);
|
||||
int manager_get_route_table_from_string(const Manager *m, const char *table, uint32_t *ret);
|
||||
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret);
|
||||
|
||||
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Route, route);
|
||||
void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_addr *router);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_destination);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "missing_network.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-can.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include "ether-addr-util.h"
|
||||
#include "hostname-setup.h"
|
||||
#include "network-internal.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-route.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
@ -168,6 +170,16 @@ static int test_load_config(Manager *manager) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool address_equal(const Address *a1, const Address *a2) {
|
||||
if (a1 == a2)
|
||||
return true;
|
||||
|
||||
if (!a1 || !a2)
|
||||
return false;
|
||||
|
||||
return address_compare_func(a1, a2) == 0;
|
||||
}
|
||||
|
||||
static void test_address_equality(void) {
|
||||
_cleanup_(address_freep) Address *a1 = NULL, *a2 = NULL;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "net-condition.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-conf.h"
|
||||
#include "networkd-network.h"
|
||||
#include "strv.h"
|
||||
|
Loading…
Reference in New Issue
Block a user