Commit f93eb4ba authored by David S. Miller's avatar David S. Miller

Merge branch 'fib_trie-next'

Alexander Duyck says:

====================
ipv4/fib_trie: Cleanups to prepare for introduction of key vector

This patch series is meant to mostly just clean up the fib_trie to prepare
it for the introduction of the key_vector.  As such there are a number of
minor clean-ups such as reformatting the tnode to match the format once the
key vector is introduced, some optimizations to drop the need for a leaf
parent pointer, and some changes to remove duplication of effort such as
the 2 look-ups that were essentially being done per node insertion.

v2: Added code to cleanup idx >> n->bits and explain unsigned long logic
    Added code to prevent allocation when tnode size is larger than size_t
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3a65f63f 1de3d87b
...@@ -185,6 +185,7 @@ struct fib_table { ...@@ -185,6 +185,7 @@ struct fib_table {
u32 tb_id; u32 tb_id;
int tb_default; int tb_default;
int tb_num_default; int tb_num_default;
struct rcu_head rcu;
unsigned long tb_data[0]; unsigned long tb_data[0];
}; };
...@@ -206,12 +207,16 @@ void fib_free_table(struct fib_table *tb); ...@@ -206,12 +207,16 @@ void fib_free_table(struct fib_table *tb);
static inline struct fib_table *fib_get_table(struct net *net, u32 id) static inline struct fib_table *fib_get_table(struct net *net, u32 id)
{ {
struct hlist_node *tb_hlist;
struct hlist_head *ptr; struct hlist_head *ptr;
ptr = id == RT_TABLE_LOCAL ? ptr = id == RT_TABLE_LOCAL ?
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] : &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]; &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
return hlist_entry(ptr->first, struct fib_table, tb_hlist);
tb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr));
return hlist_entry(tb_hlist, struct fib_table, tb_hlist);
} }
static inline struct fib_table *fib_new_table(struct net *net, u32 id) static inline struct fib_table *fib_new_table(struct net *net, u32 id)
...@@ -222,15 +227,19 @@ static inline struct fib_table *fib_new_table(struct net *net, u32 id) ...@@ -222,15 +227,19 @@ static inline struct fib_table *fib_new_table(struct net *net, u32 id)
static inline int fib_lookup(struct net *net, const struct flowi4 *flp, static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
struct fib_result *res) struct fib_result *res)
{ {
int err = -ENETUNREACH; struct fib_table *tb;
int err;
rcu_read_lock(); rcu_read_lock();
if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res, for (err = 0; !err; err = -ENETUNREACH) {
FIB_LOOKUP_NOREF) || tb = fib_get_table(net, RT_TABLE_LOCAL);
!fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res, if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
FIB_LOOKUP_NOREF)) break;
err = 0; tb = fib_get_table(net, RT_TABLE_MAIN);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;
}
rcu_read_unlock(); rcu_read_unlock();
...@@ -249,28 +258,33 @@ int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res); ...@@ -249,28 +258,33 @@ int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res);
static inline int fib_lookup(struct net *net, struct flowi4 *flp, static inline int fib_lookup(struct net *net, struct flowi4 *flp,
struct fib_result *res) struct fib_result *res)
{ {
if (!net->ipv4.fib_has_custom_rules) { struct fib_table *tb;
int err = -ENETUNREACH; int err;
rcu_read_lock(); if (net->ipv4.fib_has_custom_rules)
return __fib_lookup(net, flp, res);
res->tclassid = 0;
if ((net->ipv4.fib_local && rcu_read_lock();
!fib_table_lookup(net->ipv4.fib_local, flp, res,
FIB_LOOKUP_NOREF)) || res->tclassid = 0;
(net->ipv4.fib_main &&
!fib_table_lookup(net->ipv4.fib_main, flp, res, for (err = 0; !err; err = -ENETUNREACH) {
FIB_LOOKUP_NOREF)) || tb = rcu_dereference_rtnl(net->ipv4.fib_local);
(net->ipv4.fib_default && if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
!fib_table_lookup(net->ipv4.fib_default, flp, res, break;
FIB_LOOKUP_NOREF)))
err = 0; tb = rcu_dereference_rtnl(net->ipv4.fib_main);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
rcu_read_unlock(); break;
return err; tb = rcu_dereference_rtnl(net->ipv4.fib_default);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;
} }
return __fib_lookup(net, flp, res);
rcu_read_unlock();
return err;
} }
#endif /* CONFIG_IP_MULTIPLE_TABLES */ #endif /* CONFIG_IP_MULTIPLE_TABLES */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/uidgid.h> #include <linux/uidgid.h>
#include <net/inet_frag.h> #include <net/inet_frag.h>
#include <linux/rcupdate.h>
struct tcpm_hash_bucket; struct tcpm_hash_bucket;
struct ctl_table_header; struct ctl_table_header;
...@@ -38,9 +39,9 @@ struct netns_ipv4 { ...@@ -38,9 +39,9 @@ struct netns_ipv4 {
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_rules_ops *rules_ops; struct fib_rules_ops *rules_ops;
bool fib_has_custom_rules; bool fib_has_custom_rules;
struct fib_table *fib_local; struct fib_table __rcu *fib_local;
struct fib_table *fib_main; struct fib_table __rcu *fib_main;
struct fib_table *fib_default; struct fib_table __rcu *fib_default;
#endif #endif
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
int fib_num_tclassid_users; int fib_num_tclassid_users;
......
...@@ -89,17 +89,14 @@ struct fib_table *fib_new_table(struct net *net, u32 id) ...@@ -89,17 +89,14 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
switch (id) { switch (id) {
case RT_TABLE_LOCAL: case RT_TABLE_LOCAL:
net->ipv4.fib_local = tb; rcu_assign_pointer(net->ipv4.fib_local, tb);
break; break;
case RT_TABLE_MAIN: case RT_TABLE_MAIN:
net->ipv4.fib_main = tb; rcu_assign_pointer(net->ipv4.fib_main, tb);
break; break;
case RT_TABLE_DEFAULT: case RT_TABLE_DEFAULT:
net->ipv4.fib_default = tb; rcu_assign_pointer(net->ipv4.fib_default, tb);
break; break;
default: default:
break; break;
} }
...@@ -132,13 +129,14 @@ struct fib_table *fib_get_table(struct net *net, u32 id) ...@@ -132,13 +129,14 @@ struct fib_table *fib_get_table(struct net *net, u32 id)
static void fib_flush(struct net *net) static void fib_flush(struct net *net)
{ {
int flushed = 0; int flushed = 0;
struct fib_table *tb;
struct hlist_head *head;
unsigned int h; unsigned int h;
for (h = 0; h < FIB_TABLE_HASHSZ; h++) { for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
head = &net->ipv4.fib_table_hash[h]; struct hlist_head *head = &net->ipv4.fib_table_hash[h];
hlist_for_each_entry(tb, head, tb_hlist) struct hlist_node *tmp;
struct fib_table *tb;
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
flushed += fib_table_flush(tb); flushed += fib_table_flush(tb);
} }
...@@ -665,10 +663,12 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -665,10 +663,12 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
s_h = cb->args[0]; s_h = cb->args[0];
s_e = cb->args[1]; s_e = cb->args[1];
rcu_read_lock();
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
e = 0; e = 0;
head = &net->ipv4.fib_table_hash[h]; head = &net->ipv4.fib_table_hash[h];
hlist_for_each_entry(tb, head, tb_hlist) { hlist_for_each_entry_rcu(tb, head, tb_hlist) {
if (e < s_e) if (e < s_e)
goto next; goto next;
if (dumped) if (dumped)
...@@ -682,6 +682,8 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -682,6 +682,8 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
} }
} }
out: out:
rcu_read_unlock();
cb->args[1] = e; cb->args[1] = e;
cb->args[0] = h; cb->args[0] = h;
...@@ -1117,14 +1119,34 @@ static void ip_fib_net_exit(struct net *net) ...@@ -1117,14 +1119,34 @@ static void ip_fib_net_exit(struct net *net)
rtnl_lock(); rtnl_lock();
for (i = 0; i < FIB_TABLE_HASHSZ; i++) { for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
struct fib_table *tb; struct hlist_head *head = &net->ipv4.fib_table_hash[i];
struct hlist_head *head;
struct hlist_node *tmp; struct hlist_node *tmp;
struct fib_table *tb;
/* this is done in two passes as flushing the table could
* cause it to be reallocated in order to accommodate new
* tnodes at the root as the table shrinks.
*/
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
fib_table_flush(tb);
head = &net->ipv4.fib_table_hash[i];
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) {
#ifdef CONFIG_IP_MULTIPLE_TABLES
switch (tb->tb_id) {
case RT_TABLE_LOCAL:
RCU_INIT_POINTER(net->ipv4.fib_local, NULL);
break;
case RT_TABLE_MAIN:
RCU_INIT_POINTER(net->ipv4.fib_main, NULL);
break;
case RT_TABLE_DEFAULT:
RCU_INIT_POINTER(net->ipv4.fib_default, NULL);
break;
default:
break;
}
#endif
hlist_del(&tb->tb_hlist); hlist_del(&tb->tb_hlist);
fib_table_flush(tb);
fib_free_table(tb); fib_free_table(tb);
} }
} }
......
This diff is collapsed.
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