Fixed
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
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.