diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 518ebe6..4c805b3 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -2028,6 +2028,16 @@ Expression of retrans_time, which is deprecated, is in 1/100 seconds (for IPv4) or in jiffies (for IPv6). Expression of retrans_time_ms is in milliseconds. + +retrans_rand_backof_ms +---------------------- + +This is an extra delay (ms) for the retransmit timer. A random value between +0 and retrans_rand_backof_ms will be added to the retrans_timer. Default +is zero. Setting this to a larger value will help large broadcast domains +resolve ARP (for instance, 500 mac-vlans talking to 500 other mac-vlans). + + unres_qlen ---------- diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 8dbe468..a45b5df 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -608,6 +608,7 @@ enum { NET_NEIGH_GC_THRESH3=16, NET_NEIGH_RETRANS_TIME_MS=17, NET_NEIGH_REACHABLE_TIME_MS=18, + NET_NEIGH_RETRANS_RAND_BACKOFF=19, __NET_NEIGH_MAX }; diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 64a5f01..4947976 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -65,6 +65,7 @@ struct neigh_parms int proxy_delay; int proxy_qlen; int locktime; + int retrans_rand_backoff; }; struct neigh_statistics diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c index 37c8fab..6f3467c 100644 --- a/kernel/sysctl_check.c +++ b/kernel/sysctl_check.c @@ -249,6 +249,7 @@ static const struct trans_ctl_table trans_net_neigh_vars_table[] = { { NET_NEIGH_GC_THRESH3, "gc_thresh3" }, { NET_NEIGH_RETRANS_TIME_MS, "retrans_time_ms" }, { NET_NEIGH_REACHABLE_TIME_MS, "base_reachable_time_ms" }, + { NET_NEIGH_RETRANS_RAND_BACKOFF, "retrans_rand_backoff_ms"}, {} }; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 19b8e00..ec1f048 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -765,6 +765,13 @@ static __inline__ int neigh_max_probes(struct neighbour *n) p->ucast_probes + p->app_probes + p->mcast_probes); } +static unsigned long neigh_rand_retry(struct neighbour* neigh) { + if (neigh->parms->retrans_rand_backoff) { + return net_random() % neigh->parms->retrans_rand_backoff; + } + return 0; +} + /* Called when a timer expires for a neighbour entry. */ static void neigh_timer_handler(unsigned long arg) @@ -820,11 +827,11 @@ static void neigh_timer_handler(unsigned long arg) neigh->nud_state = NUD_PROBE; neigh->updated = jiffies; atomic_set(&neigh->probes, 0); - next = now + neigh->parms->retrans_time; + next = now + neigh->parms->retrans_time + neigh_rand_retry(neigh); } } else { /* NUD_PROBE|NUD_INCOMPLETE */ - next = now + neigh->parms->retrans_time; + next = now + neigh->parms->retrans_time + neigh_rand_retry(neigh); } if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && @@ -2642,6 +2649,14 @@ static struct neigh_sysctl_table { .strategy = &sysctl_ms_jiffies, }, { + .ctl_name = NET_NEIGH_RETRANS_RAND_BACKOFF, + .procname = "retrans_rand_backoff_ms", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_ms_jiffies, + .strategy = &sysctl_ms_jiffies, + }, + { .ctl_name = NET_NEIGH_GC_INTERVAL, .procname = "gc_interval", .maxlen = sizeof(int), @@ -2712,18 +2727,19 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, t->neigh_vars[11].data = &p->locktime; t->neigh_vars[12].data = &p->retrans_time; t->neigh_vars[13].data = &p->base_reachable_time; + t->neigh_vars[14].data = &p->retrans_rand_backoff; if (dev) { dev_name_source = dev->name; neigh_path[NEIGH_CTL_PATH_DEV].ctl_name = dev->ifindex; /* Terminate the table early */ - memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14])); + memset(&t->neigh_vars[15], 0, sizeof(t->neigh_vars[14])); } else { dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname; - t->neigh_vars[14].data = (int *)(p + 1); - t->neigh_vars[15].data = (int *)(p + 1) + 1; - t->neigh_vars[16].data = (int *)(p + 1) + 2; - t->neigh_vars[17].data = (int *)(p + 1) + 3; + t->neigh_vars[15].data = (int *)(p + 1); + t->neigh_vars[16].data = (int *)(p + 1) + 1; + t->neigh_vars[17].data = (int *)(p + 1) + 2; + t->neigh_vars[18].data = (int *)(p + 1) + 3; }