From c454673da7c1d6533f40ec2f788023df9af56ebf Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sun, 25 Mar 2007 23:24:24 -0700 Subject: [NET] rules: Unified rules dumping Implements a unified, protocol independant rules dumping function which is capable of both, dumping a specific protocol family or all of them. This speeds up dumping as less lookups are required. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/fib_rules.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'net/core/fib_rules.c') diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index bf45f24cfea..fdf05af16ba 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -393,19 +393,15 @@ nla_put_failure: return -EMSGSIZE; } -int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family) +static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, + struct fib_rules_ops *ops) { int idx = 0; struct fib_rule *rule; - struct fib_rules_ops *ops; - - ops = lookup_rules_ops(family); - if (ops == NULL) - return -EAFNOSUPPORT; rcu_read_lock(); list_for_each_entry_rcu(rule, ops->rules_list, list) { - if (idx < cb->args[0]) + if (idx < cb->args[1]) goto skip; if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid, @@ -416,13 +412,44 @@ skip: idx++; } rcu_read_unlock(); - cb->args[0] = idx; + cb->args[1] = idx; rules_ops_put(ops); return skb->len; } -EXPORT_SYMBOL_GPL(fib_rules_dump); +static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct fib_rules_ops *ops; + int idx = 0, family; + + family = rtnl_msg_family(cb->nlh); + if (family != AF_UNSPEC) { + /* Protocol specific dump request */ + ops = lookup_rules_ops(family); + if (ops == NULL) + return -EAFNOSUPPORT; + + return dump_rules(skb, cb, ops); + } + + rcu_read_lock(); + list_for_each_entry_rcu(ops, &rules_ops, list) { + if (idx < cb->args[0] || !try_module_get(ops->owner)) + goto skip; + + if (dump_rules(skb, cb, ops) < 0) + break; + + cb->args[1] = 0; + skip: + idx++; + } + rcu_read_unlock(); + cb->args[0] = idx; + + return skb->len; +} static void notify_rule_change(int event, struct fib_rule *rule, struct fib_rules_ops *ops, struct nlmsghdr *nlh, @@ -503,7 +530,7 @@ static int __init fib_rules_init(void) { 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, rtnl_dump_all); + rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule); return register_netdevice_notifier(&fib_rules_notifier); } -- cgit v1.2.3