Eric Dumazet a écrit :
Denys Fedoryshchenko a écrit :
Already patched and tested, it doesn't change anything.
We still leak dsts somewhere.
You could try git bisect, or try to patch net/core/dst.c so that
dst_gc_task() (line 83) displays
route informations for say 10 first entries found in the dst_busy_list
(refcnt, interface, source IP, dest IP, things like that) that could
ring a bell given your netfilter rules or network conf.
I cooked a patch (untested) to implement this idea :
It should display lines similar to /proc/net/rt_cache (reusing the same
helper function)
Signed-off-by: Eric Dumazet <dada1@xxxxxxxxxxxxx>
include/net/dst.h | 2 +
net/core/dst.c | 7 ++++++
net/ipv4/route.c | 47 ++++++++++++++++++++++++++------------------
3 files changed, 37 insertions(+), 19 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 002500e..2fe9a6c 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -103,6 +103,8 @@ struct dst_ops
void (*link_failure)(struct sk_buff *);
void (*update_pmtu)(struct dst_entry *dst, u32 mtu);
int (*local_out)(struct sk_buff *skb);
+ size_t (*info_show)(struct dst_entry *, char *buff,
+ size_t len);
int entry_size;
atomic_t entries;
diff --git a/net/core/dst.c b/net/core/dst.c
index fe03266..08395e8 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -70,6 +70,7 @@ static void dst_gc_task(struct work_struct *work)
#if RT_CACHE_DEBUG >= 2
ktime_t time_start = ktime_get();
struct timespec elapsed;
+ char info[128];
#endif
mutex_lock(&dst_gc_mutex);
@@ -82,6 +83,12 @@ loop:
if (likely(atomic_read(&dst->__refcnt))) {
last->next = dst;
last = dst;
+#if RT_CACHE_DEBUG >= 2
+ if (delayed < 10 && dst->ops->info_show) {
+ dst->ops->info_show(dst, info, sizeof(info));
+ printk(KERN_DEBUG "dstgc [%d] %s\n", delayed, info);
+ }
+#endif
delayed++;
continue;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 230716c..ef8c3b7 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -148,6 +148,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
static void ipv4_link_failure(struct sk_buff *skb);
static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static int rt_garbage_collect(struct dst_ops *ops);
+static size_t rt_info_show(struct dst_entry *dst,
+ char *buff, size_t maxlen);
static struct dst_ops ipv4_dst_ops = {
@@ -161,6 +163,7 @@ static struct dst_ops ipv4_dst_ops = {
.link_failure = ipv4_link_failure,
.update_pmtu = ip_rt_update_pmtu,
.local_out = ip_local_out,
+ .info_show = rt_info_show,
.entry_size = sizeof(struct rtable),
.entries = ATOMIC_INIT(0),
};
@@ -269,6 +272,28 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
rt_hash_code((__force u32)(__be32)(daddr),\
(__force u32)(__be32)(saddr) ^ ((idx) << 5))
+static size_t rt_info_show(struct dst_entry *dst, char *buff, size_t maxlen)
+{
+ struct rtable *r = (struct rtable *)dst;
+
+ return snprintf(buff, maxlen, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"
+ "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X",
+ r->u.dst.dev ? r->u.dst.dev->name : "*",
+ (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
+ r->rt_flags, atomic_read(&r->u.dst.__refcnt),
+ r->u.dst.__use, 0, (unsigned long)r->rt_src,
+ (dst_metric(&r->u.dst, RTAX_ADVMSS) ?
+ (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
+ dst_metric(&r->u.dst, RTAX_WINDOW),
+ (int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) +
+ dst_metric(&r->u.dst, RTAX_RTTVAR)),
+ r->fl.fl4_tos,
+ r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
+ r->u.dst.hh ? (r->u.dst.hh->hh_output ==
+ dev_queue_xmit) : 0,
+ r->rt_spec_dst);
+}
+
#ifdef CONFIG_PROC_FS
struct rt_cache_iter_state {
struct seq_net_private p;
@@ -368,25 +393,9 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v)
"Metric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\t"
"HHUptod\tSpecDst");
else {
- struct rtable *r = v;
- char temp[256];
-
- sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"
- "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X",
- r->u.dst.dev ? r->u.dst.dev->name : "*",
- (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
- r->rt_flags, atomic_read(&r->u.dst.__refcnt),
- r->u.dst.__use, 0, (unsigned long)r->rt_src,
- (dst_metric(&r->u.dst, RTAX_ADVMSS) ?
- (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
- dst_metric(&r->u.dst, RTAX_WINDOW),
- (int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) +
- dst_metric(&r->u.dst, RTAX_RTTVAR)),
- r->fl.fl4_tos,
- r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
- r->u.dst.hh ? (r->u.dst.hh->hh_output ==
- dev_queue_xmit) : 0,
- r->rt_spec_dst);
+ char temp[128];
+
+ rt_info_show(v, temp, 128);
seq_printf(seq, "%-127s\n", temp);
}
return 0;