aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/fib_rules.h3
-rw-r--r--include/net/rtnetlink.h8
-rw-r--r--net/core/fib_rules.c47
-rw-r--r--net/decnet/dn_rules.c7
-rw-r--r--net/ipv4/fib_rules.c7
-rw-r--r--net/ipv6/fib6_rules.c7
6 files changed, 45 insertions, 34 deletions
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index b2b9ccdf32d..ff3029fe965 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -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
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index dce7072bd28..086fa9e8950 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -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
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);
}
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index a7a7da9b35c..fd0cc2aa316 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -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);
}
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index a7f931ddfaa..b021b3440ca 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -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);
}
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index c74da4b6dd2..dd9720e700e 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -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);
}