diff options
Diffstat (limited to 'net/ipv6/ip6_fib.c')
| -rw-r--r-- | net/ipv6/ip6_fib.c | 52 |
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 | ||
| 94 | static void fib6_gc_timer_cb(unsigned long arg); | 94 | static void fib6_gc_timer_cb(unsigned long arg); |
| 95 | 95 | ||
| 96 | static struct fib6_walker_t fib6_walker_list = { | 96 | static 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 | ||
| 103 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 99 | static 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 | ||
| 113 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 106 | static 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 | } |
| 121 | static __inline__ u32 fib6_new_sernum(void) | 112 | static __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 | ||
| 242 | static void fib6_tables_init(struct net *net) | 233 | static 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 | ||
| 265 | static void fib6_tables_init(struct net *net) | 256 | static 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 | ||
| 1472 | static int fib6_net_init(struct net *net) | 1488 | static 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 | ||
