aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_fib.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r--net/ipv6/ip6_fib.c52
1 files changed, 34 insertions, 18 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 0e93ca56eb69..2f9847924fa5 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -93,29 +93,20 @@ static __u32 rt_sernum;
93 93
94static void fib6_gc_timer_cb(unsigned long arg); 94static void fib6_gc_timer_cb(unsigned long arg);
95 95
96static struct fib6_walker_t fib6_walker_list = { 96static LIST_HEAD(fib6_walkers);
97 .prev = &fib6_walker_list, 97#define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh)
98 .next = &fib6_walker_list,
99};
100
101#define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
102 98
103static inline void fib6_walker_link(struct fib6_walker_t *w) 99static inline void fib6_walker_link(struct fib6_walker_t *w)
104{ 100{
105 write_lock_bh(&fib6_walker_lock); 101 write_lock_bh(&fib6_walker_lock);
106 w->next = fib6_walker_list.next; 102 list_add(&w->lh, &fib6_walkers);
107 w->prev = &fib6_walker_list;
108 w->next->prev = w;
109 w->prev->next = w;
110 write_unlock_bh(&fib6_walker_lock); 103 write_unlock_bh(&fib6_walker_lock);
111} 104}
112 105
113static inline void fib6_walker_unlink(struct fib6_walker_t *w) 106static inline void fib6_walker_unlink(struct fib6_walker_t *w)
114{ 107{
115 write_lock_bh(&fib6_walker_lock); 108 write_lock_bh(&fib6_walker_lock);
116 w->next->prev = w->prev; 109 list_del(&w->lh);
117 w->prev->next = w->next;
118 w->prev = w->next = w;
119 write_unlock_bh(&fib6_walker_lock); 110 write_unlock_bh(&fib6_walker_lock);
120} 111}
121static __inline__ u32 fib6_new_sernum(void) 112static __inline__ u32 fib6_new_sernum(void)
@@ -239,7 +230,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
239 return NULL; 230 return NULL;
240} 231}
241 232
242static void fib6_tables_init(struct net *net) 233static void __net_init fib6_tables_init(struct net *net)
243{ 234{
244 fib6_link_table(net, net->ipv6.fib6_main_tbl); 235 fib6_link_table(net, net->ipv6.fib6_main_tbl);
245 fib6_link_table(net, net->ipv6.fib6_local_tbl); 236 fib6_link_table(net, net->ipv6.fib6_local_tbl);
@@ -262,7 +253,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
262 return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); 253 return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
263} 254}
264 255
265static void fib6_tables_init(struct net *net) 256static void __net_init fib6_tables_init(struct net *net)
266{ 257{
267 fib6_link_table(net, net->ipv6.fib6_main_tbl); 258 fib6_link_table(net, net->ipv6.fib6_main_tbl);
268} 259}
@@ -319,12 +310,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
319 w->root = &table->tb6_root; 310 w->root = &table->tb6_root;
320 311
321 if (cb->args[4] == 0) { 312 if (cb->args[4] == 0) {
313 w->count = 0;
314 w->skip = 0;
315
322 read_lock_bh(&table->tb6_lock); 316 read_lock_bh(&table->tb6_lock);
323 res = fib6_walk(w); 317 res = fib6_walk(w);
324 read_unlock_bh(&table->tb6_lock); 318 read_unlock_bh(&table->tb6_lock);
325 if (res > 0) 319 if (res > 0) {
326 cb->args[4] = 1; 320 cb->args[4] = 1;
321 cb->args[5] = w->root->fn_sernum;
322 }
327 } else { 323 } else {
324 if (cb->args[5] != w->root->fn_sernum) {
325 /* Begin at the root if the tree changed */
326 cb->args[5] = w->root->fn_sernum;
327 w->state = FWS_INIT;
328 w->node = w->root;
329 w->skip = w->count;
330 } else
331 w->skip = 0;
332
328 read_lock_bh(&table->tb6_lock); 333 read_lock_bh(&table->tb6_lock);
329 res = fib6_walk_continue(w); 334 res = fib6_walk_continue(w);
330 read_unlock_bh(&table->tb6_lock); 335 read_unlock_bh(&table->tb6_lock);
@@ -1250,9 +1255,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w)
1250 w->leaf = fn->leaf; 1255 w->leaf = fn->leaf;
1251 case FWS_C: 1256 case FWS_C:
1252 if (w->leaf && fn->fn_flags&RTN_RTINFO) { 1257 if (w->leaf && fn->fn_flags&RTN_RTINFO) {
1253 int err = w->func(w); 1258 int err;
1259
1260 if (w->count < w->skip) {
1261 w->count++;
1262 continue;
1263 }
1264
1265 err = w->func(w);
1254 if (err) 1266 if (err)
1255 return err; 1267 return err;
1268
1269 w->count++;
1256 continue; 1270 continue;
1257 } 1271 }
1258 w->state = FWS_U; 1272 w->state = FWS_U;
@@ -1346,6 +1360,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,
1346 c.w.root = root; 1360 c.w.root = root;
1347 c.w.func = fib6_clean_node; 1361 c.w.func = fib6_clean_node;
1348 c.w.prune = prune; 1362 c.w.prune = prune;
1363 c.w.count = 0;
1364 c.w.skip = 0;
1349 c.func = func; 1365 c.func = func;
1350 c.arg = arg; 1366 c.arg = arg;
1351 c.net = net; 1367 c.net = net;
@@ -1469,7 +1485,7 @@ static void fib6_gc_timer_cb(unsigned long arg)
1469 fib6_run_gc(0, (struct net *)arg); 1485 fib6_run_gc(0, (struct net *)arg);
1470} 1486}
1471 1487
1472static int fib6_net_init(struct net *net) 1488static int __net_init fib6_net_init(struct net *net)
1473{ 1489{
1474 setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); 1490 setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
1475 1491