neigh: support smaller retrans_time settting
authorHangbin Liu <liuhangbin@gmail.com>
Wed, 1 Apr 2020 06:46:20 +0000 (14:46 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 3 Apr 2020 00:55:26 +0000 (17:55 -0700)
Currently, we limited the retrans_time to be greater than HZ/2. i.e.
setting retrans_time less than 500ms will not work. This makes the user
unable to achieve a more accurate control for bonding arp fast failover.

Update the sanity check to HZ/100, which is 10ms, to let users have more
ability on the retrans_time control.

v3: sync the behavior with IPv6 and update all the timer handler
v2: use HZ instead of hard code number

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/neighbour.c
net/ipv6/addrconf.c
net/ipv6/ndisc.c

index 5bf8d22..39d37d0 100644 (file)
@@ -1065,11 +1065,12 @@ static void neigh_timer_handler(struct timer_list *t)
                        neigh->updated = jiffies;
                        atomic_set(&neigh->probes, 0);
                        notify = 1;
-                       next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
+                       next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
+                                        HZ/100);
                }
        } else {
                /* NUD_PROBE|NUD_INCOMPLETE */
-               next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
+               next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
        }
 
        if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
@@ -1125,7 +1126,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        neigh->nud_state     = NUD_INCOMPLETE;
                        neigh->updated = now;
                        next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
-                                        HZ/2);
+                                        HZ/100);
                        neigh_add_timer(neigh, next);
                        immediate_probe = true;
                } else {
@@ -1427,7 +1428,8 @@ void __neigh_set_probe_once(struct neighbour *neigh)
        neigh->nud_state = NUD_INCOMPLETE;
        atomic_set(&neigh->probes, neigh_max_probes(neigh));
        neigh_add_timer(neigh,
-                       jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
+                       jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
+                                     HZ/100));
 }
 EXPORT_SYMBOL(__neigh_set_probe_once);
 
index 84a28b5..24e319d 100644 (file)
@@ -1357,7 +1357,7 @@ retry:
 
        regen_advance = idev->cnf.regen_max_retry *
                        idev->cnf.dad_transmits *
-                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
+                       max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
 
        /* recalculate max_desync_factor each time and update
         * idev->desync_factor if it's larger
@@ -4121,7 +4121,8 @@ static void addrconf_dad_work(struct work_struct *w)
 
        ifp->dad_probes--;
        addrconf_mod_dad_work(ifp,
-                             NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
+                             max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME),
+                                 HZ/100));
        spin_unlock(&ifp->lock);
        write_unlock_bh(&idev->lock);
 
@@ -4527,7 +4528,7 @@ restart:
                                   !(ifp->flags&IFA_F_TENTATIVE)) {
                                unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
                                        ifp->idev->cnf.dad_transmits *
-                                       NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ;
+                                       max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
 
                                if (age >= ifp->prefered_lft - regen_advance) {
                                        struct inet6_ifaddr *ifpub = ifp->ifpub;
index 6ffa153..1ecd4e9 100644 (file)
@@ -1359,8 +1359,8 @@ skip_defrtr:
 
                if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
                        rtime = (rtime*HZ)/1000;
-                       if (rtime < HZ/10)
-                               rtime = HZ/10;
+                       if (rtime < HZ/100)
+                               rtime = HZ/100;
                        NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
                        in6_dev->tstamp = jiffies;
                        send_ifinfo_notify = true;