@@ -160,6 +160,8 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh)
160160 INIT_LIST_HEAD (& f6i -> fib6_siblings );
161161 refcount_set (& f6i -> fib6_ref , 1 );
162162
163+ INIT_HLIST_NODE (& f6i -> gc_link );
164+
163165 return f6i ;
164166}
165167
@@ -246,6 +248,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
246248 net -> ipv6 .fib6_null_entry );
247249 table -> tb6_root .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO ;
248250 inet_peer_base_init (& table -> tb6_peers );
251+ INIT_HLIST_HEAD (& table -> tb6_gc_hlist );
249252 }
250253
251254 return table ;
@@ -1055,6 +1058,9 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
10551058 lockdep_is_held (& table -> tb6_lock ));
10561059 }
10571060 }
1061+
1062+ fib6_clean_expires (rt );
1063+ fib6_remove_gc_list (rt );
10581064}
10591065
10601066/*
@@ -1115,10 +1121,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
11151121 rt -> fib6_nsiblings = 0 ;
11161122 if (!(iter -> fib6_flags & RTF_EXPIRES ))
11171123 return - EEXIST ;
1118- if (!(rt -> fib6_flags & RTF_EXPIRES ))
1124+ if (!(rt -> fib6_flags & RTF_EXPIRES )) {
11191125 fib6_clean_expires (iter );
1120- else
1126+ fib6_remove_gc_list (iter );
1127+ } else {
11211128 fib6_set_expires (iter , rt -> expires );
1129+ fib6_add_gc_list (iter );
1130+ }
11221131
11231132 if (rt -> fib6_pmtu )
11241133 fib6_metric_set (iter , RTAX_MTU ,
@@ -1477,6 +1486,10 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
14771486 if (rt -> nh )
14781487 list_add (& rt -> nh_list , & rt -> nh -> f6i_list );
14791488 __fib6_update_sernum_upto_root (rt , fib6_new_sernum (info -> nl_net ));
1489+
1490+ if (rt -> fib6_flags & RTF_EXPIRES )
1491+ fib6_add_gc_list (rt );
1492+
14801493 fib6_start_gc (info -> nl_net , rt );
14811494 }
14821495
@@ -2280,9 +2293,8 @@ static void fib6_flush_trees(struct net *net)
22802293 * Garbage collection
22812294 */
22822295
2283- static int fib6_age (struct fib6_info * rt , void * arg )
2296+ static int fib6_age (struct fib6_info * rt , struct fib6_gc_args * gc_args )
22842297{
2285- struct fib6_gc_args * gc_args = arg ;
22862298 unsigned long now = jiffies ;
22872299
22882300 /*
@@ -2307,6 +2319,42 @@ static int fib6_age(struct fib6_info *rt, void *arg)
23072319 return 0 ;
23082320}
23092321
2322+ static void fib6_gc_table (struct net * net ,
2323+ struct fib6_table * tb6 ,
2324+ struct fib6_gc_args * gc_args )
2325+ {
2326+ struct fib6_info * rt ;
2327+ struct hlist_node * n ;
2328+ struct nl_info info = {
2329+ .nl_net = net ,
2330+ .skip_notify = false,
2331+ };
2332+
2333+ hlist_for_each_entry_safe (rt , n , & tb6 -> tb6_gc_hlist , gc_link )
2334+ if (fib6_age (rt , gc_args ) == -1 )
2335+ fib6_del (rt , & info );
2336+ }
2337+
2338+ static void fib6_gc_all (struct net * net , struct fib6_gc_args * gc_args )
2339+ {
2340+ struct fib6_table * table ;
2341+ struct hlist_head * head ;
2342+ unsigned int h ;
2343+
2344+ rcu_read_lock ();
2345+ for (h = 0 ; h < FIB6_TABLE_HASHSZ ; h ++ ) {
2346+ head = & net -> ipv6 .fib_table_hash [h ];
2347+ hlist_for_each_entry_rcu (table , head , tb6_hlist ) {
2348+ spin_lock_bh (& table -> tb6_lock );
2349+
2350+ fib6_gc_table (net , table , gc_args );
2351+
2352+ spin_unlock_bh (& table -> tb6_lock );
2353+ }
2354+ }
2355+ rcu_read_unlock ();
2356+ }
2357+
23102358void fib6_run_gc (unsigned long expires , struct net * net , bool force )
23112359{
23122360 struct fib6_gc_args gc_args ;
@@ -2322,7 +2370,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force)
23222370 net -> ipv6 .sysctl .ip6_rt_gc_interval ;
23232371 gc_args .more = 0 ;
23242372
2325- fib6_clean_all (net , fib6_age , & gc_args );
2373+ fib6_gc_all (net , & gc_args );
23262374 now = jiffies ;
23272375 net -> ipv6 .ip6_rt_last_gc = now ;
23282376
@@ -2382,6 +2430,7 @@ static int __net_init fib6_net_init(struct net *net)
23822430 net -> ipv6 .fib6_main_tbl -> tb6_root .fn_flags =
23832431 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO ;
23842432 inet_peer_base_init (& net -> ipv6 .fib6_main_tbl -> tb6_peers );
2433+ INIT_HLIST_HEAD (& net -> ipv6 .fib6_main_tbl -> tb6_gc_hlist );
23852434
23862435#ifdef CONFIG_IPV6_MULTIPLE_TABLES
23872436 net -> ipv6 .fib6_local_tbl = kzalloc (sizeof (* net -> ipv6 .fib6_local_tbl ),
@@ -2394,6 +2443,7 @@ static int __net_init fib6_net_init(struct net *net)
23942443 net -> ipv6 .fib6_local_tbl -> tb6_root .fn_flags =
23952444 RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO ;
23962445 inet_peer_base_init (& net -> ipv6 .fib6_local_tbl -> tb6_peers );
2446+ INIT_HLIST_HEAD (& net -> ipv6 .fib6_local_tbl -> tb6_gc_hlist );
23972447#endif
23982448 fib6_tables_init (net );
23992449
0 commit comments