net: ipv6: avoid overhead when no custom FIB rules are installed
authorVincent Bernat <vincent@bernat.im>
Tue, 8 Aug 2017 18:23:49 +0000 (20:23 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 9 Aug 2017 04:40:08 +0000 (21:40 -0700)
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() with
get_cycles(), with 40,000 routes in the main routing table, before this
patch:

    min=606 max=12911 count=627 average=1959 95th=4903 90th=3747 50th=1602 mad=821
    table=254 avgdepth=21.8 maxdepth=39
    value │                         ┊                            count
      600 │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒                                         199
      880 │▒▒▒░░░░░░░░░░░░░░░░                                      43
     1160 │▒▒▒░░░░░░░░░░░░░░░░░░░░                                  48
     1440 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░                               43
     1720 │▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░                          59
     2000 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                      50
     2280 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                    26
     2560 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                  31
     2840 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░               28
     3120 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░              17
     3400 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             17
     3680 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             8
     3960 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           11
     4240 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            6
     4520 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           6
     4800 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           9

After:

    min=544 max=11687 count=627 average=1776 95th=4546 90th=3585 50th=1227 mad=565
    table=254 avgdepth=21.8 maxdepth=39
    value │                         ┊                            count
      540 │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒                                        201
      800 │▒▒▒▒▒░░░░░░░░░░░░░░░░                                    63
     1060 │▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░                               68
     1320 │▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░                            39
     1580 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                         32
     1840 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                       32
     2100 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                    34
     2360 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                 33
     2620 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░               26
     2880 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░              22
     3140 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░              9
     3400 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             8
     3660 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░             9
     3920 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░            8
     4180 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           8
     4440 │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           8

At the frequency of the host during the bench (~ 3.7 GHz), this is
about a 100 ns difference on the median 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 <vincent@bernat.im>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Acked-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netns/ipv6.h
net/ipv6/fib6_rules.c
net/ipv6/route.c

index abdf3b40303bf7539d3af68acefa55ff94008581..0e50bf3ed0971ccbc06494a7310160a86bec4637 100644 (file)
@@ -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;
index 2f29e4e33bd3d18f1356224ecf5bc653fbd88a16..b240f24a6e523c387cfc3320ac056a2544f8cffe 100644 (file)
@@ -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,
+               };
+
+               /* 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;
+       } 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;
index aba07fce67fbd59427c8adaa1adf527b802611f7..7ecbe5eb19f80d369c2e2f8a2a8ebd3afa9a91f7 100644 (file)
@@ -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);