]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: Don't send RA with zero router lifetime when restarting radv
authorMichael Marley <michael@michaelmarley.com>
Sun, 5 Jul 2020 10:46:27 +0000 (06:46 -0400)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 7 Jul 2020 01:49:25 +0000 (10:49 +0900)
While investigating https://github.com/systemd/systemd/issues/16356, I
discovered that networkd stops the radv service before adding or updating
prefixes and then starts it again.  This causes networkd to send an RA with
a router lifetime of zero, causing the routes to flap on systems receiving
the RA for a fraction of a second before radv is started again and proper
RAs are sent.  That has the potential to cause issues with latency-sensitive
traffic like gaming or VoIP.  This patch adds a boolean argument to the
sd_radv_stop() function to control this behavior.  The zero lifetime RA is
still sent whenever radv is actually being stopped, but when it is being
restarted for a prefix update (from networkd-dhcp6.c), the final RA is no
longer sent to avoid the route flapping.

src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-ndisc-ra.c
src/network/networkd-dhcp6.c
src/network/networkd-link.c
src/systemd/sd-radv.h

index cc5c0223b5cee459785ec68f94e1176e3747a3b0..ee7c0ee53fcdfb2d69f79af9c9d28b9e1fc29041 100644 (file)
@@ -339,12 +339,12 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         return 0;
 
 fail:
-        sd_radv_stop(ra);
+        sd_radv_stop(ra, true);
 
         return 0;
 }
 
-_public_ int sd_radv_stop(sd_radv *ra) {
+_public_ int sd_radv_stop(sd_radv *ra, bool zero_router_lifetime) {
         int r;
 
         assert_return(ra, -EINVAL);
@@ -354,11 +354,15 @@ _public_ int sd_radv_stop(sd_radv *ra) {
 
         log_radv("Stopping IPv6 Router Advertisement daemon");
 
-        /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
-           with zero lifetime  */
-        r = radv_send(ra, NULL, 0);
-        if (r < 0)
-                log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
+        if (zero_router_lifetime) {
+                /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
+                with zero lifetime  */
+                r = radv_send(ra, NULL, 0);
+                if (r < 0)
+                        log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
+                else
+                        log_radv("Sent last Router Advertisement with router lifetime set to zero");
+        }
 
         radv_reset(ra);
         ra->fd = safe_close(ra->fd);
index d759ec03a8ad9efbda2a28cfb66855bfc4a7372a..7c59418ca7dd3d83b13c326d0e6ecf1f090e5949 100644 (file)
@@ -284,7 +284,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 return 0;
         }
 
-        assert_se(sd_radv_stop(ra) >= 0);
+        assert_se(sd_radv_stop(ra, true) >= 0);
         test_stopped = true;
 
         return 0;
index ecf8a32691d4d5a599be95b4eba0afbe537d1562..d9df46a23ee299081d5e34509105f28e96ef3705 100644 (file)
@@ -188,7 +188,7 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
         if (r < 0)
                 return r;
 
-        r = sd_radv_stop(radv);
+        r = sd_radv_stop(radv, false);
         if (r < 0)
                 return r;
 
index 053aa3b4cee7c53d3021ba77e4d04f0887fcf772..dcbf197ff46adf84bae0a4326108fc77713a3874 100644 (file)
@@ -840,7 +840,7 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
         }
 
         if (link->radv) {
-                k = sd_radv_stop(link->radv);
+                k = sd_radv_stop(link->radv, true);
                 if (k < 0)
                         r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
         }
index 011e40d8a5c68552a637503a62f63924408acc54..763d5ddd87de52716668b8773bf6b3af47cf687d 100644 (file)
@@ -22,6 +22,7 @@
 #include <inttypes.h>
 #include <net/ethernet.h>
 #include <netinet/in.h>
+#include <stdbool.h>
 #include <sys/types.h>
 
 #include "_sd-common.h"
@@ -49,7 +50,7 @@ int sd_radv_detach_event(sd_radv *nd);
 sd_event *sd_radv_get_event(sd_radv *ra);
 
 int sd_radv_start(sd_radv *ra);
-int sd_radv_stop(sd_radv *ra);
+int sd_radv_stop(sd_radv *ra, bool zero_router_lifetime);
 
 int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
 int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);