From: Yu Watanabe Date: Fri, 23 Feb 2024 02:42:33 +0000 (+0900) Subject: network/ndisc: remember the latest RA from the default router X-Git-Tag: v256-rc1~264^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b03d7291d554547f805377060284d6914ba45e96;p=thirdparty%2Fsystemd.git network/ndisc: remember the latest RA from the default router The remembered RA will be used later. Preparation for later commits. --- diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index b3e8bb001fe..01931f6773e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -160,6 +160,7 @@ typedef struct Link { sd_dhcp_server *dhcp_server; sd_ndisc *ndisc; + sd_ndisc_router *ndisc_default_router; sd_event_source *ndisc_expire; Set *ndisc_rdnss; Set *ndisc_dnssl; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 71e3c30727e..6be0c0f9d9b 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -505,6 +505,126 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { return 0; } +static int update_default_router_address(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) { + struct in6_addr a; + int r; + + assert(link); + assert(original_address); + assert(current_address); + + if (!link->ndisc_default_router) + return 0; + + r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a); + if (r < 0) + return r; + + if (!in6_addr_equal(&a, original_address)) + return 0; + + return sd_ndisc_router_set_sender_address(link->ndisc_default_router, current_address); +} + +static int drop_default_router(Link *link, const struct in6_addr *router, usec_t timestamp_usec) { + usec_t lifetime_usec; + int r; + + assert(link); + + if (!link->ndisc_default_router) + return 0; + + if (router) { + struct in6_addr a; + + r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a); + if (r < 0) + return r; + + if (!in6_addr_equal(&a, router)) + return 0; + } + + r = sd_ndisc_router_get_lifetime_timestamp(link->ndisc_default_router, CLOCK_BOOTTIME, &lifetime_usec); + if (r < 0) + return r; + + if (lifetime_usec > timestamp_usec) + return 0; + + link->ndisc_default_router = sd_ndisc_router_unref(link->ndisc_default_router); + return 0; +} + +static int accept_default_router(sd_ndisc_router *new_router, sd_ndisc_router *existing_router) { + usec_t lifetime_usec; + struct in6_addr a, b; + uint8_t p, q; + int r; + + assert(new_router); + + r = sd_ndisc_router_get_lifetime(new_router, &lifetime_usec); + if (r < 0) + return r; + + if (lifetime_usec == 0) + return false; /* Received a new RA about revoking the router, ignoring. */ + + if (!existing_router) + return true; + + /* lifetime of the existing router is already checked in ndisc_drop_outdated(). */ + + r = sd_ndisc_router_get_sender_address(new_router, &a); + if (r < 0) + return r; + + r = sd_ndisc_router_get_sender_address(existing_router, &b); + if (r < 0) + return r; + + if (in6_addr_equal(&a, &b)) + return true; /* Received a new RA from the remembered router. Replace the remembered RA. */ + + r = sd_ndisc_router_get_preference(new_router, &p); + if (r < 0) + return r; + + r = sd_ndisc_router_get_preference(existing_router, &q); + if (r < 0) + return r; + + if (p == q) + return true; + + if (p == SD_NDISC_PREFERENCE_HIGH) + return true; + + if (p == SD_NDISC_PREFERENCE_MEDIUM && q == SD_NDISC_PREFERENCE_LOW) + return true; + + return false; +} + +static int ndisc_remember_default_router(Link *link, sd_ndisc_router *rt) { + int r; + + assert(link); + assert(rt); + + r = accept_default_router(rt, link->ndisc_default_router); + if (r <= 0) + return r; + + sd_ndisc_router_ref(rt); + sd_ndisc_router_unref(link->ndisc_default_router); + link->ndisc_default_router = rt; + + return 1; /* The received router advertisement is from the default router. */ +} + static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) { usec_t reachable_time, msec; int r; @@ -1410,6 +1530,10 @@ static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t * valid lifetimes to improve the reaction of SLAAC to renumbering events. * See draft-ietf-6man-slaac-renum-02, section 4.2. */ + r = drop_default_router(link, router, timestamp_usec); + if (r < 0) + RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to drop outdated default router, ignoring: %m")); + SET_FOREACH(route, link->manager->routes) { if (route->source != NETWORK_CONFIG_SOURCE_NDISC) continue; @@ -1657,6 +1781,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { if (r < 0) return r; + r = ndisc_remember_default_router(link, rt); + if (r < 0) + return r; + r = ndisc_start_dhcp6_client(link, rt); if (r < 0) return r; @@ -1743,6 +1871,10 @@ static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *n if (in6_addr_equal(¤t_address, &original_address)) return 0; /* the router address is not changed */ + r = update_default_router_address(link, &original_address, ¤t_address); + if (r < 0) + return r; + Route *route; SET_FOREACH(route, link->manager->routes) { if (route->source != NETWORK_CONFIG_SOURCE_NDISC)