Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81eb8447 authored by Wei Wang's avatar Wei Wang Committed by David S. Miller
Browse files

ipv6: take care of rt6_stats



Currently, most of the rt6_stats are not hooked up correctly. As the
last part of this patch series, hook up all existing rt6_stats and add
one new stat fib_rt_uncache to indicate the number of routes in the
uncached list.
For details of the stats, please refer to the comments added in
include/net/ip6_fib.h.

Note: fib_rt_alloc and fib_rt_uncache are not guaranteed to be modified
under a lock. So atomic_t is used for them.

Signed-off-by: default avatarWei Wang <weiwan@google.com>
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 66f5d6ce
Loading
Loading
Loading
Loading
+9 −6
Original line number Original line Diff line number Diff line
@@ -297,12 +297,15 @@ struct fib6_walker {
};
};


struct rt6_statistics {
struct rt6_statistics {
	__u32		fib_nodes;
	__u32		fib_nodes;		/* all fib6 nodes */
	__u32		fib_route_nodes;
	__u32		fib_route_nodes;	/* intermediate nodes */
	__u32		fib_rt_alloc;		/* permanent routes	*/
	__u32		fib_rt_entries;		/* rt entries in fib table */
	__u32		fib_rt_entries;		/* rt entries in table	*/
	__u32		fib_rt_cache;		/* cached rt entries in exception table */
	__u32		fib_rt_cache;		/* cache routes		*/
	__u32		fib_discarded_routes;	/* total number of routes delete */
	__u32		fib_discarded_routes;

	/* The following stats are not protected by any lock */
	atomic_t	fib_rt_alloc;		/* total number of routes alloced */
	atomic_t	fib_rt_uncache;		/* rt entries in uncached list */
};
};


#define RTN_TL_ROOT	0x0001
#define RTN_TL_ROOT	0x0001
+24 −18
Original line number Original line Diff line number Diff line
@@ -149,18 +149,21 @@ static __be32 addr_bit_set(const void *token, int fn_bit)
	       addr[fn_bit >> 5];
	       addr[fn_bit >> 5];
}
}


static struct fib6_node *node_alloc(void)
static struct fib6_node *node_alloc(struct net *net)
{
{
	struct fib6_node *fn;
	struct fib6_node *fn;


	fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC);
	fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC);
	if (fn)
		net->ipv6.rt6_stats->fib_nodes++;


	return fn;
	return fn;
}
}


static void node_free_immediate(struct fib6_node *fn)
static void node_free_immediate(struct net *net, struct fib6_node *fn)
{
{
	kmem_cache_free(fib6_node_kmem, fn);
	kmem_cache_free(fib6_node_kmem, fn);
	net->ipv6.rt6_stats->fib_nodes--;
}
}


static void node_free_rcu(struct rcu_head *head)
static void node_free_rcu(struct rcu_head *head)
@@ -170,9 +173,10 @@ static void node_free_rcu(struct rcu_head *head)
	kmem_cache_free(fib6_node_kmem, fn);
	kmem_cache_free(fib6_node_kmem, fn);
}
}


static void node_free(struct fib6_node *fn)
static void node_free(struct net *net, struct fib6_node *fn)
{
{
	call_rcu(&fn->rcu, node_free_rcu);
	call_rcu(&fn->rcu, node_free_rcu);
	net->ipv6.rt6_stats->fib_nodes--;
}
}


void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
@@ -583,7 +587,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 *	node.
 *	node.
 */
 */


static struct fib6_node *fib6_add_1(struct fib6_table *table,
static struct fib6_node *fib6_add_1(struct net *net,
				    struct fib6_table *table,
				    struct fib6_node *root,
				    struct fib6_node *root,
				    struct in6_addr *addr, int plen,
				    struct in6_addr *addr, int plen,
				    int offset, int allow_create,
				    int offset, int allow_create,
@@ -675,7 +680,7 @@ static struct fib6_node *fib6_add_1(struct fib6_table *table,
	 *	Create new leaf node without children.
	 *	Create new leaf node without children.
	 */
	 */


	ln = node_alloc();
	ln = node_alloc(net);


	if (!ln)
	if (!ln)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);
@@ -716,14 +721,14 @@ static struct fib6_node *fib6_add_1(struct fib6_table *table,
	 *	(new leaf node)[ln] (old node)[fn]
	 *	(new leaf node)[ln] (old node)[fn]
	 */
	 */
	if (plen > bit) {
	if (plen > bit) {
		in = node_alloc();
		in = node_alloc(net);
		ln = node_alloc();
		ln = node_alloc(net);


		if (!in || !ln) {
		if (!in || !ln) {
			if (in)
			if (in)
				node_free_immediate(in);
				node_free_immediate(net, in);
			if (ln)
			if (ln)
				node_free_immediate(ln);
				node_free_immediate(net, ln);
			return ERR_PTR(-ENOMEM);
			return ERR_PTR(-ENOMEM);
		}
		}


@@ -768,7 +773,7 @@ static struct fib6_node *fib6_add_1(struct fib6_table *table,
		 *	     (old node)[fn] NULL
		 *	     (old node)[fn] NULL
		 */
		 */


		ln = node_alloc();
		ln = node_alloc(net);


		if (!ln)
		if (!ln)
			return ERR_PTR(-ENOMEM);
			return ERR_PTR(-ENOMEM);
@@ -1065,6 +1070,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
						fn->rr_ptr = NULL;
						fn->rr_ptr = NULL;
					rt6_release(iter);
					rt6_release(iter);
					nsiblings--;
					nsiblings--;
					info->nl_net->ipv6.rt6_stats->fib_rt_entries--;
				} else {
				} else {
					ins = &iter->dst.rt6_next;
					ins = &iter->dst.rt6_next;
				}
				}
@@ -1140,7 +1146,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
	if (!allow_create && !replace_required)
	if (!allow_create && !replace_required)
		pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
		pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");


	fn = fib6_add_1(table, root,
	fn = fib6_add_1(info->nl_net, table, root,
			&rt->rt6i_dst.addr, rt->rt6i_dst.plen,
			&rt->rt6i_dst.addr, rt->rt6i_dst.plen,
			offsetof(struct rt6_info, rt6i_dst), allow_create,
			offsetof(struct rt6_info, rt6i_dst), allow_create,
			replace_required, extack);
			replace_required, extack);
@@ -1170,7 +1176,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
			 */
			 */


			/* Create subtree root node */
			/* Create subtree root node */
			sfn = node_alloc();
			sfn = node_alloc(info->nl_net);
			if (!sfn)
			if (!sfn)
				goto failure;
				goto failure;


@@ -1181,8 +1187,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,


			/* Now add the first leaf node to new subtree */
			/* Now add the first leaf node to new subtree */


			sn = fib6_add_1(table, sfn, &rt->rt6i_src.addr,
			sn = fib6_add_1(info->nl_net, table, sfn,
					rt->rt6i_src.plen,
					&rt->rt6i_src.addr, rt->rt6i_src.plen,
					offsetof(struct rt6_info, rt6i_src),
					offsetof(struct rt6_info, rt6i_src),
					allow_create, replace_required, extack);
					allow_create, replace_required, extack);


@@ -1191,7 +1197,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
				   root, and then (in failure) stale node
				   root, and then (in failure) stale node
				   in main tree.
				   in main tree.
				 */
				 */
				node_free_immediate(sfn);
				node_free_immediate(info->nl_net, sfn);
				err = PTR_ERR(sn);
				err = PTR_ERR(sn);
				goto failure;
				goto failure;
			}
			}
@@ -1200,8 +1206,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
			rcu_assign_pointer(sfn->parent, fn);
			rcu_assign_pointer(sfn->parent, fn);
			rcu_assign_pointer(fn->subtree, sfn);
			rcu_assign_pointer(fn->subtree, sfn);
		} else {
		} else {
			sn = fib6_add_1(table, FIB6_SUBTREE(fn), &rt->rt6i_src.addr,
			sn = fib6_add_1(info->nl_net, table, FIB6_SUBTREE(fn),
					rt->rt6i_src.plen,
					&rt->rt6i_src.addr, rt->rt6i_src.plen,
					offsetof(struct rt6_info, rt6i_src),
					offsetof(struct rt6_info, rt6i_src),
					allow_create, replace_required, extack);
					allow_create, replace_required, extack);


@@ -1609,7 +1615,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
		}
		}
		read_unlock(&net->ipv6.fib6_walker_lock);
		read_unlock(&net->ipv6.fib6_walker_lock);


		node_free(fn);
		node_free(net, fn);
		if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
		if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
			return pn;
			return pn;


+14 −2
Original line number Original line Diff line number Diff line
@@ -143,9 +143,11 @@ static void rt6_uncached_list_del(struct rt6_info *rt)
{
{
	if (!list_empty(&rt->rt6i_uncached)) {
	if (!list_empty(&rt->rt6i_uncached)) {
		struct uncached_list *ul = rt->rt6i_uncached_list;
		struct uncached_list *ul = rt->rt6i_uncached_list;
		struct net *net = dev_net(rt->dst.dev);


		spin_lock_bh(&ul->lock);
		spin_lock_bh(&ul->lock);
		list_del(&rt->rt6i_uncached);
		list_del(&rt->rt6i_uncached);
		atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
		spin_unlock_bh(&ul->lock);
		spin_unlock_bh(&ul->lock);
	}
	}
}
}
@@ -359,8 +361,10 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
					1, DST_OBSOLETE_FORCE_CHK, flags);
					1, DST_OBSOLETE_FORCE_CHK, flags);


	if (rt)
	if (rt) {
		rt6_info_init(rt);
		rt6_info_init(rt);
		atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
	}


	return rt;
	return rt;
}
}
@@ -1156,6 +1160,8 @@ static DEFINE_SPINLOCK(rt6_exception_lock);
static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
				 struct rt6_exception *rt6_ex)
				 struct rt6_exception *rt6_ex)
{
{
	struct net *net = dev_net(rt6_ex->rt6i->dst.dev);

	if (!bucket || !rt6_ex)
	if (!bucket || !rt6_ex)
		return;
		return;
	rt6_ex->rt6i->rt6i_node = NULL;
	rt6_ex->rt6i->rt6i_node = NULL;
@@ -1164,6 +1170,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
	kfree_rcu(rt6_ex, rcu);
	kfree_rcu(rt6_ex, rcu);
	WARN_ON_ONCE(!bucket->depth);
	WARN_ON_ONCE(!bucket->depth);
	bucket->depth--;
	bucket->depth--;
	net->ipv6.rt6_stats->fib_rt_cache--;
}
}


/* Remove oldest rt6_ex in bucket and free the memory
/* Remove oldest rt6_ex in bucket and free the memory
@@ -1270,6 +1277,7 @@ __rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
static int rt6_insert_exception(struct rt6_info *nrt,
static int rt6_insert_exception(struct rt6_info *nrt,
				struct rt6_info *ort)
				struct rt6_info *ort)
{
{
	struct net *net = dev_net(ort->dst.dev);
	struct rt6_exception_bucket *bucket;
	struct rt6_exception_bucket *bucket;
	struct in6_addr *src_key = NULL;
	struct in6_addr *src_key = NULL;
	struct rt6_exception *rt6_ex;
	struct rt6_exception *rt6_ex;
@@ -1339,6 +1347,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
	nrt->rt6i_node = ort->rt6i_node;
	nrt->rt6i_node = ort->rt6i_node;
	hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
	hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
	bucket->depth++;
	bucket->depth++;
	net->ipv6.rt6_stats->fib_rt_cache++;


	if (bucket->depth > FIB6_MAX_DEPTH)
	if (bucket->depth > FIB6_MAX_DEPTH)
		rt6_exception_remove_oldest(bucket);
		rt6_exception_remove_oldest(bucket);
@@ -1714,6 +1723,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
			 * No need for another dst_hold()
			 * No need for another dst_hold()
			 */
			 */
			rt6_uncached_list_add(uncached_rt);
			rt6_uncached_list_add(uncached_rt);
			atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
		} else {
		} else {
			uncached_rt = net->ipv6.ip6_null_entry;
			uncached_rt = net->ipv6.ip6_null_entry;
			dst_hold(&uncached_rt->dst);
			dst_hold(&uncached_rt->dst);
@@ -1894,6 +1904,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
		       DST_OBSOLETE_NONE, 0);
		       DST_OBSOLETE_NONE, 0);
	if (rt) {
	if (rt) {
		rt6_info_init(rt);
		rt6_info_init(rt);
		atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);


		new = &rt->dst;
		new = &rt->dst;
		new->__use = 1;
		new->__use = 1;
@@ -2341,6 +2352,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
	 * do proper release of the net_device
	 * do proper release of the net_device
	 */
	 */
	rt6_uncached_list_add(rt);
	rt6_uncached_list_add(rt);
	atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);


	dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
	dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);


@@ -4422,7 +4434,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
		   net->ipv6.rt6_stats->fib_nodes,
		   net->ipv6.rt6_stats->fib_nodes,
		   net->ipv6.rt6_stats->fib_route_nodes,
		   net->ipv6.rt6_stats->fib_route_nodes,
		   net->ipv6.rt6_stats->fib_rt_alloc,
		   atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
		   net->ipv6.rt6_stats->fib_rt_entries,
		   net->ipv6.rt6_stats->fib_rt_entries,
		   net->ipv6.rt6_stats->fib_rt_cache,
		   net->ipv6.rt6_stats->fib_rt_cache,
		   dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
		   dst_entries_get_slow(&net->ipv6.ip6_dst_ops),