]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: ndisc: remove old addresses and routes after at least one SLAAC address...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 22 Jul 2020 02:55:07 +0000 (11:55 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 28 Jul 2020 17:05:05 +0000 (02:05 +0900)
Otherwise, the old addresses will exist in deperecated state.

src/network/networkd-address.c
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-ndisc.c
src/network/networkd-route.c

index 6fc3074eac0d3b6ee5c6065c84cae6d5c30964cd..1d2db3a6ba373ddad217b7bdf0e88236099d830a 100644 (file)
@@ -129,6 +129,8 @@ void address_free(Address *address) {
                         address->link->dhcp_address = NULL;
                 if (address->link->dhcp_address_old == address)
                         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))
                         memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
index 6db57b9f3d2de7202f52ffca381a8617a280aeac..79bbd25fba0423be9d69c222d9875150f7089c40 100644 (file)
@@ -714,6 +714,8 @@ static Link *link_free(Link *link) {
         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->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_foreign = set_free(link->nexthops_foreign);
@@ -723,6 +725,8 @@ static Link *link_free(Link *link) {
 
         link->addresses = set_free(link->addresses);
         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)) {
                 LIST_REMOVE(addresses, link->pool_addresses, address);
index f837ec2a24a4de537dad3243723e39f5b0ea5630..290e84a06ec9a8c2e85fa2583a958f9570573a72 100644 (file)
@@ -142,6 +142,8 @@ typedef struct Link {
         sd_ndisc *ndisc;
         Set *ndisc_rdnss;
         Set *ndisc_dnssl;
+        Set *ndisc_addresses, *ndisc_addresses_old;
+        Set *ndisc_routes, *ndisc_routes_old;
 
         sd_radv *radv;
 
index 2f6cc4042e1901a7e8089d56fe2646540de33737..0c86fa139b7375652dab7faae8905f797df89781 100644 (file)
 
 #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) {
         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) {
                 log_link_debug(link, "NDisc routes set.");
                 link->ndisc_routes_configured = true;
+
+                r = ndisc_remove_old(link, false);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return 1;
+                }
+
                 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) {
                 log_link_debug(link, "NDisc SLAAC addresses set.");
                 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);
                 if (r < 0) {
                         link_enter_failed(link);
@@ -94,6 +171,50 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
         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) {
         _cleanup_(route_freep) Route *route = NULL;
         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->mtu = mtu;
 
-        r = route_configure(route, link, ndisc_route_handler, NULL);
+        r = ndisc_route_configure(route, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set default route: %m");
-        if (r > 0)
-                link->ndisc_routes_messages++;
 
         Route *route_gw;
         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;
 
-                r = route_configure(route_gw, link, ndisc_route_handler, NULL);
+                r = ndisc_route_configure(route_gw, link);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set gateway: %m");
-                if (r > 0)
-                        link->ndisc_routes_messages++;
         }
 
         return 0;
@@ -387,11 +504,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
 
                 address->in_addr.in6 = *a;
 
-                r = address_configure(address, link, ndisc_address_handler, true, NULL);
+                r = ndisc_address_configure(address, link);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
-                if (r > 0)
-                        link->ndisc_addresses_messages++;
         }
 
         return 0;
@@ -435,11 +550,9 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 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)
                 return log_link_error_errno(link, r, "Could not set prefix route: %m");;
-        if (r > 0)
-                link->ndisc_routes_messages++;
 
         return 0;
 }
@@ -494,11 +607,9 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 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)
                 return log_link_error_errno(link, r, "Could not set additional route: %m");
-        if (r > 0)
-                link->ndisc_routes_messages++;
 
         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) {
+        Address *address;
+        Route *route;
         uint64_t flags;
         int r;
 
@@ -744,6 +857,23 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
         assert(link->manager);
         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);
         if (r < 0)
                 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));
                 if (r < 0 && r != -EBUSY)
                         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");
-                        r = 0;
-                }
         }
 
         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)
                 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) {
@@ -785,36 +939,11 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r
         switch (event) {
 
         case SD_NDISC_EVENT_ROUTER:
-                link->ndisc_addresses_configured = false;
-                link->ndisc_routes_configured = false;
-
                 r = ndisc_router_handler(link, rt);
                 if (r < 0) {
                         link_enter_failed(link);
                         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;
 
         case SD_NDISC_EVENT_TIMEOUT:
index 322e819bc1e65484d7205388beb8df95f716d03d..d04c33a5d879280e4b19e86883143f7a1a0b3ffa 100644 (file)
@@ -146,6 +146,8 @@ void route_free(Route *route) {
                 set_remove(route->link->routes_foreign, route);
                 set_remove(route->link->dhcp_routes, 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);