Commit c454673d authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[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: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 687ad8cc
...@@ -98,7 +98,4 @@ extern int fib_rules_unregister(struct fib_rules_ops *); ...@@ -98,7 +98,4 @@ extern int fib_rules_unregister(struct fib_rules_ops *);
extern int fib_rules_lookup(struct fib_rules_ops *, extern int fib_rules_lookup(struct fib_rules_ops *,
struct flowi *, int flags, struct flowi *, int flags,
struct fib_lookup_arg *); struct fib_lookup_arg *);
extern int fib_rules_dump(struct sk_buff *,
struct netlink_callback *, int);
#endif #endif
...@@ -15,4 +15,12 @@ extern int rtnl_unregister(int protocol, int msgtype); ...@@ -15,4 +15,12 @@ extern int rtnl_unregister(int protocol, int msgtype);
extern void rtnl_unregister_all(int protocol); extern void rtnl_unregister_all(int protocol);
extern int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb); 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 #endif
...@@ -393,19 +393,15 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, ...@@ -393,19 +393,15 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
return -EMSGSIZE; 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; int idx = 0;
struct fib_rule *rule; struct fib_rule *rule;
struct fib_rules_ops *ops;
ops = lookup_rules_ops(family);
if (ops == NULL)
return -EAFNOSUPPORT;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(rule, ops->rules_list, list) { list_for_each_entry_rcu(rule, ops->rules_list, list) {
if (idx < cb->args[0]) if (idx < cb->args[1])
goto skip; goto skip;
if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid, if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid,
...@@ -416,13 +412,44 @@ int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family) ...@@ -416,13 +412,44 @@ int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
idx++; idx++;
} }
rcu_read_unlock(); rcu_read_unlock();
cb->args[0] = idx; cb->args[1] = idx;
rules_ops_put(ops); rules_ops_put(ops);
return skb->len; 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, static void notify_rule_change(int event, struct fib_rule *rule,
struct fib_rules_ops *ops, struct nlmsghdr *nlh, struct fib_rules_ops *ops, struct nlmsghdr *nlh,
...@@ -503,7 +530,7 @@ static int __init fib_rules_init(void) ...@@ -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_NEWRULE, fib_nl_newrule, NULL);
rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, 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); return register_netdevice_notifier(&fib_rules_notifier);
} }
......
...@@ -239,11 +239,6 @@ static u32 dn_fib_rule_default_pref(void) ...@@ -239,11 +239,6 @@ static u32 dn_fib_rule_default_pref(void)
return 0; 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 = { static struct fib_rules_ops dn_fib_rules_ops = {
.family = AF_DECnet, .family = AF_DECnet,
.rule_size = sizeof(struct dn_fib_rule), .rule_size = sizeof(struct dn_fib_rule),
...@@ -264,12 +259,10 @@ void __init dn_fib_rules_init(void) ...@@ -264,12 +259,10 @@ void __init dn_fib_rules_init(void)
{ {
list_add_tail(&default_rule.common.list, &dn_fib_rules); list_add_tail(&default_rule.common.list, &dn_fib_rules);
fib_rules_register(&dn_fib_rules_ops); 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) void __exit dn_fib_rules_cleanup(void)
{ {
rtnl_unregister(PF_DECnet, RTM_GETRULE);
fib_rules_unregister(&dn_fib_rules_ops); fib_rules_unregister(&dn_fib_rules_ops);
} }
......
...@@ -274,11 +274,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, ...@@ -274,11 +274,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
return -ENOBUFS; 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) static u32 fib4_rule_default_pref(void)
{ {
struct list_head *pos; struct list_head *pos;
...@@ -327,6 +322,4 @@ void __init fib4_rules_init(void) ...@@ -327,6 +322,4 @@ void __init fib4_rules_init(void)
list_add_tail(&default_rule.common.list, &fib4_rules); list_add_tail(&default_rule.common.list, &fib4_rules);
fib_rules_register(&fib4_rules_ops); fib_rules_register(&fib4_rules_ops);
rtnl_register(PF_INET, RTM_GETRULE, NULL, fib4_rule_dump);
} }
...@@ -216,11 +216,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, ...@@ -216,11 +216,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
return -ENOBUFS; 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) static u32 fib6_rule_default_pref(void)
{ {
return 0x3FFF; return 0x3FFF;
...@@ -255,11 +250,9 @@ void __init fib6_rules_init(void) ...@@ -255,11 +250,9 @@ void __init fib6_rules_init(void)
list_add_tail(&main_rule.common.list, &fib6_rules); list_add_tail(&main_rule.common.list, &fib6_rules);
fib_rules_register(&fib6_rules_ops); fib_rules_register(&fib6_rules_ops);
__rtnl_register(PF_INET6, RTM_GETRULE, NULL, fib6_rules_dump);
} }
void fib6_rules_cleanup(void) void fib6_rules_cleanup(void)
{ {
rtnl_unregister(PF_INET6, RTM_GETRULE);
fib_rules_unregister(&fib6_rules_ops); fib_rules_unregister(&fib6_rules_ops);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment