diff options
author | David Ahern <dsahern@gmail.com> | 2018-04-18 03:33:24 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-18 06:41:17 +0300 |
commit | a64efe142f5e70b7e39276a414bbb3b96691c608 (patch) | |
tree | 749b0a3338f7878a20e7bc1f0e0dd5647499ee0f /net/ipv6 | |
parent | 23fb93a4d3f118a900790066d03368a296dce0d6 (diff) | |
download | linux-a64efe142f5e70b7e39276a414bbb3b96691c608.tar.xz |
net/ipv6: introduce fib6_info struct and helpers
Add fib6_info struct and alloc, destroy, hold and release helpers.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ip6_fib.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 53df4a98a7f7..d07578d84db0 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -145,6 +145,66 @@ static __be32 addr_bit_set(const void *token, int fn_bit) addr[fn_bit >> 5]; } +struct rt6_info *fib6_info_alloc(gfp_t gfp_flags) +{ + struct rt6_info *f6i; + + f6i = kzalloc(sizeof(*f6i), gfp_flags); + if (!f6i) + return NULL; + + f6i->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, gfp_flags); + if (!f6i->rt6i_pcpu) { + kfree(f6i); + return NULL; + } + + INIT_LIST_HEAD(&f6i->rt6i_siblings); + f6i->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; + + atomic_inc(&f6i->rt6i_ref); + + return f6i; +} + +void fib6_info_destroy(struct rt6_info *f6i) +{ + struct rt6_exception_bucket *bucket; + + WARN_ON(f6i->rt6i_node); + + bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket, 1); + if (bucket) { + f6i->rt6i_exception_bucket = NULL; + kfree(bucket); + } + + if (f6i->rt6i_pcpu) { + int cpu; + + for_each_possible_cpu(cpu) { + struct rt6_info **ppcpu_rt; + struct rt6_info *pcpu_rt; + + ppcpu_rt = per_cpu_ptr(f6i->rt6i_pcpu, cpu); + pcpu_rt = *ppcpu_rt; + if (pcpu_rt) { + dst_dev_put(&pcpu_rt->dst); + dst_release(&pcpu_rt->dst); + *ppcpu_rt = NULL; + } + } + } + + if (f6i->rt6i_idev) + in6_dev_put(f6i->rt6i_idev); + if (f6i->fib6_nh.nh_dev) + dev_put(f6i->fib6_nh.nh_dev); + + kfree(f6i); +} +EXPORT_SYMBOL_GPL(fib6_info_destroy); + static struct fib6_node *node_alloc(struct net *net) { struct fib6_node *fn; |