[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180225194730.30063-18-dsahern@gmail.com>
Date: Sun, 25 Feb 2018 11:47:27 -0800
From: David Ahern <dsahern@...il.com>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net, idosch@...sch.org, roopa@...ulusnetworks.com,
eric.dumazet@...il.com, weiwan@...gle.com, kafai@...com,
yoshfuji@...ux-ipv6.org, David Ahern <dsahern@...il.com>
Subject: [PATCH RFC net-next 17/20] 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@...il.com>
---
include/net/ip6_fib.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
net/ipv6/ip6_fib.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index d867b1696927..70978deac538 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -38,6 +38,7 @@
#endif
struct rt6_info;
+struct fib6_info;
struct fib6_config {
u32 fc_table;
@@ -132,6 +133,48 @@ struct fib6_nh {
int nh_weight;
};
+struct fib6_info {
+ struct fib6_table *rt6i_table;
+ struct fib6_info __rcu *rt6_next;
+ struct fib6_node __rcu *rt6i_node;
+
+ /* Multipath routes:
+ * siblings is a list of fib6_info that have the the same metric/weight,
+ * destination, but not the same gateway. nsiblings is just a cache
+ * to speed up lookup.
+ */
+ struct list_head rt6i_siblings;
+ unsigned int rt6i_nsiblings;
+
+ atomic_t rt6i_ref;
+ struct inet6_dev *rt6i_idev;
+ unsigned long expires;
+ struct dst_metrics *fib6_metrics;
+#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]
+#define fib6_hoplimit fib6_metrics->metrics[RTAX_HOPLIMIT-1]
+#define fib6_metric_lock fib6_metrics->metrics[RTAX_LOCK - 1]
+
+ struct rt6key rt6i_dst;
+ u32 rt6i_flags;
+ struct rt6key rt6i_src;
+ struct rt6key rt6i_prefsrc;
+
+ struct rt6_info * __percpu *rt6i_pcpu;
+ struct rt6_exception_bucket __rcu *rt6i_exception_bucket;
+
+ u32 rt6i_metric;
+ u8 rt6i_protocol;
+ u8 fib6_type;
+ u8 exception_bucket_flushed:1,
+ should_flush:1,
+ dst_nocount:1,
+ dst_nopolicy:1,
+ dst_host:1,
+ unused:3;
+
+ struct fib6_nh fib6_nh;
+};
+
struct rt6_info {
struct dst_entry dst;
struct rt6_info __rcu *rt6_next;
@@ -290,6 +333,20 @@ static inline void ip6_rt_put(struct rt6_info *rt)
void rt6_free_pcpu(struct rt6_info *non_pcpu_rt);
+struct rt6_info *fib6_info_alloc(gfp_t gfp_flags);
+void fib6_info_destroy(struct rt6_info *f6i);
+
+static inline void fib6_info_hold(struct rt6_info *f6i)
+{
+ atomic_inc(&f6i->rt6i_ref);
+}
+
+static inline void fib6_info_release(struct rt6_info *f6i)
+{
+ if (f6i && atomic_dec_and_test(&f6i->rt6i_ref))
+ fib6_info_destroy(f6i);
+}
+
static inline void rt6_hold(struct rt6_info *rt)
{
atomic_inc(&rt->rt6i_ref);
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 63a91db61749..6553550bd09b 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;
--
2.11.0
Powered by blists - more mailing lists