]> err.no Git - linux-2.6/commitdiff
[NET] rules: Unified rules dumping
authorThomas Graf <tgraf@suug.ch>
Mon, 26 Mar 2007 06:24:24 +0000 (23:24 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 26 Apr 2007 05:27:17 +0000 (22:27 -0700)
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 <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/fib_rules.h
include/net/rtnetlink.h
net/core/fib_rules.c
net/decnet/dn_rules.c
net/ipv4/fib_rules.c
net/ipv6/fib6_rules.c

index b2b9ccdf32d649bee0d7a76763c0cdca480d74e7..ff3029fe96561b7acd63878729611f3cc5ac4c7a 100644 (file)
@@ -98,7 +98,4 @@ extern int                    fib_rules_unregister(struct fib_rules_ops *);
 extern int                     fib_rules_lookup(struct fib_rules_ops *,
                                                 struct flowi *, int flags,
                                                 struct fib_lookup_arg *);
-
-extern int                     fib_rules_dump(struct sk_buff *,
-                                              struct netlink_callback *, int);
 #endif
index dce7072bd28cfd830cab114ba147ba9592497605..086fa9e89509896423dca8b812c9ff22a72b29c6 100644 (file)
@@ -15,4 +15,12 @@ extern int   rtnl_unregister(int protocol, int msgtype);
 extern void    rtnl_unregister_all(int protocol);
 extern int     rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb);
 
+static inline int rtnl_msg_family(struct nlmsghdr *nlh)
+{
+       if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg))
+               return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family;
+       else
+               return AF_UNSPEC;
+}
+
 #endif
index bf45f24cfea2c4f3c20a8b28114e1c7bf3df523a..fdf05af16ba50bd71a7cd03b0963692797799913 100644 (file)
@@ -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);
 }
index a7a7da9b35c393bd43bd3c367e6de1f480e4a8e0..fd0cc2aa316c6018adb007519b7cdc5732f7e61f 100644 (file)
@@ -239,11 +239,6 @@ static u32 dn_fib_rule_default_pref(void)
        return 0;
 }
 
-static int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       return fib_rules_dump(skb, cb, AF_DECnet);
-}
-
 static struct fib_rules_ops dn_fib_rules_ops = {
        .family         = AF_DECnet,
        .rule_size      = sizeof(struct dn_fib_rule),
@@ -264,12 +259,10 @@ void __init dn_fib_rules_init(void)
 {
        list_add_tail(&default_rule.common.list, &dn_fib_rules);
        fib_rules_register(&dn_fib_rules_ops);
-       rtnl_register(PF_DECnet, RTM_GETRULE, NULL, dn_fib_dump_rules);
 }
 
 void __exit dn_fib_rules_cleanup(void)
 {
-       rtnl_unregister(PF_DECnet, RTM_GETRULE);
        fib_rules_unregister(&dn_fib_rules_ops);
 }
 
index a7f931ddfaad41dd408e9a83bd00a1c6c96c3326..b021b3440ca3f2fc7a6a084a1e40213d018fb4aa 100644 (file)
@@ -274,11 +274,6 @@ nla_put_failure:
        return -ENOBUFS;
 }
 
-static int fib4_rule_dump(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       return fib_rules_dump(skb, cb, AF_INET);
-}
-
 static u32 fib4_rule_default_pref(void)
 {
        struct list_head *pos;
@@ -327,6 +322,4 @@ void __init fib4_rules_init(void)
        list_add_tail(&default_rule.common.list, &fib4_rules);
 
        fib_rules_register(&fib4_rules_ops);
-
-       rtnl_register(PF_INET, RTM_GETRULE, NULL, fib4_rule_dump);
 }
index c74da4b6dd2fa79f23938354b41ace175606edeb..dd9720e700ef299b4cff1db241953f0443222939 100644 (file)
@@ -216,11 +216,6 @@ nla_put_failure:
        return -ENOBUFS;
 }
 
-static int fib6_rules_dump(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       return fib_rules_dump(skb, cb, AF_INET6);
-}
-
 static u32 fib6_rule_default_pref(void)
 {
        return 0x3FFF;
@@ -255,11 +250,9 @@ void __init fib6_rules_init(void)
        list_add_tail(&main_rule.common.list, &fib6_rules);
 
        fib_rules_register(&fib6_rules_ops);
-       __rtnl_register(PF_INET6, RTM_GETRULE, NULL, fib6_rules_dump);
 }
 
 void fib6_rules_cleanup(void)
 {
-       rtnl_unregister(PF_INET6, RTM_GETRULE);
        fib_rules_unregister(&fib6_rules_ops);
 }