]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/dhcp-pd: do not remove unreachable route when reconfiguring non-upstream...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 7 Nov 2024 00:16:06 +0000 (09:16 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 11 Nov 2024 02:53:24 +0000 (11:53 +0900)
Unreachable routes are not owned by any interfaces, and its ifindex is
zero. Previously, if a non-upstream interface is reconfigured, all routes
including unreachable routes configured by the upstream interface are
removed.

This makes unreachable routes are always handled by the upstream interface,
and only removed when the delegated prefixes are changed or lost.

src/network/networkd-dhcp-prefix-delegation.c
src/network/networkd-dhcp-prefix-delegation.h
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c

index 0819ed54f135ea6e2dba891696855e3eb0aebd5e..7a5d0e04150f798ac33ad7bfa51a7aef15c23e86 100644 (file)
@@ -613,8 +613,49 @@ static int dhcp_pd_finalize(Link *link) {
         return 0;
 }
 
-void dhcp_pd_prefix_lost(Link *uplink) {
+static void dhcp_pd_mark_unreachable_route(Manager *manager, NetworkConfigSource source) {
+        assert(manager);
+
+        Route *route;
+        SET_FOREACH(route, manager->routes) {
+                if (route->source != source)
+                        continue;
+                if (route->family != AF_INET6)
+                        continue;
+                if (route->nexthop.ifindex != 0) /* IPv6 unreachable has 0 ifindex. */
+                        continue;
+                if (!route_type_is_reject(route->type))
+                        continue;
+
+                route_mark(route);
+        }
+}
+
+static int dhcp_pd_remove_unreachable_route(Manager *manager, NetworkConfigSource source, bool only_marked) {
+        int ret = 0;
+
+        assert(manager);
+
         Route *route;
+        SET_FOREACH(route, manager->routes) {
+                if (route->source != source)
+                        continue;
+                if (route->family != AF_INET6)
+                        continue;
+                if (route->nexthop.ifindex != 0) /* IPv6 unreachable has 0 ifindex. */
+                        continue;
+                if (!route_type_is_reject(route->type))
+                        continue;
+                if (only_marked && !route_is_marked(route))
+                        continue;
+
+                RET_GATHER(ret, route_remove_and_cancel(route, manager));
+        }
+
+        return ret;
+}
+
+static void dhcp_pd_prefix_lost(Link *uplink, NetworkConfigSource source) {
         Link *link;
         int r;
 
@@ -630,22 +671,7 @@ void dhcp_pd_prefix_lost(Link *uplink) {
                         link_enter_failed(link);
         }
 
-        SET_FOREACH(route, uplink->manager->routes) {
-                if (!IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
-                        continue;
-                if (route->family != AF_INET6)
-                        continue;
-                if (route->type != RTN_UNREACHABLE)
-                        continue;
-                if (!set_contains(uplink->dhcp_pd_prefixes,
-                                  &(struct in_addr_prefix) {
-                                          .family = AF_INET6,
-                                          .prefixlen = route->dst_prefixlen,
-                                          .address = route->dst }))
-                        continue;
-
-                (void) route_remove_and_cancel(route, uplink->manager);
-        }
+        (void) dhcp_pd_remove_unreachable_route(uplink->manager, source, /* only_marked = */ false);
 
         set_clear(uplink->dhcp_pd_prefixes);
 }
@@ -653,13 +679,20 @@ void dhcp_pd_prefix_lost(Link *uplink) {
 void dhcp4_pd_prefix_lost(Link *uplink) {
         Link *tunnel;
 
-        dhcp_pd_prefix_lost(uplink);
+        assert(uplink);
+        assert(uplink->manager);
+
+        dhcp_pd_prefix_lost(uplink, NETWORK_CONFIG_SOURCE_DHCP4);
 
         if (uplink->dhcp4_6rd_tunnel_name &&
             link_get_by_name(uplink->manager, uplink->dhcp4_6rd_tunnel_name, &tunnel) >= 0)
                 (void) link_remove(tunnel);
 }
 
+void dhcp6_pd_prefix_lost(Link *uplink) {
+        dhcp_pd_prefix_lost(uplink, NETWORK_CONFIG_SOURCE_DHCP6);
+}
+
 static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
         int r;
 
@@ -1005,9 +1038,11 @@ int dhcp4_pd_prefix_acquired(Link *uplink) {
                 return r;
 
         /* Request unreachable route */
+        dhcp_pd_mark_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP4);
         r = dhcp4_request_unreachable_route(uplink, &pd_prefix, pd_prefixlen, lifetime_usec, &server_address);
         if (r < 0)
                 return r;
+        (void) dhcp_pd_remove_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP4, /* only_marked = */ true);
 
         /* Create or update 6rd SIT tunnel device. */
         r = dhcp4_pd_create_6rd_tunnel(uplink, dhcp4_pd_6rd_tunnel_create_handler);
@@ -1085,11 +1120,14 @@ int dhcp6_pd_prefix_acquired(Link *uplink) {
 
         assert(uplink);
         assert(uplink->dhcp6_lease);
+        assert(uplink->manager);
 
         r = sd_dhcp6_lease_get_server_address(uplink->dhcp6_lease, &server_address.in6);
         if (r < 0)
                 return log_link_warning_errno(uplink, r, "Failed to get server address of DHCPv6 lease: %m");
 
+        dhcp_pd_mark_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP6);
+
         /* First, logs acquired prefixes and request unreachable routes. */
         FOREACH_DHCP6_PD_PREFIX(uplink->dhcp6_lease) {
                 usec_t lifetime_valid_usec;
@@ -1120,6 +1158,8 @@ int dhcp6_pd_prefix_acquired(Link *uplink) {
                         return r;
         }
 
+        (void) dhcp_pd_remove_unreachable_route(uplink->manager, NETWORK_CONFIG_SOURCE_DHCP6, /* only_marked = */ true);
+
         /* Then, assign subnet prefixes. */
         HASHMAP_FOREACH(link, uplink->manager->links_by_index) {
                 if (!dhcp_pd_is_uplink(link, uplink, /* accept_auto = */ true))
index 099e1444a5467597f5d4805c248ba078426e437a..27e920e1cf06280a79b94a447beca288342fad77 100644 (file)
@@ -20,8 +20,8 @@ int dhcp_request_prefix_delegation(Link *link);
 int link_drop_dhcp_pd_config(Link *link, Network *network);
 int dhcp4_pd_prefix_acquired(Link *uplink);
 int dhcp6_pd_prefix_acquired(Link *uplink);
-void dhcp_pd_prefix_lost(Link *uplink);
 void dhcp4_pd_prefix_lost(Link *uplink);
+void dhcp6_pd_prefix_lost(Link *uplink);
 int dhcp_pd_reconfigure_address(Address *address, Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_pd_subnet_id);
index ca4e2a592611193d011b04bae57d0017caac8c0a..dae1a7b7f4ee9d6423e4c91d0a5a73df388d1228 100644 (file)
@@ -247,7 +247,7 @@ static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
         SET_FOREACH(route, link->manager->routes) {
                 if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
                         continue;
-                if (route->nexthop.ifindex != 0 && route->nexthop.ifindex != link->ifindex)
+                if (route->nexthop.ifindex != link->ifindex)
                         continue;
                 if (only_marked && !route_is_marked(route))
                         continue;
index 88e7c0a263d9b56e6c6f60c917ab951575a13f50..a6808fdb757548438e3fc69466cee317099a47b1 100644 (file)
@@ -307,7 +307,6 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
         int r;
 
         link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP6);
-        manager_mark_routes(link->manager, NULL, NETWORK_CONFIG_SOURCE_DHCP6);
 
         r = sd_dhcp6_client_get_lease(client, &lease);
         if (r < 0)
@@ -330,7 +329,7 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) {
                         return r;
         } else if (sd_dhcp6_lease_has_pd_prefix(lease_old))
                 /* When we had PD prefixes but not now, we need to remove them. */
-                dhcp_pd_prefix_lost(link);
+                dhcp6_pd_prefix_lost(link);
 
         if (link->dhcp6_messages == 0) {
                 link->dhcp6_configured = true;
@@ -377,7 +376,7 @@ static int dhcp6_lease_lost(Link *link) {
         log_link_info(link, "DHCPv6 lease lost");
 
         if (sd_dhcp6_lease_has_pd_prefix(link->dhcp6_lease))
-                dhcp_pd_prefix_lost(link);
+                dhcp6_pd_prefix_lost(link);
 
         link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);