Wind River Support Network

HomeDefectsLIN6-8681
Fixed

LIN6-8681 : Changing IPv4 base_reachable_time results in reachable_time not effective immediately. In IPv6 it is immediate.

Created: Oct 31, 2014    Updated: Dec 3, 2018
Resolved Date: Jun 3, 2015
Found In Version: 6.0.0.20
Severity: Standard
Applicable for: Wind River Linux 6
Component/s: Networking

Description

  
 root@du1:~# date;
 cat /proc/sys/net/ipv6/neigh/eth20.3277/base_reachable_time
 Wed Aug 20 11:55:45 UTC 2014
 30
  
 root@du1:~# ip -4 ntable show dev eth20.3277
 inet arp_cache
     dev eth20.3277
     refcnt 1 reachable 40880 base_reachable 30000 retrans
 1000
     gc_stale 7683000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 1000
  
 We can see that base_reachable_time value is 30 sec. as
 specified in the config file and that reachable_time has a
 random value in the range [0.5*base_reachable_time,
 1.5*base_reachable_time].
  
 The problem that we see (the reason for the TR) is that
 reachable_time doesn’t get updated when base_reachable_time
 is changed:
  
 root@du1:~# echo 500
 >  /proc/sys/net/ipv4/neigh/eth20.3277/base_reachable_time
  
 root@du1:~# date;
 cat /proc/sys/net/ipv4/neigh/eth20.3277/base_reachable_time
 Wed Aug 20 11:51:16 UTC 2014
 500
  
 root@du1:~# date; ip -4 ntable show dev eth20.3277
 Wed Aug 20 11:51:39 UTC 2014
 inet arp_cache
     dev eth20.3277
     refcnt 1 reachable 40880 base_reachable 500000 retrans
 1000
     gc_stale 7683000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 1000
  
 root@du1:~# date; ip -4 ntable show dev eth20.3277
 Wed Aug 20 11:52:01 UTC 2014
 inet arp_cache
     dev eth20.3277
     refcnt 1 reachable 40880 base_reachable 500000 retrans
 1000
     gc_stale 7683000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 1000
  
 root@du1:~# date; ip -4 ntable show dev eth20.3277
 Wed Aug 20 11:53:01 UTC 2014
 inet arp_cache
     dev eth20.3277
     refcnt 1 reachable 40880 base_reachable 500000 retrans
 1000
     gc_stale 7683000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 1000
  
 root@du1:~# date; ip -4 ntable show dev eth20.3277
 Wed Aug 20 11:54:05 UTC 2014
 inet arp_cache
     dev eth20.3277
     refcnt 1 reachable 313210 base_reachable 500000 retrans
 1000
     gc_stale 7683000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 1000
  
 above we have changed base_reachable_time to 500 sec. but
 reachable_time was only updated after more than 2 minutes.
  
 For IPv6, however, the behavior is as expected.
  
 root@du1:~# date;
 cat /proc/sys/net/ipv6/neigh/eth20.3277/base_reachable_time
 Wed Aug 20 12:14:32 UTC 2014
 30
  
 root@du1:~# date; ip -6 ntable show dev eth20.3277
 Wed Aug 20 12:14:34 UTC 2014
 inet6 ndisc_cache
     dev eth20.3277
     refcnt 3 reachable 23770 base_reachable 30000 retrans
 1000
     gc_stale 60000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 0
  
 root@du1:~# echo 421
 >  /proc/sys/net/ipv6/neigh/eth20.3277/base_reachable_time
  
 root@du1:~# date;
 cat /proc/sys/net/ipv6/neigh/eth20.3277/base_reachable_time
 Wed Aug 20 12:14:54 UTC 2014
 421
  
 root@du1:~# date; ip -6 ntable show dev eth20.3277
 Wed Aug 20 12:14:56 UTC 2014
 inet6 ndisc_cache
     dev eth20.3277
     refcnt 3 reachable 504360 base_reachable 421000 retrans
 1000
     gc_stale 60000 delay_probe 5000 queue 34
     app_probes 0 ucast_probes 3 mcast_probes 3
     anycast_delay 1000 proxy_delay 800 proxy_queue 64
 locktime 0
  
 ---
  
 Looking at the linux code we see the following:
  
       * Reachable_time value, for all interfaces, is
         recalculated every 5 min:
  
 http://lxr.free-electrons.com/source/net/core/neighbour.c?v=3.10:
  
 110 /*
 111 * It is random distribution in the interval
 (1/2)*base...(3/2)*base.
 112 * It corresponds to default IPv6 settings and is not
 overridable,
 113 * because it is really reasonable choice.
 114 */
 115 
 116 unsigned long neigh_rand_reach_time(unsigned long base)
 117 {
 118         return base ? (net_random() % base) + (base >>
 1) : 0;
 119 }
 …
 751 static void neigh_periodic_work(struct work_struct
 *work)
 752 {
 …
 768         /*
 769          *      periodically recompute ReachableTime
 from random function
 770          */
 771 
 772         if (time_after(jiffies, tbl->last_rand + 300 *
 HZ)) {
 773                 struct neigh_parms *p;
 774                 tbl->last_rand = jiffies;
 775                 for (p = &tbl->parms; p; p = p->next)
 776                         p->reachable_time =
 777
 neigh_rand_reach_time(p->base_reachable_time);
 778         }
 779
 …
 830 }
  
  
       * IPv6 listens to change events and recomputes the
         reachable_time value. Function
         ‘ndisc_ifinfo_sysctl_change’ is registered as a
         handle when such events appear:
  
 http://lxr.free-electrons.com/source/net/ipv6/ndisc.c?v=3.10:
 1620 int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl,
 int write, void __user *buffer, size_t *lenp, loff_t *ppos)
 1621 {
 1622         struct net_device *dev = ctl->extra1;
 1623         struct inet6_dev *idev;
 1624         int ret;
 1625 
 1626         if ((strcmp(ctl->procname, "retrans_time") ==
 0) ||
 1627             (strcmp(ctl->procname,
 "base_reachable_time") == 0))
 1628                 ndisc_warn_deprecated_sysctl(ctl,
 "syscall", dev ? dev->name : "default");
 1629 
 1630         if (strcmp(ctl->procname, "retrans_time") == 0)
 1631                 ret = proc_dointvec(ctl, write, buffer,
 lenp, ppos);
 1632 
 1633         else if (strcmp(ctl->procname,
 "base_reachable_time") == 0)
 1634                 ret = proc_dointvec_jiffies(ctl, write,
 1635                                             buffer,
 lenp, ppos);
 1636 
 1637         else if ((strcmp(ctl->procname,
 "retrans_time_ms") == 0) ||
 1638                  (strcmp(ctl->procname,
 "base_reachable_time_ms") == 0))
 1639                 ret = proc_dointvec_ms_jiffies(ctl,
 write,
 1640                                                buffer,
 lenp, ppos);
 1641         else
 1642                 ret = -1;
 1643 
 1644         if (write && ret == 0 && dev && (idev =
 in6_dev_get(dev)) != NULL) {
 1645                 if (ctl->data ==
 &idev->nd_parms->base_reachable_time)
 1646                         idev->nd_parms->reachable_time
 =
 neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
 1647                 idev->tstamp = jiffies;
 1648                 inet6_ifinfo_notify(RTM_NEWLINK, idev);
 1649                 in6_dev_put(idev);
 1650         }
 1651         return ret;
 1652 }
 ...
 1692 int __init ndisc_init(void)
 1693 {
 ...
 1704 #ifdef CONFIG_SYSCTL
 1705         err = neigh_sysctl_register(NULL,
 &nd_tbl.parms, "ipv6",
 1706
 &ndisc_ifinfo_sysctl_change);
 1707         if (err)
 1708                 goto out_unregister_pernet;
 1709 #endif
 ...
 1723 }
  
       * In IPv4, however, we do not have such functionality
         implemented:
  
 http://lxr.free-electrons.com/source/net/ipv4/arp.c?v=3.10:
 1276 void __init arp_init(void)
 1277 {
 1278         neigh_table_init(&arp_tbl);
 1279 
 1280         dev_add_pack(&arp_packet_type);
 1281         arp_proc_init();
 1282 #ifdef CONFIG_SYSCTL
 1283         neigh_sysctl_register(NULL, &arp_tbl.parms,
 "ipv4", NULL);
 1284 #endif
 1285
 register_netdevice_notifier(&arp_netdev_notifier);
 1286 }
  
 This explains the behavior that we see, that for IPv4 it
 takes up to 5 min for reachable to be updated, after
 base_reachable_time has been changed.

Other Downloads


Live chat
Online