dhcpv4: delay forced renew transaction start
authorHans Dedecker <dedeckeh@gmail.com>
Thu, 21 Jun 2018 08:25:53 +0000 (10:25 +0200)
committerHans Dedecker <dedeckeh@gmail.com>
Fri, 22 Jun 2018 13:10:38 +0000 (15:10 +0200)
Delay the start of the forced renew transaction start with a random delay
between 500 and 1000 ms. This avoids sending DHCP forced renew messages
in case the DHCP client starts sending discover messages triggered by
link state flap.
Also it distributes sending of DHCP forced renew messages to different clients
over an interval instead of sending DHCP forced renew messages in a burst mode.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
src/dhcpv4.c

index 8c9e9bafe9e88dc716efc4b30bd6ed4461816ca9..dc10ba3dd65560e1c136808c899ad434a2a23e6c 100644 (file)
@@ -43,6 +43,7 @@ static void valid_until_cb(struct uloop_timeout *event);
 static void handle_addrlist_change(struct interface *iface);
 static void free_dhcpv4_assignment(struct dhcpv4_assignment *a);
 static void dhcpv4_fr_start(struct dhcpv4_assignment *a);
+static void dhcpv4_fr_rand_delay(struct dhcpv4_assignment *a);
 static void dhcpv4_fr_stop(struct dhcpv4_assignment *a);
 static void handle_dhcpv4(void *addr, void *data, size_t len,
                struct interface *iface, void *dest_addr);
@@ -461,7 +462,7 @@ static void handle_addrlist_change(struct interface *iface)
        list_for_each_entry(c, &iface->dhcpv4_assignments, head) {
                if ((c->flags & OAF_BOUND) && c->fr_ip && !c->fr_cnt) {
                        if (c->accept_fr_nonce || iface->dhcpv4_forcereconf)
-                               dhcpv4_fr_start(c);
+                               dhcpv4_fr_rand_delay(c);
                        else
                                dhcpv4_fr_stop(c);
                }
@@ -630,6 +631,28 @@ static void dhcpv4_fr_start(struct dhcpv4_assignment *a)
        dhcpv4_fr_send(a);
 }
 
+static void dhcpv4_fr_delay_timer(struct uloop_timeout *event)
+{
+       struct dhcpv4_assignment *a = container_of(event, struct dhcpv4_assignment, fr_timer);
+       struct interface *iface = a->iface;
+
+       (iface->dhcpv4_event.uloop.fd == -1 ? dhcpv4_fr_rand_delay(a) : dhcpv4_fr_start(a));
+}
+
+static void dhcpv4_fr_rand_delay(struct dhcpv4_assignment *a)
+{
+#define MIN_DELAY   500
+#define MAX_FUZZ    500
+       int msecs;
+
+       odhcpd_urandom(&msecs, sizeof(msecs));
+
+       msecs = labs(msecs)%MAX_FUZZ + MIN_DELAY;
+
+       uloop_timeout_set(&a->fr_timer, msecs);
+       a->fr_timer.cb = dhcpv4_fr_delay_timer;
+}
+
 static void dhcpv4_fr_stop(struct dhcpv4_assignment *a)
 {
        uloop_timeout_cancel(&a->fr_timer);