diff options
author | Alexander Duyck <alexander.h.duyck@redhat.com> | 2015-03-07 00:47:00 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-11 23:22:14 +0300 |
commit | 0ddcf43d5d4a03ded1ee3f6b3b72a0cbed4e90b1 (patch) | |
tree | 28c93b0c6eb9389182f60736103b6bfc0b61cedc /net/ipv4/fib_frontend.c | |
parent | 169bf9121b19dd6029e0a354d33513f61bfbe3d3 (diff) | |
download | linux-0ddcf43d5d4a03ded1ee3f6b3b72a0cbed4e90b1.tar.xz |
ipv4: FIB Local/MAIN table collapse
This patch is meant to collapse local and main into one by converting
tb_data from an array to a pointer. Doing this allows us to point the
local table into the main while maintaining the same variables in the
table.
As such the tb_data was converted from an array to a pointer, and a new
array called data is added in order to still provide an object for tb_data
to point to.
In order to track the origin of the fib aliases a tb_id value was added in
a hole that existed on 64b systems. Using this we can also reverse the
merge in the event that custom FIB rules are enabled.
With this patch I am seeing an improvement of 20ns to 30ns for routing
lookups as long as custom rules are not enabled, with custom rules enabled
we fall back to split tables and the original behavior.
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r-- | net/ipv4/fib_frontend.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e067770235bf..7cda3b0521d8 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -52,14 +52,14 @@ static int __net_init fib4_rules_init(struct net *net) { struct fib_table *local_table, *main_table; - local_table = fib_trie_table(RT_TABLE_LOCAL); - if (local_table == NULL) - return -ENOMEM; - - main_table = fib_trie_table(RT_TABLE_MAIN); + main_table = fib_trie_table(RT_TABLE_MAIN, NULL); if (main_table == NULL) goto fail; + local_table = fib_trie_table(RT_TABLE_LOCAL, main_table); + if (local_table == NULL) + return -ENOMEM; + hlist_add_head_rcu(&local_table->tb_hlist, &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]); hlist_add_head_rcu(&main_table->tb_hlist, @@ -74,7 +74,7 @@ fail: struct fib_table *fib_new_table(struct net *net, u32 id) { - struct fib_table *tb; + struct fib_table *tb, *alias = NULL; unsigned int h; if (id == 0) @@ -83,7 +83,10 @@ struct fib_table *fib_new_table(struct net *net, u32 id) if (tb) return tb; - tb = fib_trie_table(id); + if (id == RT_TABLE_LOCAL) + alias = fib_new_table(net, RT_TABLE_MAIN); + + tb = fib_trie_table(id, alias); if (!tb) return NULL; @@ -126,6 +129,48 @@ struct fib_table *fib_get_table(struct net *net, u32 id) } #endif /* CONFIG_IP_MULTIPLE_TABLES */ +static void fib_replace_table(struct net *net, struct fib_table *old, + struct fib_table *new) +{ +#ifdef CONFIG_IP_MULTIPLE_TABLES + switch (new->tb_id) { + case RT_TABLE_LOCAL: + rcu_assign_pointer(net->ipv4.fib_local, new); + break; + case RT_TABLE_MAIN: + rcu_assign_pointer(net->ipv4.fib_main, new); + break; + case RT_TABLE_DEFAULT: + rcu_assign_pointer(net->ipv4.fib_default, new); + break; + default: + break; + } + +#endif + /* replace the old table in the hlist */ + hlist_replace_rcu(&old->tb_hlist, &new->tb_hlist); +} + +int fib_unmerge(struct net *net) +{ + struct fib_table *old, *new; + + old = fib_get_table(net, RT_TABLE_LOCAL); + new = fib_trie_unmerge(old); + + if (!new) + return -ENOMEM; + + /* replace merged table with clean table */ + if (new != old) { + fib_replace_table(net, old, new); + fib_free_table(old); + } + + return 0; +} + static void fib_flush(struct net *net) { int flushed = 0; |