]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-radv: update how to calculate interval of sending advertisements
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 27 Oct 2021 07:08:22 +0000 (16:08 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 27 Oct 2021 10:27:23 +0000 (19:27 +0900)
src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c

index 1f1c248c0a0263c9fecdc57c768043b1937380a9..260d1a826fec753478558ef6e1e84e5bc5a4b233 100644 (file)
@@ -17,6 +17,8 @@
  * The maximum time allowed between sending unsolicited multicast Router Advertisements from the
  * interface, in seconds. MUST be no less than 4 seconds and no greater than 1800 seconds.
  * Default: 600 seconds */
+#define RADV_MIN_MAX_TIMEOUT_USEC                 (4 * USEC_PER_SEC)
+#define RADV_MAX_MAX_TIMEOUT_USEC                 (1800 * USEC_PER_SEC)
 #define RADV_DEFAULT_MAX_TIMEOUT_USEC             (600 * USEC_PER_SEC)
 /* RFC 4861 section 6.2.1.
  * MinRtrAdvInterval
@@ -24,7 +26,7 @@
  * interface, in seconds. MUST be no less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
  * Default: 0.33 * MaxRtrAdvInterval If MaxRtrAdvInterval >= 9 seconds; otherwise, the Default is
  * MaxRtrAdvInterval (Note, this should be a typo. We use 0.75 * MaxRtrAdvInterval). */
-#define RADV_DEFAULT_MIN_TIMEOUT_USEC             (RADV_DEFAULT_MAX_TIMEOUT_USEC / 3)
+#define RADV_MIN_MIN_TIMEOUT_USEC                 (3 * USEC_PER_SEC)
 /* RFC 4861 section 6.2.4.
  * AdvDefaultLifetime
  * The value to be placed in the Router Lifetime field of Router Advertisements sent from the interface,
@@ -34,7 +36,7 @@
  * point-to-point link the peers may have enough information about the number and status of devices at
  * the other end so that advertisements are needed less frequently.
  * Default: 3 * MaxRtrAdvInterval */
-#define RADV_MIN_ROUTER_LIFETIME_USEC             (4 * USEC_PER_SEC)
+#define RADV_MIN_ROUTER_LIFETIME_USEC             RADV_MIN_MAX_TIMEOUT_USEC
 #define RADV_MAX_ROUTER_LIFETIME_USEC             (9000 * USEC_PER_SEC)
 #define RADV_DEFAULT_ROUTER_LIFETIME_USEC         (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
 /* RFC 4861 section 10.
index 823b6f40e07bedd78a25c89a128c328e0fae64f5..c9fef6c7719a7b64051811b79abf6df3f231ed4e 100644 (file)
@@ -292,16 +292,6 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
         return 0;
 }
 
-static usec_t radv_compute_timeout(usec_t min, usec_t max) {
-        assert_return(min <= max, RADV_DEFAULT_MIN_TIMEOUT_USEC);
-
-        /* RFC 4861: min must be no less than 3s, max must be no less than 4s */
-        min = MAX(min, 3*USEC_PER_SEC);
-        max = MAX(max, 4*USEC_PER_SEC);
-
-        return min + (random_u32() % (max - min));
-}
-
 static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         usec_t min_timeout, max_timeout, time_now, timeout;
         sd_radv *ra = userdata;
@@ -310,6 +300,7 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         assert(s);
         assert(ra);
         assert(ra->event);
+        assert(router_lifetime_is_valid(ra->lifetime_usec));
 
         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
@@ -320,27 +311,35 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
                 log_radv_errno(ra, r, "Unable to send Router Advertisement: %m");
 
         /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
-        if (ra->ra_sent < RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
+        if (ra->ra_sent < RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
                 max_timeout = RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
-                min_timeout = RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
-        } else {
+        else
                 max_timeout = RADV_DEFAULT_MAX_TIMEOUT_USEC;
-                min_timeout = RADV_DEFAULT_MIN_TIMEOUT_USEC;
-        }
 
         /* RFC 4861, Section 6.2.1, lifetime must be at least MaxRtrAdvInterval,
-           so lower the interval here */
-        if (ra->lifetime_usec > 0 && ra->lifetime_usec < max_timeout) {
-                max_timeout = ra->lifetime_usec;
+         * so lower the interval here */
+        if (ra->lifetime_usec > 0)
+                max_timeout = MIN(max_timeout, ra->lifetime_usec);
+
+        if (max_timeout >= 9 * USEC_PER_SEC)
                 min_timeout = max_timeout / 3;
-        }
+        else
+                min_timeout = max_timeout * 3 / 4;
+
+        /* RFC 4861, Section 6.2.1.
+         * MaxRtrAdvInterval MUST be no less than 4 seconds and no greater than 1800 seconds.
+         * MinRtrAdvInterval MUST be no less than 3 seconds and no greater than .75 * MaxRtrAdvInterval. */
+        assert(max_timeout >= RADV_MIN_MAX_TIMEOUT_USEC);
+        assert(max_timeout <= RADV_MAX_MAX_TIMEOUT_USEC);
+        assert(min_timeout >= RADV_MIN_MIN_TIMEOUT_USEC);
+        assert(min_timeout <= max_timeout * 3 / 4);
 
-        timeout = radv_compute_timeout(min_timeout, max_timeout);
+        timeout = min_timeout + random_u64_range(max_timeout - min_timeout);
         log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
 
         r = event_reset_time(ra->event, &ra->timeout_event_source,
                              clock_boottime_or_monotonic(),
-                             time_now + timeout, MSEC_PER_SEC,
+                             usec_add(time_now, timeout), MSEC_PER_SEC,
                              radv_timeout, ra,
                              ra->event_priority, "radv-timeout", true);
         if (r < 0)