aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/fib6_rules.c8
-rw-r--r--net/ipv6/ip6_fib.c161
-rw-r--r--net/ipv6/route.c22
3 files changed, 109 insertions, 82 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 157db3a1ce00..03ad23a5fd3c 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -31,8 +31,8 @@ struct fib6_rule
31 31
32static struct fib_rules_ops fib6_rules_ops; 32static struct fib_rules_ops fib6_rules_ops;
33 33
34struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, 34struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
35 pol_lookup_t lookup) 35 int flags, pol_lookup_t lookup)
36{ 36{
37 struct fib_lookup_arg arg = { 37 struct fib_lookup_arg arg = {
38 .lookup_ptr = lookup, 38 .lookup_ptr = lookup,
@@ -71,7 +71,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
71 goto discard_pkt; 71 goto discard_pkt;
72 } 72 }
73 73
74 table = fib6_get_table(rule->table); 74 table = fib6_get_table(&init_net, rule->table);
75 if (table) 75 if (table)
76 rt = lookup(table, flp, flags); 76 rt = lookup(table, flp, flags);
77 77
@@ -151,7 +151,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
151 if (rule->table == RT6_TABLE_UNSPEC) 151 if (rule->table == RT6_TABLE_UNSPEC)
152 goto errout; 152 goto errout;
153 153
154 if (fib6_new_table(rule->table) == NULL) { 154 if (fib6_new_table(&init_net, rule->table) == NULL) {
155 err = -ENOBUFS; 155 err = -ENOBUFS;
156 goto errout; 156 goto errout;
157 } 157 }
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
169static 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
176static struct hlist_head *fib_table_hash;
177 174
178static void fib6_link_table(struct fib6_table *tb) 175static 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
199static struct fib6_table *fib6_local_tbl;
200
201static struct fib6_table *fib6_alloc_table(u32 id) 196static 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
215struct fib6_table *fib6_new_table(u32 id) 210struct 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
232struct fib6_table *fib6_get_table(u32 id) 227struct 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
253static void __init fib6_tables_init(void) 250static 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
261struct fib6_table *fib6_new_table(u32 id) 257struct 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
266struct fib6_table *fib6_get_table(u32 id) 262struct 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
271struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, 267struct 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
277static void __init fib6_tables_init(void) 273static 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
1469int __init fib6_init(void) 1465static 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;
1507out: 1499out:
1508 return ret; 1500 return ret;
1509 1501
1510out_fib6_local_tbl:
1511#ifdef CONFIG_IPV6_MULTIPLE_TABLES 1502#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1512 kfree(fib6_local_tbl);
1513out_fib6_main_tbl: 1503out_fib6_main_tbl:
1504 kfree(net->ipv6.fib6_main_tbl);
1514#endif 1505#endif
1515 kfree(fib6_main_tbl);
1516out_fib_table_hash: 1506out_fib_table_hash:
1517 kfree(fib_table_hash); 1507 kfree(net->ipv6.fib_table_hash);
1508 goto out;
1509 }
1510
1511static 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
1520static struct pernet_operations fib6_net_ops = {
1521 .init = fib6_net_init,
1522 .exit = fib6_net_exit,
1523};
1524
1525int __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;
1542out:
1543 return ret;
1544
1545out_unregister_subsys:
1546 unregister_pernet_subsys(&fib6_net_ops);
1518out_kmem_cache_create: 1547out_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:
1523void fib6_gc_cleanup(void) 1552void 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}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index cd717450fb10..09206f7ba525 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -571,7 +571,7 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
571 flags |= RT6_LOOKUP_F_HAS_SADDR; 571 flags |= RT6_LOOKUP_F_HAS_SADDR;
572 } 572 }
573 573
574 dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); 574 dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_lookup);
575 if (dst->error == 0) 575 if (dst->error == 0)
576 return (struct rt6_info *) dst; 576 return (struct rt6_info *) dst;
577 577
@@ -758,7 +758,7 @@ void ip6_route_input(struct sk_buff *skb)
758 if (rt6_need_strict(&iph->daddr)) 758 if (rt6_need_strict(&iph->daddr))
759 flags |= RT6_LOOKUP_F_IFACE; 759 flags |= RT6_LOOKUP_F_IFACE;
760 760
761 skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); 761 skb->dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_input);
762} 762}
763 763
764static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, 764static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
@@ -777,7 +777,7 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
777 if (!ipv6_addr_any(&fl->fl6_src)) 777 if (!ipv6_addr_any(&fl->fl6_src))
778 flags |= RT6_LOOKUP_F_HAS_SADDR; 778 flags |= RT6_LOOKUP_F_HAS_SADDR;
779 779
780 return fib6_rule_lookup(fl, flags, ip6_pol_route_output); 780 return fib6_rule_lookup(&init_net, fl, flags, ip6_pol_route_output);
781} 781}
782 782
783EXPORT_SYMBOL(ip6_route_output); 783EXPORT_SYMBOL(ip6_route_output);
@@ -1069,7 +1069,7 @@ int ip6_route_add(struct fib6_config *cfg)
1069 if (cfg->fc_metric == 0) 1069 if (cfg->fc_metric == 0)
1070 cfg->fc_metric = IP6_RT_PRIO_USER; 1070 cfg->fc_metric = IP6_RT_PRIO_USER;
1071 1071
1072 table = fib6_new_table(cfg->fc_table); 1072 table = fib6_new_table(&init_net, cfg->fc_table);
1073 if (table == NULL) { 1073 if (table == NULL) {
1074 err = -ENOBUFS; 1074 err = -ENOBUFS;
1075 goto out; 1075 goto out;
@@ -1275,7 +1275,7 @@ static int ip6_route_del(struct fib6_config *cfg)
1275 struct rt6_info *rt; 1275 struct rt6_info *rt;
1276 int err = -ESRCH; 1276 int err = -ESRCH;
1277 1277
1278 table = fib6_get_table(cfg->fc_table); 1278 table = fib6_get_table(&init_net, cfg->fc_table);
1279 if (table == NULL) 1279 if (table == NULL)
1280 return err; 1280 return err;
1281 1281
@@ -1390,7 +1390,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
1390 if (rt6_need_strict(dest)) 1390 if (rt6_need_strict(dest))
1391 flags |= RT6_LOOKUP_F_IFACE; 1391 flags |= RT6_LOOKUP_F_IFACE;
1392 1392
1393 return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); 1393 return (struct rt6_info *)fib6_rule_lookup(&init_net,
1394 (struct flowi *)&rdfl,
1395 flags, __ip6_route_redirect);
1394} 1396}
1395 1397
1396void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, 1398void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
@@ -1589,7 +1591,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle
1589 struct rt6_info *rt = NULL; 1591 struct rt6_info *rt = NULL;
1590 struct fib6_table *table; 1592 struct fib6_table *table;
1591 1593
1592 table = fib6_get_table(RT6_TABLE_INFO); 1594 table = fib6_get_table(&init_net, RT6_TABLE_INFO);
1593 if (table == NULL) 1595 if (table == NULL)
1594 return NULL; 1596 return NULL;
1595 1597
@@ -1644,7 +1646,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
1644 struct rt6_info *rt; 1646 struct rt6_info *rt;
1645 struct fib6_table *table; 1647 struct fib6_table *table;
1646 1648
1647 table = fib6_get_table(RT6_TABLE_DFLT); 1649 table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
1648 if (table == NULL) 1650 if (table == NULL)
1649 return NULL; 1651 return NULL;
1650 1652
@@ -1688,7 +1690,7 @@ void rt6_purge_dflt_routers(void)
1688 struct fib6_table *table; 1690 struct fib6_table *table;
1689 1691
1690 /* NOTE: Keep consistent with rt6_get_dflt_router */ 1692 /* NOTE: Keep consistent with rt6_get_dflt_router */
1691 table = fib6_get_table(RT6_TABLE_DFLT); 1693 table = fib6_get_table(&init_net, RT6_TABLE_DFLT);
1692 if (table == NULL) 1694 if (table == NULL)
1693 return; 1695 return;
1694 1696
@@ -1851,7 +1853,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1851 1853
1852 ipv6_addr_copy(&rt->rt6i_dst.addr, addr); 1854 ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
1853 rt->rt6i_dst.plen = 128; 1855 rt->rt6i_dst.plen = 128;
1854 rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL); 1856 rt->rt6i_table = fib6_get_table(&init_net, RT6_TABLE_LOCAL);
1855 1857
1856 atomic_set(&rt->u.dst.__refcnt, 1); 1858 atomic_set(&rt->u.dst.__refcnt, 1);
1857 1859