Commit fb811395 authored by Rick Jones's avatar Rick Jones Committed by David S. Miller

net: add explicit logging and stat for neighbour table overflow

Add an explicit neighbour table overflow message (ratelimited) and
statistic to make diagnosing neighbour table overflows tractable in
the wild.

Diagnosing a neighbour table overflow can be quite difficult in the wild
because there is no explicit dmesg logged.  Callers to neighbour code
seem to use net_dbg_ratelimit when the neighbour call fails which means
the "base message" is not emitted and the callback suppressed messages
from the ratelimiting can end-up juxtaposed with unrelated messages.
Further, a forced garbage collection will increment a stat on each call
whether it was successful in freeing-up a table entry or not, so that
statistic is only a hint.  So, add a net_info_ratelimited message and
explicit statistic to the neighbour code.
Signed-off-by: default avatarRick Jones <rick.jones2@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a7854037
...@@ -125,6 +125,7 @@ struct neigh_statistics { ...@@ -125,6 +125,7 @@ struct neigh_statistics {
unsigned long forced_gc_runs; /* number of forced GC runs */ unsigned long forced_gc_runs; /* number of forced GC runs */
unsigned long unres_discards; /* number of unresolved drops */ unsigned long unres_discards; /* number of unresolved drops */
unsigned long table_fulls; /* times even gc couldn't help */
}; };
#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field) #define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field)
......
...@@ -106,6 +106,7 @@ struct ndt_stats { ...@@ -106,6 +106,7 @@ struct ndt_stats {
__u64 ndts_rcv_probes_ucast; __u64 ndts_rcv_probes_ucast;
__u64 ndts_periodic_gc_runs; __u64 ndts_periodic_gc_runs;
__u64 ndts_forced_gc_runs; __u64 ndts_forced_gc_runs;
__u64 ndts_table_fulls;
}; };
enum { enum {
......
...@@ -274,8 +274,12 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device ...@@ -274,8 +274,12 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device
(entries >= tbl->gc_thresh2 && (entries >= tbl->gc_thresh2 &&
time_after(now, tbl->last_flush + 5 * HZ))) { time_after(now, tbl->last_flush + 5 * HZ))) {
if (!neigh_forced_gc(tbl) && if (!neigh_forced_gc(tbl) &&
entries >= tbl->gc_thresh3) entries >= tbl->gc_thresh3) {
net_info_ratelimited("%s: neighbor table overflow!\n",
tbl->id);
NEIGH_CACHE_STAT_INC(tbl, table_fulls);
goto out_entries; goto out_entries;
}
} }
n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC); n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
...@@ -1849,6 +1853,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, ...@@ -1849,6 +1853,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast; ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
ndst.ndts_periodic_gc_runs += st->periodic_gc_runs; ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
ndst.ndts_forced_gc_runs += st->forced_gc_runs; ndst.ndts_forced_gc_runs += st->forced_gc_runs;
ndst.ndts_table_fulls += st->table_fulls;
} }
if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst)) if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
...@@ -2717,12 +2722,12 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) ...@@ -2717,12 +2722,12 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
struct neigh_statistics *st = v; struct neigh_statistics *st = v;
if (v == SEQ_START_TOKEN) { if (v == SEQ_START_TOKEN) {
seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards\n"); seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls\n");
return 0; return 0;
} }
seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
"%08lx %08lx %08lx %08lx %08lx\n", "%08lx %08lx %08lx %08lx %08lx %08lx\n",
atomic_read(&tbl->entries), atomic_read(&tbl->entries),
st->allocs, st->allocs,
...@@ -2739,7 +2744,8 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) ...@@ -2739,7 +2744,8 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
st->periodic_gc_runs, st->periodic_gc_runs,
st->forced_gc_runs, st->forced_gc_runs,
st->unres_discards st->unres_discards,
st->table_fulls
); );
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment