Based on my testing here is what I have come up with.... dst_ops.entries
is not being set appropriately (or at least not what I would expect it
to be). I determined this by changing dst_ops->gc to point to a new
function (rt_display_tot) for debugging, as well as had rt_intern_hash()
call this function instead of rt_garbage_collect().
The sole purpose of this function was to loop through all hash chains and
count up the entries that should be valid, do a printk("%d %d", count,
dst_ops.entries), then return(rt_garbage_collect()). The result was, that
when rt_garbage_collect() returned 1 (dst cache overflow), the number of
entries reported by dst_ops.entries was far different than the number
reported by my loop/counter.
Upon further investigation in to rt_free(), __dst_free(), and dst_destroy(),
I found that only dst_destroy() decrements dst_ops.entries.
Furthermore, when dst_ops->gc returns 1, dst_alloc() will not create an
entry, appropriately so, the box is at a stand still.
So... For the interim, I have create a small patch that purges the dst cache
table, and resets dst_ops.entries to 0 anytime rt_garbage_collect() returns 1.
The result... The box stays up, and hums along quite happily.
I would appreciate any comments with regards to this matter. I have also
included a copy of the patch that I created to work around the issue.
Thanks,
Chad
diff -urNp linux-2.2.16cwm/net/ipv4/route.c linux-2.2.16cwm/net/ipv4/route.c
-n- linux-2.2.16/net/ipv4/route.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.16cwm/net/ipv4/route.c Tue Apr 9 15:14:12 2002
@@ -96,7 +96,7 @@
#define IP_MAX_MTU 0xFFF0
-#define RT_GC_TIMEOUT (300*HZ)
+#define RT_GC_TIMEOUT (120*HZ)
int ip_rt_min_delay = 2*HZ;
int ip_rt_max_delay = 10*HZ;
@@ -134,7 +134,8 @@ static struct dst_entry * ipv4_dst_rerou
static struct dst_entry * ipv4_negative_advice(struct dst_entry *);
static void ipv4_link_failure(struct sk_buff *skb);
static int rt_garbage_collect(void);
-
+static int rt_delete_now(void);
+static int rt_garbage_ctl(void);
struct dst_ops ipv4_dst_ops =
{
@@ -142,7 +143,7 @@ struct dst_ops ipv4_dst_ops =
__constant_htons(ETH_P_IP),
RT_HASH_DIVISOR,
- rt_garbage_collect,
+ rt_garbage_ctl,
ipv4_dst_check,
ipv4_dst_reroute,
NULL,
@@ -508,8 +509,7 @@ static int rt_garbage_collect(void)
if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
return 0;
- if (net_ratelimit())
- printk("dst cache overflow\n");
+
return 1;
work_done:
@@ -570,7 +570,7 @@ restart:
int saved_int = ip_rt_gc_min_interval;
ip_rt_gc_elasticity = 1;
ip_rt_gc_min_interval = 0;
- rt_garbage_collect();
+ rt_garbage_ctl();
ip_rt_gc_min_interval = saved_int;
ip_rt_gc_elasticity = saved_elasticity;
goto restart;
@@ -2045,4 +2045,44 @@ __initfunc(void ip_rt_init(void))
ent->read_proc = ip_rt_acct_read;
#endif
#endif
+}
+
+static int rt_delete_now(void){
+ struct rtable *rth, **rthp;
+ int i,ent1,ent2,c;
+
+ i=0;
+ ent1=0;
+ ent2=0;
+ c=0;
+
+ ent1=atomic_read(&ipv4_dst_ops.entries);
+ start_bh_atomic();
+ while(i<RT_HASH_DIVISOR){
+ rthp=&rt_hash_table[i];
+ while((rth=*rthp)!=NULL){
+ *rthp=rth->u.rt_next;
+ rth->u.rt_next=NULL;
+ c+=1;
+ rt_free(rth);
+ }
+ i++;
+ }
+
+ atomic_set(&ipv4_dst_ops.entries,0);
+ end_bh_atomic();
+ ent2=atomic_read(&ipv4_dst_ops.entries);
+
+ if(net_ratelimit()){
+ printk("dst cache overflow\n");
+ printk("rt_delete_now(); s:%d e:%d t:%d\n",ent1,ent2,c);
+ }
+
+ return 0;
+}
+
+static int rt_garbage_ctl(void){
+ if(rt_garbage_collect())
+ rt_delete_now();
+ return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/