Merge branch 'fib_trie-next'
Alexander Duyck says: ==================== fib_trie: Reduce time spent in fib_table_lookup by 35 to 75% These patches are meant to address several performance issues I have seen in the fib_trie implementation, and fib_table_lookup specifically. With these changes in place I have seen a reduction of up to 35 to 75% for the total time spent in fib_table_lookup depending on the type of search being performed. On a VM running in my Corei7-4930K system with a trie of maximum depth of 7 this resulted in a reduction of over 370ns per packet in the total time to process packets received from an ixgbe interface and route them to a dummy interface. This represents a failed lookup in the local trie followed by a successful search in the main trie. Baseline Refactor ixgbe->dummy routing 1.20Mpps 2.21Mpps ------------------------------------------------------------ processing time per packet 835ns 453ns fib_table_lookup 50.1% 418ns 25.0% 113ns check_leaf.isra.9 7.9% 66ns -- -- ixgbe_clean_rx_irq 5.3% 44ns 9.8% 44ns ip_route_input_noref 2.9% 25ns 4.6% 21ns pvclock_clocksource_read 2.6% 21ns 4.6% 21ns ip_rcv 2.6% 22ns 4.0% 18ns In the simple case of receiving a frame and dropping it before it can reach the socket layer I saw a reduction of 40ns per packet. This represents a trip through the local trie with the correct leaf found with no need for any backtracing. Baseline Refactor ixgbe->local receive 2.65Mpps 2.96Mpps ------------------------------------------------------------ processing time per packet 377ns 337ns fib_table_lookup 25.1% 95ns 25.8% 87ns ixgbe_clean_rx_irq 8.7% 33ns 9.0% 30ns check_leaf.isra.9 7.2% 27ns -- -- ip_rcv 5.7% 21ns 6.5% 22ns These changes have resulted in several functions being inlined such as check_leaf and fib_find_node, but due to the code simplification the overall size of the code has been reduced. text data bss dec hex filename 16932 376 16 17324 43ac net/ipv4/fib_trie.o - before 15259 376 8 15643 3d1b net/ipv4/fib_trie.o - after Changes since RFC: Replaced this_cpu_ptr with correct call to this_cpu_inc in patch 1 Changed test for leaf_info mismatch to (key ^ n->key) & li->mask_plen in patch 10 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e495f78d78
|
@ -222,16 +222,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,
|
||||
struct fib_result *res)
|
||||
{
|
||||
struct fib_table *table;
|
||||
int err = -ENETUNREACH;
|
||||
|
||||
table = fib_get_table(net, RT_TABLE_LOCAL);
|
||||
if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
|
||||
return 0;
|
||||
rcu_read_lock();
|
||||
|
||||
table = fib_get_table(net, RT_TABLE_MAIN);
|
||||
if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
|
||||
return 0;
|
||||
return -ENETUNREACH;
|
||||
if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res,
|
||||
FIB_LOOKUP_NOREF) ||
|
||||
!fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res,
|
||||
FIB_LOOKUP_NOREF))
|
||||
err = 0;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IP_MULTIPLE_TABLES */
|
||||
|
@ -247,20 +250,25 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
|
|||
struct fib_result *res)
|
||||
{
|
||||
if (!net->ipv4.fib_has_custom_rules) {
|
||||
int err = -ENETUNREACH;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
res->tclassid = 0;
|
||||
if (net->ipv4.fib_local &&
|
||||
!fib_table_lookup(net->ipv4.fib_local, flp, res,
|
||||
FIB_LOOKUP_NOREF))
|
||||
return 0;
|
||||
if (net->ipv4.fib_main &&
|
||||
!fib_table_lookup(net->ipv4.fib_main, flp, res,
|
||||
FIB_LOOKUP_NOREF))
|
||||
return 0;
|
||||
if (net->ipv4.fib_default &&
|
||||
!fib_table_lookup(net->ipv4.fib_default, flp, res,
|
||||
FIB_LOOKUP_NOREF))
|
||||
return 0;
|
||||
return -ENETUNREACH;
|
||||
if ((net->ipv4.fib_local &&
|
||||
!fib_table_lookup(net->ipv4.fib_local, flp, res,
|
||||
FIB_LOOKUP_NOREF)) ||
|
||||
(net->ipv4.fib_main &&
|
||||
!fib_table_lookup(net->ipv4.fib_main, flp, res,
|
||||
FIB_LOOKUP_NOREF)) ||
|
||||
(net->ipv4.fib_default &&
|
||||
!fib_table_lookup(net->ipv4.fib_default, flp, res,
|
||||
FIB_LOOKUP_NOREF)))
|
||||
err = 0;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
return __fib_lookup(net, flp, res);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(struct net *net)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
kfree(local_table);
|
||||
fib_free_table(local_table);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else
|
||||
|
@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
|
|||
return tb;
|
||||
}
|
||||
|
||||
/* caller must hold either rtnl or rcu read lock */
|
||||
struct fib_table *fib_get_table(struct net *net, u32 id)
|
||||
{
|
||||
struct fib_table *tb;
|
||||
|
@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct net *net, u32 id)
|
|||
id = RT_TABLE_MAIN;
|
||||
h = id & (FIB_TABLE_HASHSZ - 1);
|
||||
|
||||
rcu_read_lock();
|
||||
head = &net->ipv4.fib_table_hash[h];
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist) {
|
||||
if (tb->tb_id == id) {
|
||||
rcu_read_unlock();
|
||||
if (tb->tb_id == id)
|
||||
return tb;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_IP_MULTIPLE_TABLES */
|
||||
|
@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
|
|||
if (ipv4_is_multicast(addr))
|
||||
return RTN_MULTICAST;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
||||
if (local_table) {
|
||||
ret = RTN_UNICAST;
|
||||
rcu_read_lock();
|
||||
if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
|
||||
if (!dev || dev == res.fi->fib_dev)
|
||||
ret = res.type;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -919,7 +918,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
|||
#undef BRD1_OK
|
||||
}
|
||||
|
||||
static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
|
||||
static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
|
||||
{
|
||||
|
||||
struct fib_result res;
|
||||
|
@ -929,6 +928,11 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
|
|||
.flowi4_tos = frn->fl_tos,
|
||||
.flowi4_scope = frn->fl_scope,
|
||||
};
|
||||
struct fib_table *tb;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
tb = fib_get_table(net, frn->tb_id_in);
|
||||
|
||||
frn->err = -ENOENT;
|
||||
if (tb) {
|
||||
|
@ -945,6 +949,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
|
|||
}
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void nl_fib_input(struct sk_buff *skb)
|
||||
|
@ -952,7 +958,6 @@ static void nl_fib_input(struct sk_buff *skb)
|
|||
struct net *net;
|
||||
struct fib_result_nl *frn;
|
||||
struct nlmsghdr *nlh;
|
||||
struct fib_table *tb;
|
||||
u32 portid;
|
||||
|
||||
net = sock_net(skb->sk);
|
||||
|
@ -967,9 +972,7 @@ static void nl_fib_input(struct sk_buff *skb)
|
|||
nlh = nlmsg_hdr(skb);
|
||||
|
||||
frn = (struct fib_result_nl *) nlmsg_data(nlh);
|
||||
tb = fib_get_table(net, frn->tb_id_in);
|
||||
|
||||
nl_fib_lookup(frn, tb);
|
||||
nl_fib_lookup(net, frn);
|
||||
|
||||
portid = NETLINK_CB(skb).portid; /* netlink portid */
|
||||
NETLINK_CB(skb).portid = 0; /* from kernel */
|
||||
|
|
|
@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
|
|||
break;
|
||||
|
||||
case FR_ACT_UNREACHABLE:
|
||||
err = -ENETUNREACH;
|
||||
goto errout;
|
||||
return -ENETUNREACH;
|
||||
|
||||
case FR_ACT_PROHIBIT:
|
||||
err = -EACCES;
|
||||
goto errout;
|
||||
return -EACCES;
|
||||
|
||||
case FR_ACT_BLACKHOLE:
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto errout;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tbl = fib_get_table(rule->fr_net, rule->table);
|
||||
if (!tbl)
|
||||
goto errout;
|
||||
rcu_read_lock();
|
||||
|
||||
err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags);
|
||||
if (err > 0)
|
||||
err = -EAGAIN;
|
||||
errout:
|
||||
tbl = fib_get_table(rule->fr_net, rule->table);
|
||||
if (tbl)
|
||||
err = fib_table_lookup(tbl, &flp->u.ip4,
|
||||
(struct fib_result *)arg->result,
|
||||
arg->flags);
|
||||
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
1976
net/ipv4/fib_trie.c
1976
net/ipv4/fib_trie.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue