aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-03-02 17:31:35 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-02 17:31:35 -0500
commitb23dd4fe42b455af5c6e20966b7d6959fa8352ea (patch)
treebf97323eae9a8d084170e573ff2c0c40bc72c3cd /net/ipv4/route.c
parent452edd598f60522c11f7f88fdbab27eb36509d1a (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.c100
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
1017static int rt_intern_hash(unsigned hash, struct rtable *rt, 1017static 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
1203skip_hashing: 1201skip_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
1211static atomic_t __rt_peer_genid = ATOMIC_INIT(0); 1207static 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
1901e_nobufs: 1900e_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
2200no_route: 2205no_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
2425static int ip_route_output_slow(struct net *net, struct rtable **rp, 2430static 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
2599make_route: 2602make_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
2611out: 2612out:
2612 rcu_read_unlock(); 2613 rcu_read_unlock();
2613 return err; 2614 return rth;
2614} 2615}
2615 2616
2616int __ip_route_output_key(struct net *net, struct rtable **rp, 2617struct 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
2649slow_output: 2648slow_output:
2650 return ip_route_output_slow(net, rp, flp); 2649 return ip_route_output_slow(net, flp);
2651} 2650}
2652EXPORT_SYMBOL_GPL(__ip_route_output_key); 2651EXPORT_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
2720int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, 2719struct 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}
2743EXPORT_SYMBOL_GPL(ip_route_output_flow); 2737EXPORT_SYMBOL_GPL(ip_route_output_flow);
2744 2738
2745int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp) 2739struct 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}
2749EXPORT_SYMBOL(ip_route_output_key); 2743EXPORT_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)