mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 05:34:13 +08:00
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: 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
66f5d6ce53
commit
81eb8447da
@ -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
|
||||||
|
@ -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 @@ out:
|
|||||||
* 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 @@ insert_above:
|
|||||||
* (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 @@ insert_above:
|
|||||||
* (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 @@ add:
|
|||||||
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;
|
||||||
|
|
||||||
|
@ -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 @@ redo_rt6_select:
|
|||||||
* 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),
|
||||||
|
Loading…
Reference in New Issue
Block a user