diff options
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r-- | net/ipv6/ip6_fib.c | 161 |
1 files changed, 93 insertions, 68 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 04d774963f3c..7b549f0bc428 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -166,16 +166,13 @@ static __inline__ void rt6_release(struct rt6_info *rt) | |||
166 | dst_free(&rt->u.dst); | 166 | dst_free(&rt->u.dst); |
167 | } | 167 | } |
168 | 168 | ||
169 | static struct fib6_table *fib6_main_tbl; | ||
170 | |||
171 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 169 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
172 | #define FIB_TABLE_HASHSZ 256 | 170 | #define FIB_TABLE_HASHSZ 256 |
173 | #else | 171 | #else |
174 | #define FIB_TABLE_HASHSZ 1 | 172 | #define FIB_TABLE_HASHSZ 1 |
175 | #endif | 173 | #endif |
176 | static struct hlist_head *fib_table_hash; | ||
177 | 174 | ||
178 | static void fib6_link_table(struct fib6_table *tb) | 175 | static void fib6_link_table(struct net *net, struct fib6_table *tb) |
179 | { | 176 | { |
180 | unsigned int h; | 177 | unsigned int h; |
181 | 178 | ||
@@ -191,13 +188,11 @@ static void fib6_link_table(struct fib6_table *tb) | |||
191 | * No protection necessary, this is the only list mutatation | 188 | * No protection necessary, this is the only list mutatation |
192 | * operation, tables never disappear once they exist. | 189 | * operation, tables never disappear once they exist. |
193 | */ | 190 | */ |
194 | hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); | 191 | hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]); |
195 | } | 192 | } |
196 | 193 | ||
197 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 194 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
198 | 195 | ||
199 | static struct fib6_table *fib6_local_tbl; | ||
200 | |||
201 | static struct fib6_table *fib6_alloc_table(u32 id) | 196 | static struct fib6_table *fib6_alloc_table(u32 id) |
202 | { | 197 | { |
203 | struct fib6_table *table; | 198 | struct fib6_table *table; |
@@ -212,26 +207,27 @@ static struct fib6_table *fib6_alloc_table(u32 id) | |||
212 | return table; | 207 | return table; |
213 | } | 208 | } |
214 | 209 | ||
215 | struct fib6_table *fib6_new_table(u32 id) | 210 | struct fib6_table *fib6_new_table(struct net *net, u32 id) |
216 | { | 211 | { |
217 | struct fib6_table *tb; | 212 | struct fib6_table *tb; |
218 | 213 | ||
219 | if (id == 0) | 214 | if (id == 0) |
220 | id = RT6_TABLE_MAIN; | 215 | id = RT6_TABLE_MAIN; |
221 | tb = fib6_get_table(id); | 216 | tb = fib6_get_table(net, id); |
222 | if (tb) | 217 | if (tb) |
223 | return tb; | 218 | return tb; |
224 | 219 | ||
225 | tb = fib6_alloc_table(id); | 220 | tb = fib6_alloc_table(id); |
226 | if (tb != NULL) | 221 | if (tb != NULL) |
227 | fib6_link_table(tb); | 222 | fib6_link_table(net, tb); |
228 | 223 | ||
229 | return tb; | 224 | return tb; |
230 | } | 225 | } |
231 | 226 | ||
232 | struct fib6_table *fib6_get_table(u32 id) | 227 | struct fib6_table *fib6_get_table(struct net *net, u32 id) |
233 | { | 228 | { |
234 | struct fib6_table *tb; | 229 | struct fib6_table *tb; |
230 | struct hlist_head *head; | ||
235 | struct hlist_node *node; | 231 | struct hlist_node *node; |
236 | unsigned int h; | 232 | unsigned int h; |
237 | 233 | ||
@@ -239,7 +235,8 @@ struct fib6_table *fib6_get_table(u32 id) | |||
239 | id = RT6_TABLE_MAIN; | 235 | id = RT6_TABLE_MAIN; |
240 | h = id & (FIB_TABLE_HASHSZ - 1); | 236 | h = id & (FIB_TABLE_HASHSZ - 1); |
241 | rcu_read_lock(); | 237 | rcu_read_lock(); |
242 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) { | 238 | head = &net->ipv6.fib_table_hash[h]; |
239 | hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { | ||
243 | if (tb->tb6_id == id) { | 240 | if (tb->tb6_id == id) { |
244 | rcu_read_unlock(); | 241 | rcu_read_unlock(); |
245 | return tb; | 242 | return tb; |
@@ -250,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id) | |||
250 | return NULL; | 247 | return NULL; |
251 | } | 248 | } |
252 | 249 | ||
253 | static void __init fib6_tables_init(void) | 250 | static void fib6_tables_init(struct net *net) |
254 | { | 251 | { |
255 | fib6_link_table(fib6_main_tbl); | 252 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
256 | fib6_link_table(fib6_local_tbl); | 253 | fib6_link_table(net, net->ipv6.fib6_local_tbl); |
257 | } | 254 | } |
258 | |||
259 | #else | 255 | #else |
260 | 256 | ||
261 | struct fib6_table *fib6_new_table(u32 id) | 257 | struct fib6_table *fib6_new_table(struct net *net, u32 id) |
262 | { | 258 | { |
263 | return fib6_get_table(id); | 259 | return fib6_get_table(net, id); |
264 | } | 260 | } |
265 | 261 | ||
266 | struct fib6_table *fib6_get_table(u32 id) | 262 | struct fib6_table *fib6_get_table(struct net *net, u32 id) |
267 | { | 263 | { |
268 | return fib6_main_tbl; | 264 | return net->ipv6.fib6_main_tbl; |
269 | } | 265 | } |
270 | 266 | ||
271 | struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, | 267 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, |
272 | pol_lookup_t lookup) | 268 | int flags, pol_lookup_t lookup) |
273 | { | 269 | { |
274 | return (struct dst_entry *) lookup(fib6_main_tbl, fl, flags); | 270 | return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags); |
275 | } | 271 | } |
276 | 272 | ||
277 | static void __init fib6_tables_init(void) | 273 | static void fib6_tables_init(struct net *net) |
278 | { | 274 | { |
279 | fib6_link_table(fib6_main_tbl); | 275 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
280 | } | 276 | } |
281 | 277 | ||
282 | #endif | 278 | #endif |
@@ -357,11 +353,9 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
357 | struct fib6_walker_t *w; | 353 | struct fib6_walker_t *w; |
358 | struct fib6_table *tb; | 354 | struct fib6_table *tb; |
359 | struct hlist_node *node; | 355 | struct hlist_node *node; |
356 | struct hlist_head *head; | ||
360 | int res = 0; | 357 | int res = 0; |
361 | 358 | ||
362 | if (net != &init_net) | ||
363 | return 0; | ||
364 | |||
365 | s_h = cb->args[0]; | 359 | s_h = cb->args[0]; |
366 | s_e = cb->args[1]; | 360 | s_e = cb->args[1]; |
367 | 361 | ||
@@ -390,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
390 | 384 | ||
391 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { | 385 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { |
392 | e = 0; | 386 | e = 0; |
393 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) { | 387 | head = &net->ipv6.fib_table_hash[h]; |
388 | hlist_for_each_entry(tb, node, head, tb6_hlist) { | ||
394 | if (e < s_e) | 389 | if (e < s_e) |
395 | goto next; | 390 | goto next; |
396 | res = fib6_dump_table(tb, skb, cb); | 391 | res = fib6_dump_table(tb, skb, cb); |
@@ -1360,12 +1355,13 @@ void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), | |||
1360 | { | 1355 | { |
1361 | struct fib6_table *table; | 1356 | struct fib6_table *table; |
1362 | struct hlist_node *node; | 1357 | struct hlist_node *node; |
1358 | struct hlist_head *head; | ||
1363 | unsigned int h; | 1359 | unsigned int h; |
1364 | 1360 | ||
1365 | rcu_read_lock(); | 1361 | rcu_read_lock(); |
1366 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { | 1362 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
1367 | hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], | 1363 | head = &init_net.ipv6.fib_table_hash[h]; |
1368 | tb6_hlist) { | 1364 | hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { |
1369 | write_lock_bh(&table->tb6_lock); | 1365 | write_lock_bh(&table->tb6_lock); |
1370 | fib6_clean_tree(&table->tb6_root, func, prune, arg); | 1366 | fib6_clean_tree(&table->tb6_root, func, prune, arg); |
1371 | write_unlock_bh(&table->tb6_lock); | 1367 | write_unlock_bh(&table->tb6_lock); |
@@ -1466,55 +1462,88 @@ void fib6_run_gc(unsigned long dummy) | |||
1466 | spin_unlock_bh(&fib6_gc_lock); | 1462 | spin_unlock_bh(&fib6_gc_lock); |
1467 | } | 1463 | } |
1468 | 1464 | ||
1469 | int __init fib6_init(void) | 1465 | static int fib6_net_init(struct net *net) |
1470 | { | 1466 | { |
1471 | int ret = -ENOMEM; | 1467 | int ret; |
1472 | fib6_node_kmem = kmem_cache_create("fib6_nodes", | ||
1473 | sizeof(struct fib6_node), | ||
1474 | 0, SLAB_HWCACHE_ALIGN, | ||
1475 | NULL); | ||
1476 | if (!fib6_node_kmem) | ||
1477 | goto out; | ||
1478 | 1468 | ||
1479 | fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ, | 1469 | ret = -ENOMEM; |
1480 | GFP_KERNEL); | 1470 | net->ipv6.fib_table_hash = |
1481 | if (!fib_table_hash) | 1471 | kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ, |
1482 | goto out_kmem_cache_create; | 1472 | GFP_KERNEL); |
1473 | if (!net->ipv6.fib_table_hash) | ||
1474 | goto out; | ||
1483 | 1475 | ||
1484 | fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL); | 1476 | net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), |
1485 | if (!fib6_main_tbl) | 1477 | GFP_KERNEL); |
1478 | if (!net->ipv6.fib6_main_tbl) | ||
1486 | goto out_fib_table_hash; | 1479 | goto out_fib_table_hash; |
1487 | 1480 | ||
1488 | fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; | 1481 | net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; |
1489 | fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; | 1482 | net->ipv6.fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; |
1490 | fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; | 1483 | net->ipv6.fib6_main_tbl->tb6_root.fn_flags = |
1484 | RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; | ||
1491 | 1485 | ||
1492 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 1486 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
1493 | fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL); | 1487 | net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl), |
1494 | if (!fib6_local_tbl) | 1488 | GFP_KERNEL); |
1489 | if (!net->ipv6.fib6_local_tbl) | ||
1495 | goto out_fib6_main_tbl; | 1490 | goto out_fib6_main_tbl; |
1496 | 1491 | net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; | |
1497 | fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; | 1492 | net->ipv6.fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; |
1498 | fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; | 1493 | net->ipv6.fib6_local_tbl->tb6_root.fn_flags = |
1499 | fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; | 1494 | RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; |
1500 | #endif | 1495 | #endif |
1496 | fib6_tables_init(net); | ||
1501 | 1497 | ||
1502 | fib6_tables_init(); | 1498 | ret = 0; |
1503 | |||
1504 | ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); | ||
1505 | if (ret) | ||
1506 | goto out_fib6_local_tbl; | ||
1507 | out: | 1499 | out: |
1508 | return ret; | 1500 | return ret; |
1509 | 1501 | ||
1510 | out_fib6_local_tbl: | ||
1511 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 1502 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
1512 | kfree(fib6_local_tbl); | ||
1513 | out_fib6_main_tbl: | 1503 | out_fib6_main_tbl: |
1504 | kfree(net->ipv6.fib6_main_tbl); | ||
1514 | #endif | 1505 | #endif |
1515 | kfree(fib6_main_tbl); | ||
1516 | out_fib_table_hash: | 1506 | out_fib_table_hash: |
1517 | kfree(fib_table_hash); | 1507 | kfree(net->ipv6.fib_table_hash); |
1508 | goto out; | ||
1509 | } | ||
1510 | |||
1511 | static void fib6_net_exit(struct net *net) | ||
1512 | { | ||
1513 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
1514 | kfree(net->ipv6.fib6_local_tbl); | ||
1515 | #endif | ||
1516 | kfree(net->ipv6.fib6_main_tbl); | ||
1517 | kfree(net->ipv6.fib_table_hash); | ||
1518 | } | ||
1519 | |||
1520 | static struct pernet_operations fib6_net_ops = { | ||
1521 | .init = fib6_net_init, | ||
1522 | .exit = fib6_net_exit, | ||
1523 | }; | ||
1524 | |||
1525 | int __init fib6_init(void) | ||
1526 | { | ||
1527 | int ret = -ENOMEM; | ||
1528 | fib6_node_kmem = kmem_cache_create("fib6_nodes", | ||
1529 | sizeof(struct fib6_node), | ||
1530 | 0, SLAB_HWCACHE_ALIGN, | ||
1531 | NULL); | ||
1532 | if (!fib6_node_kmem) | ||
1533 | goto out; | ||
1534 | |||
1535 | ret = register_pernet_subsys(&fib6_net_ops); | ||
1536 | if (ret) | ||
1537 | goto out_kmem_cache_create; | ||
1538 | |||
1539 | ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); | ||
1540 | if (ret) | ||
1541 | goto out_unregister_subsys; | ||
1542 | out: | ||
1543 | return ret; | ||
1544 | |||
1545 | out_unregister_subsys: | ||
1546 | unregister_pernet_subsys(&fib6_net_ops); | ||
1518 | out_kmem_cache_create: | 1547 | out_kmem_cache_create: |
1519 | kmem_cache_destroy(fib6_node_kmem); | 1548 | kmem_cache_destroy(fib6_node_kmem); |
1520 | goto out; | 1549 | goto out; |
@@ -1523,10 +1552,6 @@ out_kmem_cache_create: | |||
1523 | void fib6_gc_cleanup(void) | 1552 | void fib6_gc_cleanup(void) |
1524 | { | 1553 | { |
1525 | del_timer(&ip6_fib_timer); | 1554 | del_timer(&ip6_fib_timer); |
1526 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 1555 | unregister_pernet_subsys(&fib6_net_ops); |
1527 | kfree(fib6_local_tbl); | ||
1528 | #endif | ||
1529 | kfree(fib6_main_tbl); | ||
1530 | kfree(fib_table_hash); | ||
1531 | kmem_cache_destroy(fib6_node_kmem); | 1556 | kmem_cache_destroy(fib6_node_kmem); |
1532 | } | 1557 | } |