Skip to content

Commit

Permalink
ipv6: prepare fib6_age() for exception table
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Martin KaFai Lau <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
tracywwnj authored and davem330 committed Oct 7, 2017
1 parent b16cb45 commit c757faa
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 17 deletions.
13 changes: 13 additions & 0 deletions include/net/ip6_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
#define FIB6_TABLE_HASHSZ 1
#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 fib6_config {
Expand Down Expand Up @@ -75,6 +83,11 @@ struct fib6_node {
struct rcu_head rcu;
};

struct fib6_gc_args {
int timeout;
int more;
};

#ifndef CONFIG_IPV6_SUBTREES
#define FIB6_SUBTREE(fn) NULL
#else
Expand Down
2 changes: 2 additions & 0 deletions include/net/ip6_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ int ip6_del_rt(struct rt6_info *);

void rt6_flush_exceptions(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,
const struct in6_addr *daddr,
Expand Down
26 changes: 9 additions & 17 deletions net/ipv6/ip6_fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@
#include <net/ip6_fib.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;

struct fib6_cleaner {
Expand Down Expand Up @@ -1890,12 +1882,6 @@ static void fib6_flush_trees(struct net *net)
* Garbage collection
*/

struct fib6_gc_args
{
int timeout;
int more;
};

static int fib6_age(struct rt6_info *rt, void *arg)
{
struct fib6_gc_args *gc_args = arg;
Expand All @@ -1904,9 +1890,6 @@ static int fib6_age(struct rt6_info *rt, void *arg)
/*
* check addrconf expiration here.
* 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) {
Expand All @@ -1915,6 +1898,9 @@ static int fib6_age(struct rt6_info *rt, void *arg)
return -1;
}
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) {
if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout))
rt->dst.obsolete = DST_OBSOLETE_KILL;
Expand All @@ -1940,6 +1926,12 @@ static int fib6_age(struct rt6_info *rt, void *arg)
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;
}

Expand Down
60 changes: 60 additions & 0 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,66 @@ static void rt6_exceptions_clean_tohost(struct rt6_info *rt,
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,
int oif, struct flowi6 *fl6, int flags)
{
Expand Down

0 comments on commit c757faa

Please sign in to comment.