network: ndisc: remove old addresses and routes after at least one SLAAC address becomes ready
Otherwise, the old addresses will exist in deperecated state.
This commit is contained in:
parent
6e537f62d7
commit
69203fba70
|
@ -129,6 +129,8 @@ void address_free(Address *address) {
|
||||||
address->link->dhcp_address = NULL;
|
address->link->dhcp_address = NULL;
|
||||||
if (address->link->dhcp_address_old == address)
|
if (address->link->dhcp_address_old == address)
|
||||||
address->link->dhcp_address_old = NULL;
|
address->link->dhcp_address_old = NULL;
|
||||||
|
set_remove(address->link->ndisc_addresses, address);
|
||||||
|
set_remove(address->link->ndisc_addresses_old, address);
|
||||||
|
|
||||||
if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
|
if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
|
||||||
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
|
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
|
||||||
|
|
|
@ -714,6 +714,8 @@ static Link *link_free(Link *link) {
|
||||||
link->routes_foreign = set_free(link->routes_foreign);
|
link->routes_foreign = set_free(link->routes_foreign);
|
||||||
link->dhcp_routes = set_free(link->dhcp_routes);
|
link->dhcp_routes = set_free(link->dhcp_routes);
|
||||||
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
|
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
|
||||||
|
link->ndisc_routes = set_free(link->ndisc_routes);
|
||||||
|
link->ndisc_routes_old = set_free(link->ndisc_routes_old);
|
||||||
|
|
||||||
link->nexthops = set_free(link->nexthops);
|
link->nexthops = set_free(link->nexthops);
|
||||||
link->nexthops_foreign = set_free(link->nexthops_foreign);
|
link->nexthops_foreign = set_free(link->nexthops_foreign);
|
||||||
|
@ -723,6 +725,8 @@ static Link *link_free(Link *link) {
|
||||||
|
|
||||||
link->addresses = set_free(link->addresses);
|
link->addresses = set_free(link->addresses);
|
||||||
link->addresses_foreign = set_free(link->addresses_foreign);
|
link->addresses_foreign = set_free(link->addresses_foreign);
|
||||||
|
link->ndisc_addresses = set_free(link->ndisc_addresses);
|
||||||
|
link->ndisc_addresses_old = set_free(link->ndisc_addresses_old);
|
||||||
|
|
||||||
while ((address = link->pool_addresses)) {
|
while ((address = link->pool_addresses)) {
|
||||||
LIST_REMOVE(addresses, link->pool_addresses, address);
|
LIST_REMOVE(addresses, link->pool_addresses, address);
|
||||||
|
|
|
@ -142,6 +142,8 @@ typedef struct Link {
|
||||||
sd_ndisc *ndisc;
|
sd_ndisc *ndisc;
|
||||||
Set *ndisc_rdnss;
|
Set *ndisc_rdnss;
|
||||||
Set *ndisc_dnssl;
|
Set *ndisc_dnssl;
|
||||||
|
Set *ndisc_addresses, *ndisc_addresses_old;
|
||||||
|
Set *ndisc_routes, *ndisc_routes_old;
|
||||||
|
|
||||||
sd_radv *radv;
|
sd_radv *radv;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,69 @@
|
||||||
|
|
||||||
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
|
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
|
||||||
|
|
||||||
|
static int ndisc_remove_old(Link *link, bool force);
|
||||||
|
|
||||||
|
static int ndisc_address_callback(Address *address) {
|
||||||
|
Address *a;
|
||||||
|
Iterator i;
|
||||||
|
|
||||||
|
assert(address);
|
||||||
|
assert(address->link);
|
||||||
|
|
||||||
|
/* Make this called only once */
|
||||||
|
SET_FOREACH(a, address->link->ndisc_addresses, i)
|
||||||
|
a->callback = NULL;
|
||||||
|
|
||||||
|
return ndisc_remove_old(address->link, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ndisc_remove_old(Link *link, bool force) {
|
||||||
|
Address *address;
|
||||||
|
Route *route;
|
||||||
|
Iterator i;
|
||||||
|
int k, r = 0;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (!force) {
|
||||||
|
bool set_callback = !set_isempty(link->ndisc_addresses);
|
||||||
|
|
||||||
|
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SET_FOREACH(address, link->ndisc_addresses, i)
|
||||||
|
if (address_is_ready(address)) {
|
||||||
|
set_callback = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_callback) {
|
||||||
|
SET_FOREACH(address, link->ndisc_addresses, i)
|
||||||
|
address->callback = ndisc_address_callback;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_isempty(link->ndisc_addresses_old) || !set_isempty(link->ndisc_routes_old))
|
||||||
|
log_link_debug(link, "Removing old NDisc addresses and routes.");
|
||||||
|
|
||||||
|
link_dirty(link);
|
||||||
|
|
||||||
|
SET_FOREACH(address, link->ndisc_addresses_old, i) {
|
||||||
|
k = address_remove(address, link, NULL);
|
||||||
|
if (k < 0)
|
||||||
|
r = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_FOREACH(route, link->ndisc_routes_old, i) {
|
||||||
|
k = route_remove(route, link, NULL);
|
||||||
|
if (k < 0)
|
||||||
|
r = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -56,6 +119,13 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
||||||
if (link->ndisc_routes_messages == 0) {
|
if (link->ndisc_routes_messages == 0) {
|
||||||
log_link_debug(link, "NDisc routes set.");
|
log_link_debug(link, "NDisc routes set.");
|
||||||
link->ndisc_routes_configured = true;
|
link->ndisc_routes_configured = true;
|
||||||
|
|
||||||
|
r = ndisc_remove_old(link, false);
|
||||||
|
if (r < 0) {
|
||||||
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
link_check_ready(link);
|
link_check_ready(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +154,13 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
||||||
if (link->ndisc_addresses_messages == 0) {
|
if (link->ndisc_addresses_messages == 0) {
|
||||||
log_link_debug(link, "NDisc SLAAC addresses set.");
|
log_link_debug(link, "NDisc SLAAC addresses set.");
|
||||||
link->ndisc_addresses_configured = true;
|
link->ndisc_addresses_configured = true;
|
||||||
|
|
||||||
|
r = ndisc_remove_old(link, false);
|
||||||
|
if (r < 0) {
|
||||||
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
r = link_request_set_routes(link);
|
r = link_request_set_routes(link);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
|
@ -94,6 +171,50 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ndisc_route_configure(Route *route, Link *link) {
|
||||||
|
Route *ret;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(route);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
r = route_configure(route, link, ndisc_route_handler, &ret);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
|
||||||
|
|
||||||
|
link->ndisc_routes_messages++;
|
||||||
|
|
||||||
|
r = set_ensure_put(&link->ndisc_routes, &route_hash_ops, ret);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to store NDisc route: %m");
|
||||||
|
|
||||||
|
(void) set_remove(link->ndisc_routes_old, ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ndisc_address_configure(Address *address, Link *link) {
|
||||||
|
Address *ret;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(address);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
r = address_configure(address, link, ndisc_address_handler, true, &ret);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
|
||||||
|
|
||||||
|
link->ndisc_addresses_messages++;
|
||||||
|
|
||||||
|
r = set_ensure_put(&link->ndisc_addresses, &address_hash_ops, ret);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
|
||||||
|
|
||||||
|
(void) set_remove(link->ndisc_addresses_old, ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||||
_cleanup_(route_freep) Route *route = NULL;
|
_cleanup_(route_freep) Route *route = NULL;
|
||||||
union in_addr_union gateway;
|
union in_addr_union gateway;
|
||||||
|
@ -155,11 +276,9 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||||
route->lifetime = time_now + lifetime * USEC_PER_SEC;
|
route->lifetime = time_now + lifetime * USEC_PER_SEC;
|
||||||
route->mtu = mtu;
|
route->mtu = mtu;
|
||||||
|
|
||||||
r = route_configure(route, link, ndisc_route_handler, NULL);
|
r = ndisc_route_configure(route, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not set default route: %m");
|
return log_link_error_errno(link, r, "Could not set default route: %m");
|
||||||
if (r > 0)
|
|
||||||
link->ndisc_routes_messages++;
|
|
||||||
|
|
||||||
Route *route_gw;
|
Route *route_gw;
|
||||||
LIST_FOREACH(routes, route_gw, link->network->static_routes) {
|
LIST_FOREACH(routes, route_gw, link->network->static_routes) {
|
||||||
|
@ -171,11 +290,9 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
||||||
|
|
||||||
route_gw->gw = gateway;
|
route_gw->gw = gateway;
|
||||||
|
|
||||||
r = route_configure(route_gw, link, ndisc_route_handler, NULL);
|
r = ndisc_route_configure(route_gw, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not set gateway: %m");
|
return log_link_error_errno(link, r, "Could not set gateway: %m");
|
||||||
if (r > 0)
|
|
||||||
link->ndisc_routes_messages++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -387,11 +504,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||||
|
|
||||||
address->in_addr.in6 = *a;
|
address->in_addr.in6 = *a;
|
||||||
|
|
||||||
r = address_configure(address, link, ndisc_address_handler, true, NULL);
|
r = ndisc_address_configure(address, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
|
return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
|
||||||
if (r > 0)
|
|
||||||
link->ndisc_addresses_messages++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -435,11 +550,9 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||||
|
|
||||||
r = route_configure(route, link, ndisc_route_handler, NULL);
|
r = ndisc_route_configure(route, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not set prefix route: %m");;
|
return log_link_error_errno(link, r, "Could not set prefix route: %m");;
|
||||||
if (r > 0)
|
|
||||||
link->ndisc_routes_messages++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -494,11 +607,9 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get route address: %m");
|
return log_link_error_errno(link, r, "Failed to get route address: %m");
|
||||||
|
|
||||||
r = route_configure(route, link, ndisc_route_handler, NULL);
|
r = ndisc_route_configure(route, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not set additional route: %m");
|
return log_link_error_errno(link, r, "Could not set additional route: %m");
|
||||||
if (r > 0)
|
|
||||||
link->ndisc_routes_messages++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -736,6 +847,8 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
|
Address *address;
|
||||||
|
Route *route;
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -744,6 +857,23 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
assert(rt);
|
assert(rt);
|
||||||
|
|
||||||
|
link->ndisc_addresses_configured = false;
|
||||||
|
link->ndisc_routes_configured = false;
|
||||||
|
|
||||||
|
link_dirty(link);
|
||||||
|
|
||||||
|
while ((address = set_steal_first(link->ndisc_addresses))) {
|
||||||
|
r = set_ensure_put(&link->ndisc_addresses_old, &address_hash_ops, address);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to store old NDisc SLAAC address: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((route = set_steal_first(link->ndisc_routes))) {
|
||||||
|
r = set_ensure_put(&link->ndisc_routes_old, &route_hash_ops, route);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Failed to store old NDisc route: %m");
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_ndisc_router_get_flags(rt, &flags);
|
r = sd_ndisc_router_get_flags(rt, &flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get RA flags: %m");
|
return log_link_error_errno(link, r, "Failed to get RA flags: %m");
|
||||||
|
@ -757,10 +887,8 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
|
r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
|
||||||
if (r < 0 && r != -EBUSY)
|
if (r < 0 && r != -EBUSY)
|
||||||
return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
|
return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
|
||||||
else {
|
else
|
||||||
log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
|
log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ndisc_router_process_default(link, rt);
|
r = ndisc_router_process_default(link, rt);
|
||||||
|
@ -770,7 +898,33 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return r;
|
if (link->ndisc_addresses_messages == 0)
|
||||||
|
link->ndisc_addresses_configured = true;
|
||||||
|
else {
|
||||||
|
log_link_debug(link, "Setting SLAAC addresses.");
|
||||||
|
|
||||||
|
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
|
||||||
|
* Before they are called, the related flags must be cleared. Otherwise, the link
|
||||||
|
* becomes configured state before routes are configured. */
|
||||||
|
link->static_routes_configured = false;
|
||||||
|
link->static_nexthops_configured = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (link->ndisc_routes_messages == 0)
|
||||||
|
link->ndisc_routes_configured = true;
|
||||||
|
else
|
||||||
|
log_link_debug(link, "Setting NDisc routes.");
|
||||||
|
|
||||||
|
r = ndisc_remove_old(link, false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
|
||||||
|
link_check_ready(link);
|
||||||
|
else
|
||||||
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
|
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
|
||||||
|
@ -785,36 +939,11 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
|
||||||
case SD_NDISC_EVENT_ROUTER:
|
case SD_NDISC_EVENT_ROUTER:
|
||||||
link->ndisc_addresses_configured = false;
|
|
||||||
link->ndisc_routes_configured = false;
|
|
||||||
|
|
||||||
r = ndisc_router_handler(link, rt);
|
r = ndisc_router_handler(link, rt);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->ndisc_addresses_messages == 0)
|
|
||||||
link->ndisc_addresses_configured = true;
|
|
||||||
else {
|
|
||||||
log_link_debug(link, "Setting SLAAC addresses.");
|
|
||||||
|
|
||||||
/* address_handler calls link_request_set_routes() and link_request_set_nexthop().
|
|
||||||
* Before they are called, the related flags must be cleared. Otherwise, the link
|
|
||||||
* becomes configured state before routes are configured. */
|
|
||||||
link->static_routes_configured = false;
|
|
||||||
link->static_nexthops_configured = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link->ndisc_routes_messages == 0)
|
|
||||||
link->ndisc_routes_configured = true;
|
|
||||||
else
|
|
||||||
log_link_debug(link, "Setting NDisc routes.");
|
|
||||||
|
|
||||||
if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
|
|
||||||
link_check_ready(link);
|
|
||||||
else
|
|
||||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_NDISC_EVENT_TIMEOUT:
|
case SD_NDISC_EVENT_TIMEOUT:
|
||||||
|
|
|
@ -146,6 +146,8 @@ void route_free(Route *route) {
|
||||||
set_remove(route->link->routes_foreign, route);
|
set_remove(route->link->routes_foreign, route);
|
||||||
set_remove(route->link->dhcp_routes, route);
|
set_remove(route->link->dhcp_routes, route);
|
||||||
set_remove(route->link->dhcp_routes_old, route);
|
set_remove(route->link->dhcp_routes_old, route);
|
||||||
|
set_remove(route->link->ndisc_routes, route);
|
||||||
|
set_remove(route->link->ndisc_routes_old, route);
|
||||||
}
|
}
|
||||||
|
|
||||||
ordered_set_free_free(route->multipath_routes);
|
ordered_set_free_free(route->multipath_routes);
|
||||||
|
|
Loading…
Reference in a new issue