If the user hasn't installed any custom rules, don't go through the
whole FIB rules layer. This is pretty similar to f4530fa574df (ipv4:
Avoid overhead when no custom FIB rules are installed).

Using a micro-benchmark module [1], timing ip6_route_output() using
get_cycles(), on my laptop with performance governor (so, subject to
some caution due to thermal throttling), with 40,000 routes in the main
routing table, before this patch:

    min=603 max=12477 count=627 average=1926 95th=4518 90th=3661 50th=1600 
mad=724
    table=254 avgdepth=21.8 maxdepth=39
        value │                         ┊                            count
          600 │▒▒▒▒▒▒▒▒▒▒                                              134
          860 │▒▒▒▒▒▒▒░░░░░░░░░░                                        91
         1120 │▒▒▒░░░░░░░░░░░░░░░░░░                                    39
         1380 │▒▒▒▒░░░░░░░░░░░░░░░░░░░░░                                58
         1640 │▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░                           57
         1900 │▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                       58
         2160 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                   46
         2420 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                 26
         2680 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░               27
         2940 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░              15
         3200 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░              8
         3460 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             8
         3720 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           12
         3980 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            9
         4240 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           7
         4500 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           6

After:

    min=486 max=12390 count=627 average=1715 95th=4365 90th=3352 50th=1324 
mad=631
    table=254 avgdepth=21.8 maxdepth=39
        value │                         ┊                            count
          480 │▒▒▒▒▒▒▒▒▒▒▒▒                                            153
          730 │▒▒▒▒▒▒▒░░░░░░░░░░░░                                      88
          980 │▒▒▒▒░░░░░░░░░░░░░░░░░░░                                  57
         1230 │▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░                             56
         1480 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░                          43
         1730 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                      50
         1980 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                   31
         2230 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                  23
         2480 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                15
         2730 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░               23
         2980 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             20
         3230 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            14
         3480 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            4
         3730 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            8
         3980 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           9
         4230 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           4

At the frequency of the laptop during the bench (~ 2.3 GHz), this is
about a 130 ns difference on the median value and 50 ns on the minimal
value.

A next step would be to collapse local and main tables, as in
0ddcf43d5d4a (ipv4: FIB Local/MAIN table collapse).

[1]: 
https://github.com/vincentbernat/network-lab/blob/master/lab-routes-ipv6/kbench_mod.c

Signed-off-by: Vincent Bernat <vinc...@bernat.im>
---
 include/net/netns/ipv6.h |  1 +
 net/ipv6/fib6_rules.c    | 34 ++++++++++++++++++++++++----------
 net/ipv6/route.c         |  1 +
 3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index abdf3b40303b..0e50bf3ed097 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -65,6 +65,7 @@ struct netns_ipv6 {
        unsigned int             ip6_rt_gc_expire;
        unsigned long            ip6_rt_last_gc;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+       bool                     fib6_has_custom_rules;
        struct rt6_info         *ip6_prohibit_entry;
        struct rt6_info         *ip6_blk_hole_entry;
        struct fib6_table       *fib6_local_tbl;
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 2f29e4e33bd3..693c27ede40e 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -63,19 +63,32 @@ unsigned int fib6_rules_seq_read(struct net *net)
 struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
                                   int flags, pol_lookup_t lookup)
 {
-       struct fib_lookup_arg arg = {
-               .lookup_ptr = lookup,
-               .flags = FIB_LOOKUP_NOREF,
-       };
-
        /* update flow if oif or iif point to device enslaved to l3mdev */
        l3mdev_update_flow(net, flowi6_to_flowi(fl6));
 
-       fib_rules_lookup(net->ipv6.fib6_rules_ops,
-                        flowi6_to_flowi(fl6), flags, &arg);
-
-       if (arg.result)
-               return arg.result;
+       if (net->ipv6.fib6_has_custom_rules) {
+               struct fib_lookup_arg arg = {
+                       .lookup_ptr = lookup,
+                       .flags = FIB_LOOKUP_NOREF,
+               };
+
+               fib_rules_lookup(net->ipv6.fib6_rules_ops,
+                                flowi6_to_flowi(fl6), flags, &arg);
+
+               if (arg.result)
+                       return arg.result;
+       } else {
+               struct rt6_info *rt;
+
+               rt = lookup(net, net->ipv6.fib6_local_tbl, fl6, flags);
+               if (rt != net->ipv6.ip6_null_entry && rt->dst.error != -EAGAIN)
+                       return &rt->dst;
+               ip6_rt_put(rt);
+               rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, flags);
+               if (rt->dst.error != -EAGAIN)
+                       return &rt->dst;
+               ip6_rt_put(rt);
+       }
 
        dst_hold(&net->ipv6.ip6_null_entry->dst);
        return &net->ipv6.ip6_null_entry->dst;
@@ -245,6 +258,7 @@ static int fib6_rule_configure(struct fib_rule *rule, 
struct sk_buff *skb,
        rule6->dst.plen = frh->dst_len;
        rule6->tclass = frh->tos;
 
+       net->ipv6.fib6_has_custom_rules = true;
        err = 0;
 errout:
        return err;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index aba07fce67fb..7ecbe5eb19f8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3934,6 +3934,7 @@ static int __net_init ip6_route_net_init(struct net *net)
                         ip6_template_metrics, true);
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+       net->ipv6.fib6_has_custom_rules = false;
        net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
                                               
sizeof(*net->ipv6.ip6_prohibit_entry),
                                               GFP_KERNEL);
-- 
2.13.3

Reply via email to