diff options
author | David S. Miller <davem@davemloft.net> | 2011-03-02 17:31:35 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-02 17:31:35 -0500 |
commit | b23dd4fe42b455af5c6e20966b7d6959fa8352ea (patch) | |
tree | bf97323eae9a8d084170e573ff2c0c40bc72c3cd /net/ipv4/route.c | |
parent | 452edd598f60522c11f7f88fdbab27eb36509d1a (diff) |
ipv4: Make output route lookup return rtable directly.
Instead of on the stack.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 100 |
1 files changed, 49 insertions, 51 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 63d37004ee66..5090e956f6b8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1014,8 +1014,8 @@ static int slow_chain_length(const struct rtable *head) | |||
1014 | return length >> FRACT_BITS; | 1014 | return length >> FRACT_BITS; |
1015 | } | 1015 | } |
1016 | 1016 | ||
1017 | static int rt_intern_hash(unsigned hash, struct rtable *rt, | 1017 | static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt, |
1018 | struct rtable **rp, struct sk_buff *skb, int ifindex) | 1018 | struct sk_buff *skb, int ifindex) |
1019 | { | 1019 | { |
1020 | struct rtable *rth, *cand; | 1020 | struct rtable *rth, *cand; |
1021 | struct rtable __rcu **rthp, **candp; | 1021 | struct rtable __rcu **rthp, **candp; |
@@ -1056,7 +1056,7 @@ restart: | |||
1056 | printk(KERN_WARNING | 1056 | printk(KERN_WARNING |
1057 | "Neighbour table failure & not caching routes.\n"); | 1057 | "Neighbour table failure & not caching routes.\n"); |
1058 | ip_rt_put(rt); | 1058 | ip_rt_put(rt); |
1059 | return err; | 1059 | return ERR_PTR(err); |
1060 | } | 1060 | } |
1061 | } | 1061 | } |
1062 | 1062 | ||
@@ -1093,11 +1093,9 @@ restart: | |||
1093 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1093 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1094 | 1094 | ||
1095 | rt_drop(rt); | 1095 | rt_drop(rt); |
1096 | if (rp) | 1096 | if (skb) |
1097 | *rp = rth; | ||
1098 | else | ||
1099 | skb_dst_set(skb, &rth->dst); | 1097 | skb_dst_set(skb, &rth->dst); |
1100 | return 0; | 1098 | return rth; |
1101 | } | 1099 | } |
1102 | 1100 | ||
1103 | if (!atomic_read(&rth->dst.__refcnt)) { | 1101 | if (!atomic_read(&rth->dst.__refcnt)) { |
@@ -1154,7 +1152,7 @@ restart: | |||
1154 | 1152 | ||
1155 | if (err != -ENOBUFS) { | 1153 | if (err != -ENOBUFS) { |
1156 | rt_drop(rt); | 1154 | rt_drop(rt); |
1157 | return err; | 1155 | return ERR_PTR(err); |
1158 | } | 1156 | } |
1159 | 1157 | ||
1160 | /* Neighbour tables are full and nothing | 1158 | /* Neighbour tables are full and nothing |
@@ -1175,7 +1173,7 @@ restart: | |||
1175 | if (net_ratelimit()) | 1173 | if (net_ratelimit()) |
1176 | printk(KERN_WARNING "ipv4: Neighbour table overflow.\n"); | 1174 | printk(KERN_WARNING "ipv4: Neighbour table overflow.\n"); |
1177 | rt_drop(rt); | 1175 | rt_drop(rt); |
1178 | return -ENOBUFS; | 1176 | return ERR_PTR(-ENOBUFS); |
1179 | } | 1177 | } |
1180 | } | 1178 | } |
1181 | 1179 | ||
@@ -1201,11 +1199,9 @@ restart: | |||
1201 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1199 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1202 | 1200 | ||
1203 | skip_hashing: | 1201 | skip_hashing: |
1204 | if (rp) | 1202 | if (skb) |
1205 | *rp = rt; | ||
1206 | else | ||
1207 | skb_dst_set(skb, &rt->dst); | 1203 | skb_dst_set(skb, &rt->dst); |
1208 | return 0; | 1204 | return rt; |
1209 | } | 1205 | } |
1210 | 1206 | ||
1211 | static atomic_t __rt_peer_genid = ATOMIC_INIT(0); | 1207 | static atomic_t __rt_peer_genid = ATOMIC_INIT(0); |
@@ -1896,7 +1892,10 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1896 | RT_CACHE_STAT_INC(in_slow_mc); | 1892 | RT_CACHE_STAT_INC(in_slow_mc); |
1897 | 1893 | ||
1898 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); | 1894 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); |
1899 | return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex); | 1895 | rth = rt_intern_hash(hash, rth, skb, dev->ifindex); |
1896 | err = 0; | ||
1897 | if (IS_ERR(rth)) | ||
1898 | err = PTR_ERR(rth); | ||
1900 | 1899 | ||
1901 | e_nobufs: | 1900 | e_nobufs: |
1902 | return -ENOBUFS; | 1901 | return -ENOBUFS; |
@@ -2051,7 +2050,10 @@ static int ip_mkroute_input(struct sk_buff *skb, | |||
2051 | /* put it into the cache */ | 2050 | /* put it into the cache */ |
2052 | hash = rt_hash(daddr, saddr, fl->iif, | 2051 | hash = rt_hash(daddr, saddr, fl->iif, |
2053 | rt_genid(dev_net(rth->dst.dev))); | 2052 | rt_genid(dev_net(rth->dst.dev))); |
2054 | return rt_intern_hash(hash, rth, NULL, skb, fl->iif); | 2053 | rth = rt_intern_hash(hash, rth, skb, fl->iif); |
2054 | if (IS_ERR(rth)) | ||
2055 | return PTR_ERR(rth); | ||
2056 | return 0; | ||
2055 | } | 2057 | } |
2056 | 2058 | ||
2057 | /* | 2059 | /* |
@@ -2194,7 +2196,10 @@ local_input: | |||
2194 | } | 2196 | } |
2195 | rth->rt_type = res.type; | 2197 | rth->rt_type = res.type; |
2196 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); | 2198 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); |
2197 | err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); | 2199 | rth = rt_intern_hash(hash, rth, skb, fl.iif); |
2200 | err = 0; | ||
2201 | if (IS_ERR(rth)) | ||
2202 | err = PTR_ERR(rth); | ||
2198 | goto out; | 2203 | goto out; |
2199 | 2204 | ||
2200 | no_route: | 2205 | no_route: |
@@ -2422,8 +2427,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2422 | * called with rcu_read_lock(); | 2427 | * called with rcu_read_lock(); |
2423 | */ | 2428 | */ |
2424 | 2429 | ||
2425 | static int ip_route_output_slow(struct net *net, struct rtable **rp, | 2430 | static struct rtable *ip_route_output_slow(struct net *net, |
2426 | const struct flowi *oldflp) | 2431 | const struct flowi *oldflp) |
2427 | { | 2432 | { |
2428 | u32 tos = RT_FL_TOS(oldflp); | 2433 | u32 tos = RT_FL_TOS(oldflp); |
2429 | struct flowi fl = { .fl4_dst = oldflp->fl4_dst, | 2434 | struct flowi fl = { .fl4_dst = oldflp->fl4_dst, |
@@ -2438,8 +2443,6 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2438 | unsigned int flags = 0; | 2443 | unsigned int flags = 0; |
2439 | struct net_device *dev_out = NULL; | 2444 | struct net_device *dev_out = NULL; |
2440 | struct rtable *rth; | 2445 | struct rtable *rth; |
2441 | int err; | ||
2442 | |||
2443 | 2446 | ||
2444 | res.fi = NULL; | 2447 | res.fi = NULL; |
2445 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 2448 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
@@ -2448,7 +2451,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2448 | 2451 | ||
2449 | rcu_read_lock(); | 2452 | rcu_read_lock(); |
2450 | if (oldflp->fl4_src) { | 2453 | if (oldflp->fl4_src) { |
2451 | err = -EINVAL; | 2454 | rth = ERR_PTR(-EINVAL); |
2452 | if (ipv4_is_multicast(oldflp->fl4_src) || | 2455 | if (ipv4_is_multicast(oldflp->fl4_src) || |
2453 | ipv4_is_lbcast(oldflp->fl4_src) || | 2456 | ipv4_is_lbcast(oldflp->fl4_src) || |
2454 | ipv4_is_zeronet(oldflp->fl4_src)) | 2457 | ipv4_is_zeronet(oldflp->fl4_src)) |
@@ -2499,13 +2502,13 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2499 | 2502 | ||
2500 | if (oldflp->oif) { | 2503 | if (oldflp->oif) { |
2501 | dev_out = dev_get_by_index_rcu(net, oldflp->oif); | 2504 | dev_out = dev_get_by_index_rcu(net, oldflp->oif); |
2502 | err = -ENODEV; | 2505 | rth = ERR_PTR(-ENODEV); |
2503 | if (dev_out == NULL) | 2506 | if (dev_out == NULL) |
2504 | goto out; | 2507 | goto out; |
2505 | 2508 | ||
2506 | /* RACE: Check return value of inet_select_addr instead. */ | 2509 | /* RACE: Check return value of inet_select_addr instead. */ |
2507 | if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { | 2510 | if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { |
2508 | err = -ENETUNREACH; | 2511 | rth = ERR_PTR(-ENETUNREACH); |
2509 | goto out; | 2512 | goto out; |
2510 | } | 2513 | } |
2511 | if (ipv4_is_local_multicast(oldflp->fl4_dst) || | 2514 | if (ipv4_is_local_multicast(oldflp->fl4_dst) || |
@@ -2563,7 +2566,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2563 | res.type = RTN_UNICAST; | 2566 | res.type = RTN_UNICAST; |
2564 | goto make_route; | 2567 | goto make_route; |
2565 | } | 2568 | } |
2566 | err = -ENETUNREACH; | 2569 | rth = ERR_PTR(-ENETUNREACH); |
2567 | goto out; | 2570 | goto out; |
2568 | } | 2571 | } |
2569 | 2572 | ||
@@ -2598,23 +2601,20 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2598 | 2601 | ||
2599 | make_route: | 2602 | make_route: |
2600 | rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags); | 2603 | rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags); |
2601 | if (IS_ERR(rth)) | 2604 | if (!IS_ERR(rth)) { |
2602 | err = PTR_ERR(rth); | ||
2603 | else { | ||
2604 | unsigned int hash; | 2605 | unsigned int hash; |
2605 | 2606 | ||
2606 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | 2607 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, |
2607 | rt_genid(dev_net(dev_out))); | 2608 | rt_genid(dev_net(dev_out))); |
2608 | err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); | 2609 | rth = rt_intern_hash(hash, rth, NULL, oldflp->oif); |
2609 | } | 2610 | } |
2610 | 2611 | ||
2611 | out: | 2612 | out: |
2612 | rcu_read_unlock(); | 2613 | rcu_read_unlock(); |
2613 | return err; | 2614 | return rth; |
2614 | } | 2615 | } |
2615 | 2616 | ||
2616 | int __ip_route_output_key(struct net *net, struct rtable **rp, | 2617 | struct rtable *__ip_route_output_key(struct net *net, const struct flowi *flp) |
2617 | const struct flowi *flp) | ||
2618 | { | 2618 | { |
2619 | struct rtable *rth; | 2619 | struct rtable *rth; |
2620 | unsigned int hash; | 2620 | unsigned int hash; |
@@ -2639,15 +2639,14 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, | |||
2639 | dst_use(&rth->dst, jiffies); | 2639 | dst_use(&rth->dst, jiffies); |
2640 | RT_CACHE_STAT_INC(out_hit); | 2640 | RT_CACHE_STAT_INC(out_hit); |
2641 | rcu_read_unlock_bh(); | 2641 | rcu_read_unlock_bh(); |
2642 | *rp = rth; | 2642 | return rth; |
2643 | return 0; | ||
2644 | } | 2643 | } |
2645 | RT_CACHE_STAT_INC(out_hlist_search); | 2644 | RT_CACHE_STAT_INC(out_hlist_search); |
2646 | } | 2645 | } |
2647 | rcu_read_unlock_bh(); | 2646 | rcu_read_unlock_bh(); |
2648 | 2647 | ||
2649 | slow_output: | 2648 | slow_output: |
2650 | return ip_route_output_slow(net, rp, flp); | 2649 | return ip_route_output_slow(net, flp); |
2651 | } | 2650 | } |
2652 | EXPORT_SYMBOL_GPL(__ip_route_output_key); | 2651 | EXPORT_SYMBOL_GPL(__ip_route_output_key); |
2653 | 2652 | ||
@@ -2717,34 +2716,29 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or | |||
2717 | return rt ? &rt->dst : ERR_PTR(-ENOMEM); | 2716 | return rt ? &rt->dst : ERR_PTR(-ENOMEM); |
2718 | } | 2717 | } |
2719 | 2718 | ||
2720 | int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, | 2719 | struct rtable *ip_route_output_flow(struct net *net, struct flowi *flp, |
2721 | struct sock *sk) | 2720 | struct sock *sk) |
2722 | { | 2721 | { |
2723 | int err; | 2722 | struct rtable *rt = __ip_route_output_key(net, flp); |
2724 | 2723 | ||
2725 | if ((err = __ip_route_output_key(net, rp, flp)) != 0) | 2724 | if (IS_ERR(rt)) |
2726 | return err; | 2725 | return rt; |
2727 | 2726 | ||
2728 | if (flp->proto) { | 2727 | if (flp->proto) { |
2729 | if (!flp->fl4_src) | 2728 | if (!flp->fl4_src) |
2730 | flp->fl4_src = (*rp)->rt_src; | 2729 | flp->fl4_src = rt->rt_src; |
2731 | if (!flp->fl4_dst) | 2730 | if (!flp->fl4_dst) |
2732 | flp->fl4_dst = (*rp)->rt_dst; | 2731 | flp->fl4_dst = rt->rt_dst; |
2733 | *rp = (struct rtable *) xfrm_lookup(net, &(*rp)->dst, flp, sk, 0); | 2732 | rt = (struct rtable *) xfrm_lookup(net, &rt->dst, flp, sk, 0); |
2734 | if (IS_ERR(*rp)) { | ||
2735 | err = PTR_ERR(*rp); | ||
2736 | *rp = NULL; | ||
2737 | return err; | ||
2738 | } | ||
2739 | } | 2733 | } |
2740 | 2734 | ||
2741 | return 0; | 2735 | return rt; |
2742 | } | 2736 | } |
2743 | EXPORT_SYMBOL_GPL(ip_route_output_flow); | 2737 | EXPORT_SYMBOL_GPL(ip_route_output_flow); |
2744 | 2738 | ||
2745 | int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp) | 2739 | struct rtable *ip_route_output_key(struct net *net, struct flowi *flp) |
2746 | { | 2740 | { |
2747 | return ip_route_output_flow(net, rp, flp, NULL); | 2741 | return ip_route_output_flow(net, flp, NULL); |
2748 | } | 2742 | } |
2749 | EXPORT_SYMBOL(ip_route_output_key); | 2743 | EXPORT_SYMBOL(ip_route_output_key); |
2750 | 2744 | ||
@@ -2915,7 +2909,11 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2915 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | 2909 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, |
2916 | .mark = mark, | 2910 | .mark = mark, |
2917 | }; | 2911 | }; |
2918 | err = ip_route_output_key(net, &rt, &fl); | 2912 | rt = ip_route_output_key(net, &fl); |
2913 | |||
2914 | err = 0; | ||
2915 | if (IS_ERR(rt)) | ||
2916 | err = PTR_ERR(rt); | ||
2919 | } | 2917 | } |
2920 | 2918 | ||
2921 | if (err) | 2919 | if (err) |