diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-09-29 07:53:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-30 20:59:30 -0400 |
commit | dd28d1a0b5ecc0f5512f658b1a8fd38bc4f4c98c (patch) | |
tree | 5cee646dfe354803f0b6f7b9ddd11c189c4ee8e3 /net/ipv4/route.c | |
parent | e1a5964f0c32a75b17360cfc565d25aaedbff747 (diff) |
ipv4: __mkroute_output() speedup
While doing stress tests with a disabled IP route cache, I found
__mkroute_output() was touching three times in_device atomic refcount.
Use RCU to touch it once to reduce cache line ping pongs.
Before patch
time to perform the test
real 1m42.009s
user 0m12.545s
sys 25m0.726s
Profile :
16109.00 26.4% ip_route_output_slow vmlinux
7434.00 12.2% dst_destroy vmlinux
3280.00 5.4% fib_rules_lookup vmlinux
3252.00 5.3% fib_semantic_match vmlinux
2622.00 4.3% fib_table_lookup vmlinux
2535.00 4.1% dst_alloc vmlinux
1750.00 2.9% _raw_read_lock vmlinux
1532.00 2.5% rt_set_nexthop vmlinux
After patch
real 1m36.503s
user 0m12.977s
sys 23m25.608s
14234.00 22.4% ip_route_output_slow vmlinux
8717.00 13.7% dst_destroy vmlinux
4052.00 6.4% fib_rules_lookup vmlinux
3951.00 6.2% fib_semantic_match vmlinux
3191.00 5.0% dst_alloc vmlinux
1764.00 2.8% fib_table_lookup vmlinux
1692.00 2.7% _raw_read_lock vmlinux
1605.00 2.5% rt_set_nexthop vmlinux
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 33 |
1 files changed, 15 insertions, 18 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 98beda47bc99..ea895004caf3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2358,9 +2358,8 @@ static int __mkroute_output(struct rtable **result, | |||
2358 | struct rtable *rth; | 2358 | struct rtable *rth; |
2359 | struct in_device *in_dev; | 2359 | struct in_device *in_dev; |
2360 | u32 tos = RT_FL_TOS(oldflp); | 2360 | u32 tos = RT_FL_TOS(oldflp); |
2361 | int err = 0; | ||
2362 | 2361 | ||
2363 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK)) | 2362 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK)) |
2364 | return -EINVAL; | 2363 | return -EINVAL; |
2365 | 2364 | ||
2366 | if (fl->fl4_dst == htonl(0xFFFFFFFF)) | 2365 | if (fl->fl4_dst == htonl(0xFFFFFFFF)) |
@@ -2373,11 +2372,12 @@ static int __mkroute_output(struct rtable **result, | |||
2373 | if (dev_out->flags & IFF_LOOPBACK) | 2372 | if (dev_out->flags & IFF_LOOPBACK) |
2374 | flags |= RTCF_LOCAL; | 2373 | flags |= RTCF_LOCAL; |
2375 | 2374 | ||
2376 | /* get work reference to inet device */ | 2375 | rcu_read_lock(); |
2377 | in_dev = in_dev_get(dev_out); | 2376 | in_dev = __in_dev_get_rcu(dev_out); |
2378 | if (!in_dev) | 2377 | if (!in_dev) { |
2378 | rcu_read_unlock(); | ||
2379 | return -EINVAL; | 2379 | return -EINVAL; |
2380 | 2380 | } | |
2381 | if (res->type == RTN_BROADCAST) { | 2381 | if (res->type == RTN_BROADCAST) { |
2382 | flags |= RTCF_BROADCAST | RTCF_LOCAL; | 2382 | flags |= RTCF_BROADCAST | RTCF_LOCAL; |
2383 | if (res->fi) { | 2383 | if (res->fi) { |
@@ -2385,13 +2385,13 @@ static int __mkroute_output(struct rtable **result, | |||
2385 | res->fi = NULL; | 2385 | res->fi = NULL; |
2386 | } | 2386 | } |
2387 | } else if (res->type == RTN_MULTICAST) { | 2387 | } else if (res->type == RTN_MULTICAST) { |
2388 | flags |= RTCF_MULTICAST|RTCF_LOCAL; | 2388 | flags |= RTCF_MULTICAST | RTCF_LOCAL; |
2389 | if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, | 2389 | if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, |
2390 | oldflp->proto)) | 2390 | oldflp->proto)) |
2391 | flags &= ~RTCF_LOCAL; | 2391 | flags &= ~RTCF_LOCAL; |
2392 | /* If multicast route do not exist use | 2392 | /* If multicast route do not exist use |
2393 | default one, but do not gateway in this case. | 2393 | * default one, but do not gateway in this case. |
2394 | Yes, it is hack. | 2394 | * Yes, it is hack. |
2395 | */ | 2395 | */ |
2396 | if (res->fi && res->prefixlen < 4) { | 2396 | if (res->fi && res->prefixlen < 4) { |
2397 | fib_info_put(res->fi); | 2397 | fib_info_put(res->fi); |
@@ -2402,9 +2402,12 @@ static int __mkroute_output(struct rtable **result, | |||
2402 | 2402 | ||
2403 | rth = dst_alloc(&ipv4_dst_ops); | 2403 | rth = dst_alloc(&ipv4_dst_ops); |
2404 | if (!rth) { | 2404 | if (!rth) { |
2405 | err = -ENOBUFS; | 2405 | rcu_read_unlock(); |
2406 | goto cleanup; | 2406 | return -ENOBUFS; |
2407 | } | 2407 | } |
2408 | in_dev_hold(in_dev); | ||
2409 | rcu_read_unlock(); | ||
2410 | rth->idev = in_dev; | ||
2408 | 2411 | ||
2409 | atomic_set(&rth->dst.__refcnt, 1); | 2412 | atomic_set(&rth->dst.__refcnt, 1); |
2410 | rth->dst.flags= DST_HOST; | 2413 | rth->dst.flags= DST_HOST; |
@@ -2425,7 +2428,6 @@ static int __mkroute_output(struct rtable **result, | |||
2425 | cache entry */ | 2428 | cache entry */ |
2426 | rth->dst.dev = dev_out; | 2429 | rth->dst.dev = dev_out; |
2427 | dev_hold(dev_out); | 2430 | dev_hold(dev_out); |
2428 | rth->idev = in_dev_get(dev_out); | ||
2429 | rth->rt_gateway = fl->fl4_dst; | 2431 | rth->rt_gateway = fl->fl4_dst; |
2430 | rth->rt_spec_dst= fl->fl4_src; | 2432 | rth->rt_spec_dst= fl->fl4_src; |
2431 | 2433 | ||
@@ -2460,13 +2462,8 @@ static int __mkroute_output(struct rtable **result, | |||
2460 | rt_set_nexthop(rth, res, 0); | 2462 | rt_set_nexthop(rth, res, 0); |
2461 | 2463 | ||
2462 | rth->rt_flags = flags; | 2464 | rth->rt_flags = flags; |
2463 | |||
2464 | *result = rth; | 2465 | *result = rth; |
2465 | cleanup: | 2466 | return 0; |
2466 | /* release work reference to inet device */ | ||
2467 | in_dev_put(in_dev); | ||
2468 | |||
2469 | return err; | ||
2470 | } | 2467 | } |
2471 | 2468 | ||
2472 | static int ip_mkroute_output(struct rtable **rp, | 2469 | static int ip_mkroute_output(struct rtable **rp, |