Skip to content

Commit

Permalink
ipv4: FIB Local/MAIN table collapse
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alexander Duyck authored and davem330 committed Mar 11, 2015
1 parent 169bf91 commit 0ddcf43
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 38 deletions.
2 changes: 1 addition & 1 deletion include/net/fib_rules.h
Expand Up @@ -58,7 +58,7 @@ struct fib_rules_ops {
struct sk_buff *,
struct fib_rule_hdr *,
struct nlattr **);
void (*delete)(struct fib_rule *);
int (*delete)(struct fib_rule *);
int (*compare)(struct fib_rule *,
struct fib_rule_hdr *,
struct nlattr **);
Expand Down
26 changes: 9 additions & 17 deletions include/net/ip_fib.h
Expand Up @@ -186,7 +186,8 @@ struct fib_table {
int tb_default;
int tb_num_default;
struct rcu_head rcu;
unsigned long tb_data[0];
unsigned long *tb_data;
unsigned long __data[0];
};

int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
Expand All @@ -196,11 +197,10 @@ int fib_table_delete(struct fib_table *, struct fib_config *);
int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int fib_table_flush(struct fib_table *table);
struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
void fib_table_flush_external(struct fib_table *table);
void fib_free_table(struct fib_table *tb);



#ifndef CONFIG_IP_MULTIPLE_TABLES

#define TABLE_LOCAL_INDEX (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1))
Expand Down Expand Up @@ -229,18 +229,13 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
struct fib_result *res)
{
struct fib_table *tb;
int err;
int err = -ENETUNREACH;

rcu_read_lock();

for (err = 0; !err; err = -ENETUNREACH) {
tb = fib_get_table(net, RT_TABLE_LOCAL);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;
tb = fib_get_table(net, RT_TABLE_MAIN);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;
}
tb = fib_get_table(net, RT_TABLE_MAIN);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
err = 0;

rcu_read_unlock();

Expand Down Expand Up @@ -270,10 +265,6 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
res->tclassid = 0;

for (err = 0; !err; err = -ENETUNREACH) {
tb = rcu_dereference_rtnl(net->ipv4.fib_local);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;

tb = rcu_dereference_rtnl(net->ipv4.fib_main);
if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF))
break;
Expand Down Expand Up @@ -309,6 +300,7 @@ static inline int fib_num_tclassid_users(struct net *net)
return 0;
}
#endif
int fib_unmerge(struct net *net);
void fib_flush_external(struct net *net);

/* Exported by fib_semantics.c */
Expand All @@ -320,7 +312,7 @@ void fib_select_multipath(struct fib_result *res);

/* Exported by fib_trie.c */
void fib_trie_init(void);
struct fib_table *fib_trie_table(u32 id);
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);

static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
{
Expand Down
8 changes: 6 additions & 2 deletions net/core/fib_rules.c
Expand Up @@ -492,6 +492,12 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
goto errout;
}

if (ops->delete) {
err = ops->delete(rule);
if (err)
goto errout;
}

list_del_rcu(&rule->list);

if (rule->action == FR_ACT_GOTO) {
Expand All @@ -517,8 +523,6 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)

notify_rule_change(RTM_DELRULE, rule, ops, nlh,
NETLINK_CB(skb).portid);
if (ops->delete)
ops->delete(rule);
fib_rule_put(rule);
flush_route_cache(ops);
rules_ops_put(ops);
Expand Down
59 changes: 52 additions & 7 deletions net/ipv4/fib_frontend.c
Expand Up @@ -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,
Expand All @@ -74,7 +74,7 @@ static int __net_init fib4_rules_init(struct net *net)

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)
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/fib_lookup.h
Expand Up @@ -12,6 +12,7 @@ struct fib_alias {
u8 fa_type;
u8 fa_state;
u8 fa_slen;
u32 tb_id;
struct rcu_head rcu;
};

Expand Down
20 changes: 16 additions & 4 deletions net/ipv4/fib_rules.c
Expand Up @@ -174,6 +174,11 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
if (frh->tos & ~IPTOS_TOS_MASK)
goto errout;

/* split local/main if they are not already split */
err = fib_unmerge(net);
if (err)
goto errout;

if (rule->table == RT_TABLE_UNSPEC) {
if (rule->action == FR_ACT_TO_TBL) {
struct fib_table *table;
Expand Down Expand Up @@ -216,17 +221,24 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
return err;
}

static void fib4_rule_delete(struct fib_rule *rule)
static int fib4_rule_delete(struct fib_rule *rule)
{
struct net *net = rule->fr_net;
#ifdef CONFIG_IP_ROUTE_CLASSID
struct fib4_rule *rule4 = (struct fib4_rule *) rule;
int err;

if (rule4->tclassid)
/* split local/main if they are not already split */
err = fib_unmerge(net);
if (err)
goto errout;

#ifdef CONFIG_IP_ROUTE_CLASSID
if (((struct fib4_rule *)rule)->tclassid)
net->ipv4.fib_num_tclassid_users--;
#endif
net->ipv4.fib_has_custom_rules = true;
fib_flush_external(rule->fr_net);
errout:
return err;
}

static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
Expand Down

0 comments on commit 0ddcf43

Please sign in to comment.