summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_fib.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /net/ipv6/ip6_fib.c
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r--net/ipv6/ip6_fib.c82
1 files changed, 72 insertions, 10 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 6c9f24492..15ce420ac 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.9 1997/09/20 20:48:27 davem Exp $
+ * $Id: ip6_fib.c,v 1.10 1997/12/13 21:53:10 kuznet Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -45,8 +45,6 @@ struct rt6_statistics rt6_stats;
static __u32 rt_sernum = 0;
-static void fib6_run_gc(unsigned long);
-
static struct timer_list ip6_fib_timer = {
NULL, NULL,
0,
@@ -182,6 +180,16 @@ static __inline__ void node_free(struct fib6_node * fn)
kfree(fn);
}
+extern __inline__ void rt6_release(struct rt6_info *rt)
+{
+ struct dst_entry *dst = (struct dst_entry *) rt;
+ if (atomic_dec_and_test(&dst->refcnt)) {
+ rt->rt6i_node = NULL;
+ dst_free(dst);
+ }
+}
+
+
/*
* Routing Table
*
@@ -409,8 +417,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
if ((iter->rt6i_dev == rt->rt6i_dev) &&
(iter->rt6i_flowr == rt->rt6i_flowr) &&
(ipv6_addr_cmp(&iter->rt6i_gateway,
- &rt->rt6i_gateway) == 0))
+ &rt->rt6i_gateway) == 0)) {
+ if (rt->rt6i_expires == 0 ||
+ (long)(rt->rt6i_expires - iter->rt6i_expires) > 0)
+ rt->rt6i_expires = iter->rt6i_expires;
return -EEXIST;
+ }
}
if (iter->rt6i_metric > rt->rt6i_metric)
@@ -426,6 +438,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
*ins = rt;
rt->u.next = iter;
atomic_inc(&rt->rt6i_ref);
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_NEWROUTE, rt);
+#endif
rt6_stats.fib_rt_entries++;
if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -440,7 +455,8 @@ static __inline__ void fib6_start_gc(struct rt6_info *rt)
{
if ((ip6_fib_timer.expires == 0) &&
(rt->rt6i_flags & (RTF_ADDRCONF | RTF_CACHE))) {
- ip6_fib_timer.expires = jiffies + ipv6_config.rt_gc_period;
+ del_timer(&ip6_fib_timer);
+ ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval;
add_timer(&ip6_fib_timer);
}
}
@@ -513,6 +529,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt)
if (err == 0)
fib6_start_gc(rt);
out:
+ if (err)
+ dst_free(&rt->u.dst);
return err;
}
@@ -782,7 +800,11 @@ static struct fib6_node * fib6_del_1(struct rt6_info *rt)
*/
*back = lf->u.next;
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_DELROUTE, lf);
+#endif
rt6_release(lf);
+ rt6_stats.fib_rt_entries--;
return fn;
}
back = &lf->u.next;
@@ -810,14 +832,19 @@ int fib6_del(struct rt6_info *rt)
/*
* Tree transversal function
*
+ * Wau... It is NOT REENTERABLE!!!!!!! It is cathastrophe. --ANK
*/
+int fib6_walk_count;
+
void fib6_walk_tree(struct fib6_node *root, f_pnode func, void *arg,
int filter)
{
struct fib6_node *fn;
fn = root;
+
+ fib6_walk_count++;
do {
if (!(fn->fn_flags & RTN_TAG)) {
@@ -858,6 +885,8 @@ void fib6_walk_tree(struct fib6_node *root, f_pnode func, void *arg,
} while (!(fn->fn_flags & RTN_TAG));
} while (!(fn->fn_flags & RTN_ROOT) || (fn->fn_flags & RTN_TAG));
+
+ fib6_walk_count--;
}
/*
@@ -874,7 +903,7 @@ static int fib6_gc_node(struct fib6_node *fn, int timeout)
for (rt = fn->leaf; rt;) {
if ((rt->rt6i_flags & RTF_CACHE) && atomic_read(&rt->rt6i_use) == 0) {
- if (now - rt->rt6i_tstamp > timeout) {
+ if ((long)(now - rt->rt6i_tstamp) >= timeout) {
struct rt6_info *old;
old = rt;
@@ -884,6 +913,10 @@ static int fib6_gc_node(struct fib6_node *fn, int timeout)
*back = rt;
old->rt6i_node = NULL;
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_DELROUTE, old);
+#endif
+ old->u.dst.obsolete = 1;
rt6_release(old);
rt6_stats.fib_rt_entries--;
continue;
@@ -893,7 +926,28 @@ static int fib6_gc_node(struct fib6_node *fn, int timeout)
/*
* check addrconf expiration here.
+ *
+ * BUGGGG Crossing fingers and ...
+ * Seems, radix tree walking is absolutely broken,
+ * but we will try in any case --ANK
*/
+ if (rt->rt6i_expires && (long)(now - rt->rt6i_expires) < 0) {
+ struct rt6_info *old;
+
+ old = rt;
+ rt = rt->u.next;
+
+ *back = rt;
+
+ old->rt6i_node = NULL;
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_DELROUTE, old);
+#endif
+ old->u.dst.obsolete = 1;
+ rt6_release(old);
+ rt6_stats.fib_rt_entries--;
+ continue;
+ }
back = &rt->u.next;
rt = rt->u.next;
}
@@ -987,17 +1041,25 @@ static void fib6_garbage_collect(struct fib6_node *fn, void *p_arg)
}
}
-static void fib6_run_gc(unsigned long dummy)
+void fib6_run_gc(unsigned long dummy)
{
struct fib6_gc_args arg = {
- ipv6_config.rt_cache_timeout,
+ ip6_rt_gc_timeout,
0
};
- fib6_walk_tree(&ip6_routing_table, fib6_garbage_collect, &arg, 0);
+ del_timer(&ip6_fib_timer);
+
+ if (dummy)
+ arg.timeout = dummy;
+
+ if (fib6_walk_count == 0)
+ fib6_walk_tree(&ip6_routing_table, fib6_garbage_collect, &arg, 0);
+ else
+ arg.more = 1;
if (arg.more) {
- ip6_fib_timer.expires = jiffies + ipv6_config.rt_gc_period;
+ ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval;
add_timer(&ip6_fib_timer);
} else {
ip6_fib_timer.expires = 0;