diff options
author | David S. Miller <davem@davemloft.net> | 2011-02-17 18:29:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-17 18:29:00 -0500 |
commit | 5ada552746685d558d0a8e9e979921c75a41e469 (patch) | |
tree | e81111d9cdb826f34d31f1276a51321c6ce14df0 /net | |
parent | cf0bdefd4676ad4ad59507a058821491a40ec7e6 (diff) |
ipv4: Simplify output route creation call sequence.
There's a lot of redundancy and unnecessary stack frames
in the output route creation path.
1) Make __mkroute_output() return error pointers.
2) Eliminate ip_mkroute_output() entirely, made possible by #1.
3) Call __mkroute_output() directly and handling the returning error
pointers in ip_route_output_slow().
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/route.c | 58 |
1 files changed, 23 insertions, 35 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 756f5443b5f7..849be48971ec 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2323,33 +2323,32 @@ skip_cache: | |||
2323 | EXPORT_SYMBOL(ip_route_input_common); | 2323 | EXPORT_SYMBOL(ip_route_input_common); |
2324 | 2324 | ||
2325 | /* called with rcu_read_lock() */ | 2325 | /* called with rcu_read_lock() */ |
2326 | static int __mkroute_output(struct rtable **result, | 2326 | static struct rtable *__mkroute_output(struct fib_result *res, |
2327 | struct fib_result *res, | 2327 | const struct flowi *fl, |
2328 | const struct flowi *fl, | 2328 | const struct flowi *oldflp, |
2329 | const struct flowi *oldflp, | 2329 | struct net_device *dev_out, |
2330 | struct net_device *dev_out, | 2330 | unsigned int flags) |
2331 | unsigned flags) | ||
2332 | { | 2331 | { |
2333 | struct rtable *rth; | ||
2334 | struct in_device *in_dev; | ||
2335 | u32 tos = RT_FL_TOS(oldflp); | 2332 | u32 tos = RT_FL_TOS(oldflp); |
2333 | struct in_device *in_dev; | ||
2334 | struct rtable *rth; | ||
2336 | 2335 | ||
2337 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK)) | 2336 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK)) |
2338 | return -EINVAL; | 2337 | return ERR_PTR(-EINVAL); |
2339 | 2338 | ||
2340 | if (ipv4_is_lbcast(fl->fl4_dst)) | 2339 | if (ipv4_is_lbcast(fl->fl4_dst)) |
2341 | res->type = RTN_BROADCAST; | 2340 | res->type = RTN_BROADCAST; |
2342 | else if (ipv4_is_multicast(fl->fl4_dst)) | 2341 | else if (ipv4_is_multicast(fl->fl4_dst)) |
2343 | res->type = RTN_MULTICAST; | 2342 | res->type = RTN_MULTICAST; |
2344 | else if (ipv4_is_zeronet(fl->fl4_dst)) | 2343 | else if (ipv4_is_zeronet(fl->fl4_dst)) |
2345 | return -EINVAL; | 2344 | return ERR_PTR(-EINVAL); |
2346 | 2345 | ||
2347 | if (dev_out->flags & IFF_LOOPBACK) | 2346 | if (dev_out->flags & IFF_LOOPBACK) |
2348 | flags |= RTCF_LOCAL; | 2347 | flags |= RTCF_LOCAL; |
2349 | 2348 | ||
2350 | in_dev = __in_dev_get_rcu(dev_out); | 2349 | in_dev = __in_dev_get_rcu(dev_out); |
2351 | if (!in_dev) | 2350 | if (!in_dev) |
2352 | return -EINVAL; | 2351 | return ERR_PTR(-EINVAL); |
2353 | 2352 | ||
2354 | if (res->type == RTN_BROADCAST) { | 2353 | if (res->type == RTN_BROADCAST) { |
2355 | flags |= RTCF_BROADCAST | RTCF_LOCAL; | 2354 | flags |= RTCF_BROADCAST | RTCF_LOCAL; |
@@ -2370,7 +2369,7 @@ static int __mkroute_output(struct rtable **result, | |||
2370 | 2369 | ||
2371 | rth = dst_alloc(&ipv4_dst_ops); | 2370 | rth = dst_alloc(&ipv4_dst_ops); |
2372 | if (!rth) | 2371 | if (!rth) |
2373 | return -ENOBUFS; | 2372 | return ERR_PTR(-ENOBUFS); |
2374 | 2373 | ||
2375 | atomic_set(&rth->dst.__refcnt, 1); | 2374 | atomic_set(&rth->dst.__refcnt, 1); |
2376 | rth->dst.flags= DST_HOST; | 2375 | rth->dst.flags= DST_HOST; |
@@ -2425,28 +2424,7 @@ static int __mkroute_output(struct rtable **result, | |||
2425 | rt_set_nexthop(rth, res, 0); | 2424 | rt_set_nexthop(rth, res, 0); |
2426 | 2425 | ||
2427 | rth->rt_flags = flags; | 2426 | rth->rt_flags = flags; |
2428 | *result = rth; | 2427 | return rth; |
2429 | return 0; | ||
2430 | } | ||
2431 | |||
2432 | /* called with rcu_read_lock() */ | ||
2433 | static int ip_mkroute_output(struct rtable **rp, | ||
2434 | struct fib_result *res, | ||
2435 | const struct flowi *fl, | ||
2436 | const struct flowi *oldflp, | ||
2437 | struct net_device *dev_out, | ||
2438 | unsigned flags) | ||
2439 | { | ||
2440 | struct rtable *rth = NULL; | ||
2441 | int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags); | ||
2442 | unsigned hash; | ||
2443 | if (err == 0) { | ||
2444 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | ||
2445 | rt_genid(dev_net(dev_out))); | ||
2446 | err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); | ||
2447 | } | ||
2448 | |||
2449 | return err; | ||
2450 | } | 2428 | } |
2451 | 2429 | ||
2452 | /* | 2430 | /* |
@@ -2469,6 +2447,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2469 | struct fib_result res; | 2447 | struct fib_result res; |
2470 | unsigned int flags = 0; | 2448 | unsigned int flags = 0; |
2471 | struct net_device *dev_out = NULL; | 2449 | struct net_device *dev_out = NULL; |
2450 | struct rtable *rth; | ||
2472 | int err; | 2451 | int err; |
2473 | 2452 | ||
2474 | 2453 | ||
@@ -2627,7 +2606,16 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2627 | 2606 | ||
2628 | 2607 | ||
2629 | make_route: | 2608 | make_route: |
2630 | err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags); | 2609 | rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags); |
2610 | if (IS_ERR(rth)) | ||
2611 | err = PTR_ERR(rth); | ||
2612 | else { | ||
2613 | unsigned int hash; | ||
2614 | |||
2615 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | ||
2616 | rt_genid(dev_net(dev_out))); | ||
2617 | err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); | ||
2618 | } | ||
2631 | 2619 | ||
2632 | out: return err; | 2620 | out: return err; |
2633 | } | 2621 | } |