diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 9cccf25cb9..1f722aca52 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -428,6 +428,7 @@ int address_remove( sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + _cleanup_free_ char *b = NULL; int r; assert(address); @@ -437,6 +438,11 @@ int address_remove( assert(link->manager); assert(link->manager->rtnl); + if (DEBUG_LOGGING) { + if (in_addr_to_string(address->family, &address->in_addr, &b) >= 0) + log_link_debug(link, "Removing address %s", b); + } + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 08bfa6db8f..2c0c04985d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2618,6 +2618,38 @@ static int link_set_ipv6_mtu(Link *link) { return 0; } +static bool link_is_static_address_configured(Link *link, Address *address) { + Address *net_address; + + assert(link); + assert(address); + + if (!link->network) + return false; + + LIST_FOREACH(addresses, net_address, link->network->static_addresses) + if (address_equal(net_address, address)) + return true; + + return false; +} + +static bool link_is_static_route_configured(Link *link, Route *route) { + Route *net_route; + + assert(link); + assert(route); + + if (!link->network) + return false; + + LIST_FOREACH(routes, net_route, link->network->static_routes) + if (route_equal(net_route, route)) + return true; + + return false; +} + static int link_drop_foreign_config(Link *link) { Address *address; Route *route; @@ -2629,9 +2661,15 @@ static int link_drop_foreign_config(Link *link) { if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1) continue; - r = address_remove(address, link, link_address_remove_handler); - if (r < 0) - return r; + if (link_is_static_address_configured(link, address)) { + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add address: %m"); + } else { + r = address_remove(address, link, link_address_remove_handler); + if (r < 0) + return r; + } } SET_FOREACH(route, link->routes_foreign, i) { @@ -2639,9 +2677,15 @@ static int link_drop_foreign_config(Link *link) { if (route->protocol == RTPROT_KERNEL) continue; - r = route_remove(route, link, link_route_remove_handler); - if (r < 0) - return r; + if (link_is_static_route_configured(link, route)) { + r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL); + if (r < 0) + return r; + } else { + r = route_remove(route, link, link_route_remove_handler); + if (r < 0) + return r; + } } return 0; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 529d942f15..e8cde66bef 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -201,6 +201,16 @@ static const struct hash_ops route_hash_ops = { .compare = route_compare_func }; +bool route_equal(Route *r1, Route *r2) { + if (r1 == r2) + return true; + + if (!r1 || !r2) + return false; + + return route_compare_func(r1, r2) == 0; +} + int route_get(Link *link, int family, const union in_addr_union *dst, diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 7283f48304..fe000d61b8 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -52,6 +52,7 @@ int route_get(Link *link, int family, const union in_addr_union *dst, unsigned c int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); void route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type); +bool route_equal(Route *r1, Route *r2); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);