aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/fib_rules.c91
1 files changed, 54 insertions, 37 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index e12e9f583949..c5f78fed6885 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -15,9 +15,6 @@
15#include <net/sock.h> 15#include <net/sock.h>
16#include <net/fib_rules.h> 16#include <net/fib_rules.h>
17 17
18static LIST_HEAD(rules_ops);
19static DEFINE_SPINLOCK(rules_mod_lock);
20
21int fib_default_rule_add(struct fib_rules_ops *ops, 18int fib_default_rule_add(struct fib_rules_ops *ops,
22 u32 pref, u32 table, u32 flags) 19 u32 pref, u32 table, u32 flags)
23{ 20{
@@ -40,16 +37,17 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
40} 37}
41EXPORT_SYMBOL(fib_default_rule_add); 38EXPORT_SYMBOL(fib_default_rule_add);
42 39
43static void notify_rule_change(int event, struct fib_rule *rule, 40static void notify_rule_change(struct net *net, int event,
41 struct fib_rule *rule,
44 struct fib_rules_ops *ops, struct nlmsghdr *nlh, 42 struct fib_rules_ops *ops, struct nlmsghdr *nlh,
45 u32 pid); 43 u32 pid);
46 44
47static struct fib_rules_ops *lookup_rules_ops(int family) 45static struct fib_rules_ops *lookup_rules_ops(struct net *net, int family)
48{ 46{
49 struct fib_rules_ops *ops; 47 struct fib_rules_ops *ops;
50 48
51 rcu_read_lock(); 49 rcu_read_lock();
52 list_for_each_entry_rcu(ops, &rules_ops, list) { 50 list_for_each_entry_rcu(ops, &net->rules_ops, list) {
53 if (ops->family == family) { 51 if (ops->family == family) {
54 if (!try_module_get(ops->owner)) 52 if (!try_module_get(ops->owner))
55 ops = NULL; 53 ops = NULL;
@@ -87,15 +85,16 @@ int fib_rules_register(struct net *net, struct fib_rules_ops *ops)
87 ops->action == NULL) 85 ops->action == NULL)
88 return -EINVAL; 86 return -EINVAL;
89 87
90 spin_lock(&rules_mod_lock); 88 spin_lock(&net->rules_mod_lock);
91 list_for_each_entry(o, &rules_ops, list) 89 list_for_each_entry(o, &net->rules_ops, list)
92 if (ops->family == o->family) 90 if (ops->family == o->family)
93 goto errout; 91 goto errout;
94 92
95 list_add_tail_rcu(&ops->list, &rules_ops); 93 hold_net(net);
94 list_add_tail_rcu(&ops->list, &net->rules_ops);
96 err = 0; 95 err = 0;
97errout: 96errout:
98 spin_unlock(&rules_mod_lock); 97 spin_unlock(&net->rules_mod_lock);
99 98
100 return err; 99 return err;
101} 100}
@@ -118,8 +117,8 @@ int fib_rules_unregister(struct net *net, struct fib_rules_ops *ops)
118 int err = 0; 117 int err = 0;
119 struct fib_rules_ops *o; 118 struct fib_rules_ops *o;
120 119
121 spin_lock(&rules_mod_lock); 120 spin_lock(&net->rules_mod_lock);
122 list_for_each_entry(o, &rules_ops, list) { 121 list_for_each_entry(o, &net->rules_ops, list) {
123 if (o == ops) { 122 if (o == ops) {
124 list_del_rcu(&o->list); 123 list_del_rcu(&o->list);
125 fib_rules_cleanup_ops(ops); 124 fib_rules_cleanup_ops(ops);
@@ -129,9 +128,11 @@ int fib_rules_unregister(struct net *net, struct fib_rules_ops *ops)
129 128
130 err = -ENOENT; 129 err = -ENOENT;
131out: 130out:
132 spin_unlock(&rules_mod_lock); 131 spin_unlock(&net->rules_mod_lock);
133 132
134 synchronize_rcu(); 133 synchronize_rcu();
134 if (!err)
135 release_net(net);
135 136
136 return err; 137 return err;
137} 138}
@@ -229,13 +230,10 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
229 struct nlattr *tb[FRA_MAX+1]; 230 struct nlattr *tb[FRA_MAX+1];
230 int err = -EINVAL, unresolved = 0; 231 int err = -EINVAL, unresolved = 0;
231 232
232 if (net != &init_net)
233 return -EINVAL;
234
235 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) 233 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
236 goto errout; 234 goto errout;
237 235
238 ops = lookup_rules_ops(frh->family); 236 ops = lookup_rules_ops(net, frh->family);
239 if (ops == NULL) { 237 if (ops == NULL) {
240 err = EAFNOSUPPORT; 238 err = EAFNOSUPPORT;
241 goto errout; 239 goto errout;
@@ -348,7 +346,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
348 else 346 else
349 list_add_rcu(&rule->list, &ops->rules_list); 347 list_add_rcu(&rule->list, &ops->rules_list);
350 348
351 notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid); 349 notify_rule_change(net, RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
352 flush_route_cache(ops); 350 flush_route_cache(ops);
353 rules_ops_put(ops); 351 rules_ops_put(ops);
354 return 0; 352 return 0;
@@ -369,13 +367,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
369 struct nlattr *tb[FRA_MAX+1]; 367 struct nlattr *tb[FRA_MAX+1];
370 int err = -EINVAL; 368 int err = -EINVAL;
371 369
372 if (net != &init_net)
373 return -EINVAL;
374
375 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) 370 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
376 goto errout; 371 goto errout;
377 372
378 ops = lookup_rules_ops(frh->family); 373 ops = lookup_rules_ops(net, frh->family);
379 if (ops == NULL) { 374 if (ops == NULL) {
380 err = EAFNOSUPPORT; 375 err = EAFNOSUPPORT;
381 goto errout; 376 goto errout;
@@ -441,7 +436,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
441 } 436 }
442 437
443 synchronize_rcu(); 438 synchronize_rcu();
444 notify_rule_change(RTM_DELRULE, rule, ops, nlh, 439 notify_rule_change(net, RTM_DELRULE, rule, ops, nlh,
445 NETLINK_CB(skb).pid); 440 NETLINK_CB(skb).pid);
446 fib_rule_put(rule); 441 fib_rule_put(rule);
447 flush_route_cache(ops); 442 flush_route_cache(ops);
@@ -551,13 +546,10 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
551 struct fib_rules_ops *ops; 546 struct fib_rules_ops *ops;
552 int idx = 0, family; 547 int idx = 0, family;
553 548
554 if (net != &init_net)
555 return -EINVAL;
556
557 family = rtnl_msg_family(cb->nlh); 549 family = rtnl_msg_family(cb->nlh);
558 if (family != AF_UNSPEC) { 550 if (family != AF_UNSPEC) {
559 /* Protocol specific dump request */ 551 /* Protocol specific dump request */
560 ops = lookup_rules_ops(family); 552 ops = lookup_rules_ops(net, family);
561 if (ops == NULL) 553 if (ops == NULL)
562 return -EAFNOSUPPORT; 554 return -EAFNOSUPPORT;
563 555
@@ -565,7 +557,7 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
565 } 557 }
566 558
567 rcu_read_lock(); 559 rcu_read_lock();
568 list_for_each_entry_rcu(ops, &rules_ops, list) { 560 list_for_each_entry_rcu(ops, &net->rules_ops, list) {
569 if (idx < cb->args[0] || !try_module_get(ops->owner)) 561 if (idx < cb->args[0] || !try_module_get(ops->owner))
570 goto skip; 562 goto skip;
571 563
@@ -582,7 +574,7 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
582 return skb->len; 574 return skb->len;
583} 575}
584 576
585static void notify_rule_change(int event, struct fib_rule *rule, 577static void notify_rule_change(struct net *net, int event, struct fib_rule *rule,
586 struct fib_rules_ops *ops, struct nlmsghdr *nlh, 578 struct fib_rules_ops *ops, struct nlmsghdr *nlh,
587 u32 pid) 579 u32 pid)
588{ 580{
@@ -600,10 +592,10 @@ static void notify_rule_change(int event, struct fib_rule *rule,
600 kfree_skb(skb); 592 kfree_skb(skb);
601 goto errout; 593 goto errout;
602 } 594 }
603 err = rtnl_notify(skb, &init_net, pid, ops->nlgroup, nlh, GFP_KERNEL); 595 err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
604errout: 596errout:
605 if (err < 0) 597 if (err < 0)
606 rtnl_set_sk_err(&init_net, ops->nlgroup, err); 598 rtnl_set_sk_err(net, ops->nlgroup, err);
607} 599}
608 600
609static void attach_rules(struct list_head *rules, struct net_device *dev) 601static void attach_rules(struct list_head *rules, struct net_device *dev)
@@ -631,22 +623,20 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
631 void *ptr) 623 void *ptr)
632{ 624{
633 struct net_device *dev = ptr; 625 struct net_device *dev = ptr;
626 struct net *net = dev->nd_net;
634 struct fib_rules_ops *ops; 627 struct fib_rules_ops *ops;
635 628
636 if (dev->nd_net != &init_net)
637 return NOTIFY_DONE;
638
639 ASSERT_RTNL(); 629 ASSERT_RTNL();
640 rcu_read_lock(); 630 rcu_read_lock();
641 631
642 switch (event) { 632 switch (event) {
643 case NETDEV_REGISTER: 633 case NETDEV_REGISTER:
644 list_for_each_entry(ops, &rules_ops, list) 634 list_for_each_entry(ops, &net->rules_ops, list)
645 attach_rules(&ops->rules_list, dev); 635 attach_rules(&ops->rules_list, dev);
646 break; 636 break;
647 637
648 case NETDEV_UNREGISTER: 638 case NETDEV_UNREGISTER:
649 list_for_each_entry(ops, &rules_ops, list) 639 list_for_each_entry(ops, &net->rules_ops, list)
650 detach_rules(&ops->rules_list, dev); 640 detach_rules(&ops->rules_list, dev);
651 break; 641 break;
652 } 642 }
@@ -660,13 +650,40 @@ static struct notifier_block fib_rules_notifier = {
660 .notifier_call = fib_rules_event, 650 .notifier_call = fib_rules_event,
661}; 651};
662 652
653static int fib_rules_net_init(struct net *net)
654{
655 INIT_LIST_HEAD(&net->rules_ops);
656 spin_lock_init(&net->rules_mod_lock);
657 return 0;
658}
659
660static struct pernet_operations fib_rules_net_ops = {
661 .init = fib_rules_net_init,
662};
663
663static int __init fib_rules_init(void) 664static int __init fib_rules_init(void)
664{ 665{
666 int err;
665 rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL); 667 rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
666 rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL); 668 rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
667 rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule); 669 rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);
668 670
669 return register_netdevice_notifier(&fib_rules_notifier); 671 err = register_netdevice_notifier(&fib_rules_notifier);
672 if (err < 0)
673 goto fail;
674
675 err = register_pernet_subsys(&fib_rules_net_ops);
676 if (err < 0)
677 goto fail_unregister;
678 return 0;
679
680fail_unregister:
681 unregister_netdevice_notifier(&fib_rules_notifier);
682fail:
683 rtnl_unregister(PF_UNSPEC, RTM_NEWRULE);
684 rtnl_unregister(PF_UNSPEC, RTM_DELRULE);
685 rtnl_unregister(PF_UNSPEC, RTM_GETRULE);
686 return err;
670} 687}
671 688
672subsys_initcall(fib_rules_init); 689subsys_initcall(fib_rules_init);