ipv6: prepare fib6_age() for exception table
If all dst cache entries are stored in the exception table under the main route, we have to go through them during fib6_age() when doing garbage collecting. Introduce a new function rt6_age_exception() which goes through all dst entries in the exception table and remove those entries that are expired. This function is called in fib6_age() so that all dst caches are also garbage collected. Signed-off-by: Wei Wang <weiwan@google.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b16cb459d7
commit
c757faa8bf
@ -29,6 +29,14 @@
|
|||||||
#define FIB6_TABLE_HASHSZ 1
|
#define FIB6_TABLE_HASHSZ 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RT6_DEBUG 2
|
||||||
|
|
||||||
|
#if RT6_DEBUG >= 3
|
||||||
|
#define RT6_TRACE(x...) pr_debug(x)
|
||||||
|
#else
|
||||||
|
#define RT6_TRACE(x...) do { ; } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct rt6_info;
|
struct rt6_info;
|
||||||
|
|
||||||
struct fib6_config {
|
struct fib6_config {
|
||||||
@ -75,6 +83,11 @@ struct fib6_node {
|
|||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fib6_gc_args {
|
||||||
|
int timeout;
|
||||||
|
int more;
|
||||||
|
};
|
||||||
|
|
||||||
#ifndef CONFIG_IPV6_SUBTREES
|
#ifndef CONFIG_IPV6_SUBTREES
|
||||||
#define FIB6_SUBTREE(fn) NULL
|
#define FIB6_SUBTREE(fn) NULL
|
||||||
#else
|
#else
|
||||||
|
@ -97,6 +97,8 @@ int ip6_del_rt(struct rt6_info *);
|
|||||||
|
|
||||||
void rt6_flush_exceptions(struct rt6_info *rt);
|
void rt6_flush_exceptions(struct rt6_info *rt);
|
||||||
int rt6_remove_exception_rt(struct rt6_info *rt);
|
int rt6_remove_exception_rt(struct rt6_info *rt);
|
||||||
|
void rt6_age_exceptions(struct rt6_info *rt, struct fib6_gc_args *gc_args,
|
||||||
|
unsigned long now);
|
||||||
|
|
||||||
static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,
|
static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,
|
||||||
const struct in6_addr *daddr,
|
const struct in6_addr *daddr,
|
||||||
|
@ -38,14 +38,6 @@
|
|||||||
#include <net/ip6_fib.h>
|
#include <net/ip6_fib.h>
|
||||||
#include <net/ip6_route.h>
|
#include <net/ip6_route.h>
|
||||||
|
|
||||||
#define RT6_DEBUG 2
|
|
||||||
|
|
||||||
#if RT6_DEBUG >= 3
|
|
||||||
#define RT6_TRACE(x...) pr_debug(x)
|
|
||||||
#else
|
|
||||||
#define RT6_TRACE(x...) do { ; } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct kmem_cache *fib6_node_kmem __read_mostly;
|
static struct kmem_cache *fib6_node_kmem __read_mostly;
|
||||||
|
|
||||||
struct fib6_cleaner {
|
struct fib6_cleaner {
|
||||||
@ -1890,12 +1882,6 @@ static void fib6_flush_trees(struct net *net)
|
|||||||
* Garbage collection
|
* Garbage collection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct fib6_gc_args
|
|
||||||
{
|
|
||||||
int timeout;
|
|
||||||
int more;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int fib6_age(struct rt6_info *rt, void *arg)
|
static int fib6_age(struct rt6_info *rt, void *arg)
|
||||||
{
|
{
|
||||||
struct fib6_gc_args *gc_args = arg;
|
struct fib6_gc_args *gc_args = arg;
|
||||||
@ -1904,9 +1890,6 @@ static int fib6_age(struct rt6_info *rt, void *arg)
|
|||||||
/*
|
/*
|
||||||
* check addrconf expiration here.
|
* check addrconf expiration here.
|
||||||
* Routes are expired even if they are in use.
|
* Routes are expired even if they are in use.
|
||||||
*
|
|
||||||
* Also age clones. Note, that clones are aged out
|
|
||||||
* only if they are not in use now.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (rt->rt6i_flags & RTF_EXPIRES && rt->dst.expires) {
|
if (rt->rt6i_flags & RTF_EXPIRES && rt->dst.expires) {
|
||||||
@ -1915,6 +1898,9 @@ static int fib6_age(struct rt6_info *rt, void *arg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
gc_args->more++;
|
gc_args->more++;
|
||||||
|
/* The following part will soon be removed when the exception
|
||||||
|
* table is hooked up to store all cached routes.
|
||||||
|
*/
|
||||||
} else if (rt->rt6i_flags & RTF_CACHE) {
|
} else if (rt->rt6i_flags & RTF_CACHE) {
|
||||||
if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout))
|
if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout))
|
||||||
rt->dst.obsolete = DST_OBSOLETE_KILL;
|
rt->dst.obsolete = DST_OBSOLETE_KILL;
|
||||||
@ -1940,6 +1926,12 @@ static int fib6_age(struct rt6_info *rt, void *arg)
|
|||||||
gc_args->more++;
|
gc_args->more++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Also age clones in the exception table.
|
||||||
|
* Note, that clones are aged out
|
||||||
|
* only if they are not in use now.
|
||||||
|
*/
|
||||||
|
rt6_age_exceptions(rt, gc_args, now);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1528,6 +1528,66 @@ static void rt6_exceptions_clean_tohost(struct rt6_info *rt,
|
|||||||
spin_unlock_bh(&rt6_exception_lock);
|
spin_unlock_bh(&rt6_exception_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
|
||||||
|
struct rt6_exception *rt6_ex,
|
||||||
|
struct fib6_gc_args *gc_args,
|
||||||
|
unsigned long now)
|
||||||
|
{
|
||||||
|
struct rt6_info *rt = rt6_ex->rt6i;
|
||||||
|
|
||||||
|
if (atomic_read(&rt->dst.__refcnt) == 1 &&
|
||||||
|
time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
|
||||||
|
RT6_TRACE("aging clone %p\n", rt);
|
||||||
|
rt6_remove_exception(bucket, rt6_ex);
|
||||||
|
return;
|
||||||
|
} else if (rt->rt6i_flags & RTF_GATEWAY) {
|
||||||
|
struct neighbour *neigh;
|
||||||
|
__u8 neigh_flags = 0;
|
||||||
|
|
||||||
|
neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
|
||||||
|
if (neigh) {
|
||||||
|
neigh_flags = neigh->flags;
|
||||||
|
neigh_release(neigh);
|
||||||
|
}
|
||||||
|
if (!(neigh_flags & NTF_ROUTER)) {
|
||||||
|
RT6_TRACE("purging route %p via non-router but gateway\n",
|
||||||
|
rt);
|
||||||
|
rt6_remove_exception(bucket, rt6_ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gc_args->more++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rt6_age_exceptions(struct rt6_info *rt,
|
||||||
|
struct fib6_gc_args *gc_args,
|
||||||
|
unsigned long now)
|
||||||
|
{
|
||||||
|
struct rt6_exception_bucket *bucket;
|
||||||
|
struct rt6_exception *rt6_ex;
|
||||||
|
struct hlist_node *tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!rcu_access_pointer(rt->rt6i_exception_bucket))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_bh(&rt6_exception_lock);
|
||||||
|
bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
|
||||||
|
lockdep_is_held(&rt6_exception_lock));
|
||||||
|
|
||||||
|
if (bucket) {
|
||||||
|
for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
|
||||||
|
hlist_for_each_entry_safe(rt6_ex, tmp,
|
||||||
|
&bucket->chain, hlist) {
|
||||||
|
rt6_age_examine_exception(bucket, rt6_ex,
|
||||||
|
gc_args, now);
|
||||||
|
}
|
||||||
|
bucket++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&rt6_exception_lock);
|
||||||
|
}
|
||||||
|
|
||||||
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
|
||||||
int oif, struct flowi6 *fl6, int flags)
|
int oif, struct flowi6 *fl6, int flags)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user