Subject: Re: kernel 2.6.25-rc7 highly unstable on high load

From: Eric Dumazet <[email-masked]>
Date: Fri, 28 Mar 2008 16:57:55 +0100

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 <[email-masked]>

 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;