Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 78734
b: refs/heads/master
c: 5fd30ee
h: refs/heads/master
v: v3
  • Loading branch information
Denis V. Lunev authored and David S. Miller committed Jan 28, 2008
1 parent 372ff28 commit 47a05a7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 38 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 868d13ac811746e28e4c806f2b1bd8575796f9af
refs/heads/master: 5fd30ee7c48bf7f9cd16ab44c8a09fa4a57cc21d
4 changes: 4 additions & 0 deletions trunk/include/net/net_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ struct net {
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;

/* core fib_rules */
struct list_head rules_ops;
spinlock_t rules_mod_lock;

struct sock *rtnl; /* rtnetlink socket */

/* core sysctls */
Expand Down
91 changes: 54 additions & 37 deletions trunk/net/core/fib_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
#include <net/sock.h>
#include <net/fib_rules.h>

static LIST_HEAD(rules_ops);
static DEFINE_SPINLOCK(rules_mod_lock);

int fib_default_rule_add(struct fib_rules_ops *ops,
u32 pref, u32 table, u32 flags)
{
Expand All @@ -40,16 +37,17 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
}
EXPORT_SYMBOL(fib_default_rule_add);

static void notify_rule_change(int event, struct fib_rule *rule,
static void notify_rule_change(struct net *net, int event,
struct fib_rule *rule,
struct fib_rules_ops *ops, struct nlmsghdr *nlh,
u32 pid);

static struct fib_rules_ops *lookup_rules_ops(int family)
static struct fib_rules_ops *lookup_rules_ops(struct net *net, int family)
{
struct fib_rules_ops *ops;

rcu_read_lock();
list_for_each_entry_rcu(ops, &rules_ops, list) {
list_for_each_entry_rcu(ops, &net->rules_ops, list) {
if (ops->family == family) {
if (!try_module_get(ops->owner))
ops = NULL;
Expand Down Expand Up @@ -87,15 +85,16 @@ int fib_rules_register(struct net *net, struct fib_rules_ops *ops)
ops->action == NULL)
return -EINVAL;

spin_lock(&rules_mod_lock);
list_for_each_entry(o, &rules_ops, list)
spin_lock(&net->rules_mod_lock);
list_for_each_entry(o, &net->rules_ops, list)
if (ops->family == o->family)
goto errout;

list_add_tail_rcu(&ops->list, &rules_ops);
hold_net(net);
list_add_tail_rcu(&ops->list, &net->rules_ops);
err = 0;
errout:
spin_unlock(&rules_mod_lock);
spin_unlock(&net->rules_mod_lock);

return err;
}
Expand All @@ -118,8 +117,8 @@ int fib_rules_unregister(struct net *net, struct fib_rules_ops *ops)
int err = 0;
struct fib_rules_ops *o;

spin_lock(&rules_mod_lock);
list_for_each_entry(o, &rules_ops, list) {
spin_lock(&net->rules_mod_lock);
list_for_each_entry(o, &net->rules_ops, list) {
if (o == ops) {
list_del_rcu(&o->list);
fib_rules_cleanup_ops(ops);
Expand All @@ -129,9 +128,11 @@ int fib_rules_unregister(struct net *net, struct fib_rules_ops *ops)

err = -ENOENT;
out:
spin_unlock(&rules_mod_lock);
spin_unlock(&net->rules_mod_lock);

synchronize_rcu();
if (!err)
release_net(net);

return err;
}
Expand Down Expand Up @@ -229,13 +230,10 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
struct nlattr *tb[FRA_MAX+1];
int err = -EINVAL, unresolved = 0;

if (net != &init_net)
return -EINVAL;

if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
goto errout;

ops = lookup_rules_ops(frh->family);
ops = lookup_rules_ops(net, frh->family);
if (ops == NULL) {
err = EAFNOSUPPORT;
goto errout;
Expand Down Expand Up @@ -348,7 +346,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
else
list_add_rcu(&rule->list, &ops->rules_list);

notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
notify_rule_change(net, RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid);
flush_route_cache(ops);
rules_ops_put(ops);
return 0;
Expand All @@ -369,13 +367,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
struct nlattr *tb[FRA_MAX+1];
int err = -EINVAL;

if (net != &init_net)
return -EINVAL;

if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
goto errout;

ops = lookup_rules_ops(frh->family);
ops = lookup_rules_ops(net, frh->family);
if (ops == NULL) {
err = EAFNOSUPPORT;
goto errout;
Expand Down Expand Up @@ -441,7 +436,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
}

synchronize_rcu();
notify_rule_change(RTM_DELRULE, rule, ops, nlh,
notify_rule_change(net, RTM_DELRULE, rule, ops, nlh,
NETLINK_CB(skb).pid);
fib_rule_put(rule);
flush_route_cache(ops);
Expand Down Expand Up @@ -551,21 +546,18 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
struct fib_rules_ops *ops;
int idx = 0, family;

if (net != &init_net)
return -EINVAL;

family = rtnl_msg_family(cb->nlh);
if (family != AF_UNSPEC) {
/* Protocol specific dump request */
ops = lookup_rules_ops(family);
ops = lookup_rules_ops(net, family);
if (ops == NULL)
return -EAFNOSUPPORT;

return dump_rules(skb, cb, ops);
}

rcu_read_lock();
list_for_each_entry_rcu(ops, &rules_ops, list) {
list_for_each_entry_rcu(ops, &net->rules_ops, list) {
if (idx < cb->args[0] || !try_module_get(ops->owner))
goto skip;

Expand All @@ -582,7 +574,7 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}

static void notify_rule_change(int event, struct fib_rule *rule,
static void notify_rule_change(struct net *net, int event, struct fib_rule *rule,
struct fib_rules_ops *ops, struct nlmsghdr *nlh,
u32 pid)
{
Expand All @@ -600,10 +592,10 @@ static void notify_rule_change(int event, struct fib_rule *rule,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, pid, ops->nlgroup, nlh, GFP_KERNEL);
err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, ops->nlgroup, err);
rtnl_set_sk_err(net, ops->nlgroup, err);
}

static void attach_rules(struct list_head *rules, struct net_device *dev)
Expand Down Expand Up @@ -631,22 +623,20 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *dev = ptr;
struct net *net = dev->nd_net;
struct fib_rules_ops *ops;

if (dev->nd_net != &init_net)
return NOTIFY_DONE;

ASSERT_RTNL();
rcu_read_lock();

switch (event) {
case NETDEV_REGISTER:
list_for_each_entry(ops, &rules_ops, list)
list_for_each_entry(ops, &net->rules_ops, list)
attach_rules(&ops->rules_list, dev);
break;

case NETDEV_UNREGISTER:
list_for_each_entry(ops, &rules_ops, list)
list_for_each_entry(ops, &net->rules_ops, list)
detach_rules(&ops->rules_list, dev);
break;
}
Expand All @@ -660,13 +650,40 @@ static struct notifier_block fib_rules_notifier = {
.notifier_call = fib_rules_event,
};

static int fib_rules_net_init(struct net *net)
{
INIT_LIST_HEAD(&net->rules_ops);
spin_lock_init(&net->rules_mod_lock);
return 0;
}

static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
};

static int __init fib_rules_init(void)
{
int err;
rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);

return register_netdevice_notifier(&fib_rules_notifier);
err = register_netdevice_notifier(&fib_rules_notifier);
if (err < 0)
goto fail;

err = register_pernet_subsys(&fib_rules_net_ops);
if (err < 0)
goto fail_unregister;
return 0;

fail_unregister:
unregister_netdevice_notifier(&fib_rules_notifier);
fail:
rtnl_unregister(PF_UNSPEC, RTM_NEWRULE);
rtnl_unregister(PF_UNSPEC, RTM_DELRULE);
rtnl_unregister(PF_UNSPEC, RTM_GETRULE);
return err;
}

subsys_initcall(fib_rules_init);

0 comments on commit 47a05a7

Please sign in to comment.