summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_fib.h15
-rw-r--r--net/ipv6/ip6_fib.c42
-rw-r--r--net/ipv6/route.c16
3 files changed, 47 insertions, 26 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 0b438b9bcb10..10c913816032 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -297,12 +297,15 @@ struct fib6_walker {
297}; 297};
298 298
299struct rt6_statistics { 299struct rt6_statistics {
300 __u32 fib_nodes; 300 __u32 fib_nodes; /* all fib6 nodes */
301 __u32 fib_route_nodes; 301 __u32 fib_route_nodes; /* intermediate nodes */
302 __u32 fib_rt_alloc; /* permanent routes */ 302 __u32 fib_rt_entries; /* rt entries in fib table */
303 __u32 fib_rt_entries; /* rt entries in table */ 303 __u32 fib_rt_cache; /* cached rt entries in exception table */
304 __u32 fib_rt_cache; /* cache routes */ 304 __u32 fib_discarded_routes; /* total number of routes delete */
305 __u32 fib_discarded_routes; 305
306 /* The following stats are not protected by any lock */
307 atomic_t fib_rt_alloc; /* total number of routes alloced */
308 atomic_t fib_rt_uncache; /* rt entries in uncached list */
306}; 309};
307 310
308#define RTN_TL_ROOT 0x0001 311#define RTN_TL_ROOT 0x0001
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 3f95908b39c3..52a29ba32928 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -149,18 +149,21 @@ static __be32 addr_bit_set(const void *token, int fn_bit)
149 addr[fn_bit >> 5]; 149 addr[fn_bit >> 5];
150} 150}
151 151
152static struct fib6_node *node_alloc(void) 152static struct fib6_node *node_alloc(struct net *net)
153{ 153{
154 struct fib6_node *fn; 154 struct fib6_node *fn;
155 155
156 fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC); 156 fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC);
157 if (fn)
158 net->ipv6.rt6_stats->fib_nodes++;
157 159
158 return fn; 160 return fn;
159} 161}
160 162
161static void node_free_immediate(struct fib6_node *fn) 163static void node_free_immediate(struct net *net, struct fib6_node *fn)
162{ 164{
163 kmem_cache_free(fib6_node_kmem, fn); 165 kmem_cache_free(fib6_node_kmem, fn);
166 net->ipv6.rt6_stats->fib_nodes--;
164} 167}
165 168
166static void node_free_rcu(struct rcu_head *head) 169static void node_free_rcu(struct rcu_head *head)
@@ -170,9 +173,10 @@ static void node_free_rcu(struct rcu_head *head)
170 kmem_cache_free(fib6_node_kmem, fn); 173 kmem_cache_free(fib6_node_kmem, fn);
171} 174}
172 175
173static void node_free(struct fib6_node *fn) 176static void node_free(struct net *net, struct fib6_node *fn)
174{ 177{
175 call_rcu(&fn->rcu, node_free_rcu); 178 call_rcu(&fn->rcu, node_free_rcu);
179 net->ipv6.rt6_stats->fib_nodes--;
176} 180}
177 181
178void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) 182void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
@@ -583,7 +587,8 @@ out:
583 * node. 587 * node.
584 */ 588 */
585 589
586static struct fib6_node *fib6_add_1(struct fib6_table *table, 590static struct fib6_node *fib6_add_1(struct net *net,
591 struct fib6_table *table,
587 struct fib6_node *root, 592 struct fib6_node *root,
588 struct in6_addr *addr, int plen, 593 struct in6_addr *addr, int plen,
589 int offset, int allow_create, 594 int offset, int allow_create,
@@ -675,7 +680,7 @@ static struct fib6_node *fib6_add_1(struct fib6_table *table,
675 * Create new leaf node without children. 680 * Create new leaf node without children.
676 */ 681 */
677 682
678 ln = node_alloc(); 683 ln = node_alloc(net);
679 684
680 if (!ln) 685 if (!ln)
681 return ERR_PTR(-ENOMEM); 686 return ERR_PTR(-ENOMEM);
@@ -716,14 +721,14 @@ insert_above:
716 * (new leaf node)[ln] (old node)[fn] 721 * (new leaf node)[ln] (old node)[fn]
717 */ 722 */
718 if (plen > bit) { 723 if (plen > bit) {
719 in = node_alloc(); 724 in = node_alloc(net);
720 ln = node_alloc(); 725 ln = node_alloc(net);
721 726
722 if (!in || !ln) { 727 if (!in || !ln) {
723 if (in) 728 if (in)
724 node_free_immediate(in); 729 node_free_immediate(net, in);
725 if (ln) 730 if (ln)
726 node_free_immediate(ln); 731 node_free_immediate(net, ln);
727 return ERR_PTR(-ENOMEM); 732 return ERR_PTR(-ENOMEM);
728 } 733 }
729 734
@@ -768,7 +773,7 @@ insert_above:
768 * (old node)[fn] NULL 773 * (old node)[fn] NULL
769 */ 774 */
770 775
771 ln = node_alloc(); 776 ln = node_alloc(net);
772 777
773 if (!ln) 778 if (!ln)
774 return ERR_PTR(-ENOMEM); 779 return ERR_PTR(-ENOMEM);
@@ -1065,6 +1070,7 @@ add:
1065 fn->rr_ptr = NULL; 1070 fn->rr_ptr = NULL;
1066 rt6_release(iter); 1071 rt6_release(iter);
1067 nsiblings--; 1072 nsiblings--;
1073 info->nl_net->ipv6.rt6_stats->fib_rt_entries--;
1068 } else { 1074 } else {
1069 ins = &iter->dst.rt6_next; 1075 ins = &iter->dst.rt6_next;
1070 } 1076 }
@@ -1140,7 +1146,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
1140 if (!allow_create && !replace_required) 1146 if (!allow_create && !replace_required)
1141 pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n"); 1147 pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
1142 1148
1143 fn = fib6_add_1(table, root, 1149 fn = fib6_add_1(info->nl_net, table, root,
1144 &rt->rt6i_dst.addr, rt->rt6i_dst.plen, 1150 &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
1145 offsetof(struct rt6_info, rt6i_dst), allow_create, 1151 offsetof(struct rt6_info, rt6i_dst), allow_create,
1146 replace_required, extack); 1152 replace_required, extack);
@@ -1170,7 +1176,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
1170 */ 1176 */
1171 1177
1172 /* Create subtree root node */ 1178 /* Create subtree root node */
1173 sfn = node_alloc(); 1179 sfn = node_alloc(info->nl_net);
1174 if (!sfn) 1180 if (!sfn)
1175 goto failure; 1181 goto failure;
1176 1182
@@ -1181,8 +1187,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
1181 1187
1182 /* Now add the first leaf node to new subtree */ 1188 /* Now add the first leaf node to new subtree */
1183 1189
1184 sn = fib6_add_1(table, sfn, &rt->rt6i_src.addr, 1190 sn = fib6_add_1(info->nl_net, table, sfn,
1185 rt->rt6i_src.plen, 1191 &rt->rt6i_src.addr, rt->rt6i_src.plen,
1186 offsetof(struct rt6_info, rt6i_src), 1192 offsetof(struct rt6_info, rt6i_src),
1187 allow_create, replace_required, extack); 1193 allow_create, replace_required, extack);
1188 1194
@@ -1191,7 +1197,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
1191 root, and then (in failure) stale node 1197 root, and then (in failure) stale node
1192 in main tree. 1198 in main tree.
1193 */ 1199 */
1194 node_free_immediate(sfn); 1200 node_free_immediate(info->nl_net, sfn);
1195 err = PTR_ERR(sn); 1201 err = PTR_ERR(sn);
1196 goto failure; 1202 goto failure;
1197 } 1203 }
@@ -1200,8 +1206,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
1200 rcu_assign_pointer(sfn->parent, fn); 1206 rcu_assign_pointer(sfn->parent, fn);
1201 rcu_assign_pointer(fn->subtree, sfn); 1207 rcu_assign_pointer(fn->subtree, sfn);
1202 } else { 1208 } else {
1203 sn = fib6_add_1(table, FIB6_SUBTREE(fn), &rt->rt6i_src.addr, 1209 sn = fib6_add_1(info->nl_net, table, FIB6_SUBTREE(fn),
1204 rt->rt6i_src.plen, 1210 &rt->rt6i_src.addr, rt->rt6i_src.plen,
1205 offsetof(struct rt6_info, rt6i_src), 1211 offsetof(struct rt6_info, rt6i_src),
1206 allow_create, replace_required, extack); 1212 allow_create, replace_required, extack);
1207 1213
@@ -1609,7 +1615,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
1609 } 1615 }
1610 read_unlock(&net->ipv6.fib6_walker_lock); 1616 read_unlock(&net->ipv6.fib6_walker_lock);
1611 1617
1612 node_free(fn); 1618 node_free(net, fn);
1613 if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn)) 1619 if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
1614 return pn; 1620 return pn;
1615 1621
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index cf44d0994b1e..399d1bceec4a 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -143,9 +143,11 @@ static void rt6_uncached_list_del(struct rt6_info *rt)
143{ 143{
144 if (!list_empty(&rt->rt6i_uncached)) { 144 if (!list_empty(&rt->rt6i_uncached)) {
145 struct uncached_list *ul = rt->rt6i_uncached_list; 145 struct uncached_list *ul = rt->rt6i_uncached_list;
146 struct net *net = dev_net(rt->dst.dev);
146 147
147 spin_lock_bh(&ul->lock); 148 spin_lock_bh(&ul->lock);
148 list_del(&rt->rt6i_uncached); 149 list_del(&rt->rt6i_uncached);
150 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
149 spin_unlock_bh(&ul->lock); 151 spin_unlock_bh(&ul->lock);
150 } 152 }
151} 153}
@@ -359,8 +361,10 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
359 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, 361 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
360 1, DST_OBSOLETE_FORCE_CHK, flags); 362 1, DST_OBSOLETE_FORCE_CHK, flags);
361 363
362 if (rt) 364 if (rt) {
363 rt6_info_init(rt); 365 rt6_info_init(rt);
366 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
367 }
364 368
365 return rt; 369 return rt;
366} 370}
@@ -1156,6 +1160,8 @@ static DEFINE_SPINLOCK(rt6_exception_lock);
1156static void rt6_remove_exception(struct rt6_exception_bucket *bucket, 1160static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1157 struct rt6_exception *rt6_ex) 1161 struct rt6_exception *rt6_ex)
1158{ 1162{
1163 struct net *net = dev_net(rt6_ex->rt6i->dst.dev);
1164
1159 if (!bucket || !rt6_ex) 1165 if (!bucket || !rt6_ex)
1160 return; 1166 return;
1161 rt6_ex->rt6i->rt6i_node = NULL; 1167 rt6_ex->rt6i->rt6i_node = NULL;
@@ -1164,6 +1170,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1164 kfree_rcu(rt6_ex, rcu); 1170 kfree_rcu(rt6_ex, rcu);
1165 WARN_ON_ONCE(!bucket->depth); 1171 WARN_ON_ONCE(!bucket->depth);
1166 bucket->depth--; 1172 bucket->depth--;
1173 net->ipv6.rt6_stats->fib_rt_cache--;
1167} 1174}
1168 1175
1169/* Remove oldest rt6_ex in bucket and free the memory 1176/* Remove oldest rt6_ex in bucket and free the memory
@@ -1270,6 +1277,7 @@ __rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1270static int rt6_insert_exception(struct rt6_info *nrt, 1277static int rt6_insert_exception(struct rt6_info *nrt,
1271 struct rt6_info *ort) 1278 struct rt6_info *ort)
1272{ 1279{
1280 struct net *net = dev_net(ort->dst.dev);
1273 struct rt6_exception_bucket *bucket; 1281 struct rt6_exception_bucket *bucket;
1274 struct in6_addr *src_key = NULL; 1282 struct in6_addr *src_key = NULL;
1275 struct rt6_exception *rt6_ex; 1283 struct rt6_exception *rt6_ex;
@@ -1339,6 +1347,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,
1339 nrt->rt6i_node = ort->rt6i_node; 1347 nrt->rt6i_node = ort->rt6i_node;
1340 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain); 1348 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1341 bucket->depth++; 1349 bucket->depth++;
1350 net->ipv6.rt6_stats->fib_rt_cache++;
1342 1351
1343 if (bucket->depth > FIB6_MAX_DEPTH) 1352 if (bucket->depth > FIB6_MAX_DEPTH)
1344 rt6_exception_remove_oldest(bucket); 1353 rt6_exception_remove_oldest(bucket);
@@ -1714,6 +1723,7 @@ redo_rt6_select:
1714 * No need for another dst_hold() 1723 * No need for another dst_hold()
1715 */ 1724 */
1716 rt6_uncached_list_add(uncached_rt); 1725 rt6_uncached_list_add(uncached_rt);
1726 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
1717 } else { 1727 } else {
1718 uncached_rt = net->ipv6.ip6_null_entry; 1728 uncached_rt = net->ipv6.ip6_null_entry;
1719 dst_hold(&uncached_rt->dst); 1729 dst_hold(&uncached_rt->dst);
@@ -1894,6 +1904,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
1894 DST_OBSOLETE_NONE, 0); 1904 DST_OBSOLETE_NONE, 0);
1895 if (rt) { 1905 if (rt) {
1896 rt6_info_init(rt); 1906 rt6_info_init(rt);
1907 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
1897 1908
1898 new = &rt->dst; 1909 new = &rt->dst;
1899 new->__use = 1; 1910 new->__use = 1;
@@ -2341,6 +2352,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
2341 * do proper release of the net_device 2352 * do proper release of the net_device
2342 */ 2353 */
2343 rt6_uncached_list_add(rt); 2354 rt6_uncached_list_add(rt);
2355 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
2344 2356
2345 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); 2357 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2346 2358
@@ -4422,7 +4434,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
4422 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", 4434 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
4423 net->ipv6.rt6_stats->fib_nodes, 4435 net->ipv6.rt6_stats->fib_nodes,
4424 net->ipv6.rt6_stats->fib_route_nodes, 4436 net->ipv6.rt6_stats->fib_route_nodes,
4425 net->ipv6.rt6_stats->fib_rt_alloc, 4437 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
4426 net->ipv6.rt6_stats->fib_rt_entries, 4438 net->ipv6.rt6_stats->fib_rt_entries,
4427 net->ipv6.rt6_stats->fib_rt_cache, 4439 net->ipv6.rt6_stats->fib_rt_cache,
4428 dst_entries_get_slow(&net->ipv6.ip6_dst_ops), 4440 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),