aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-02 15:21:31 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-03 06:18:19 -0400
commit96d362202bfc0e5da78ee59b1645296fbca515f4 (patch)
treece3cc34d9a75f8c5d91ea9eb711993657d32af77 /net/ipv4/route.c
parentb5f7e7554753e2cc3ef3bef0271fdb32027df2ba (diff)
ipv4: RCU conversion of ip_route_input_slow/ip_route_input_mc
Avoid two atomic ops on struct in_device refcount per incoming packet, if slow path taken, (or route cache disabled) 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.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index d377b45005fc..1cfe0d199e7c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1843,13 +1843,14 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
1843 rt->rt_type = res->type; 1843 rt->rt_type = res->type;
1844} 1844}
1845 1845
1846/* called in rcu_read_lock() section */
1846static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, 1847static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1847 u8 tos, struct net_device *dev, int our) 1848 u8 tos, struct net_device *dev, int our)
1848{ 1849{
1849 unsigned hash; 1850 unsigned int hash;
1850 struct rtable *rth; 1851 struct rtable *rth;
1851 __be32 spec_dst; 1852 __be32 spec_dst;
1852 struct in_device *in_dev = in_dev_get(dev); 1853 struct in_device *in_dev = __in_dev_get_rcu(dev);
1853 u32 itag = 0; 1854 u32 itag = 0;
1854 int err; 1855 int err;
1855 1856
@@ -1914,18 +1915,14 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1914#endif 1915#endif
1915 RT_CACHE_STAT_INC(in_slow_mc); 1916 RT_CACHE_STAT_INC(in_slow_mc);
1916 1917
1917 in_dev_put(in_dev);
1918 hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); 1918 hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
1919 return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex); 1919 return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
1920 1920
1921e_nobufs: 1921e_nobufs:
1922 in_dev_put(in_dev);
1923 return -ENOBUFS; 1922 return -ENOBUFS;
1924
1925e_inval: 1923e_inval:
1926 err = -EINVAL; 1924 return -EINVAL;
1927e_err: 1925e_err:
1928 in_dev_put(in_dev);
1929 return err; 1926 return err;
1930} 1927}
1931 1928
@@ -2101,7 +2098,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2101 u8 tos, struct net_device *dev) 2098 u8 tos, struct net_device *dev)
2102{ 2099{
2103 struct fib_result res; 2100 struct fib_result res;
2104 struct in_device *in_dev = in_dev_get(dev); 2101 struct in_device *in_dev = __in_dev_get_rcu(dev);
2105 struct flowi fl = { .nl_u = { .ip4_u = 2102 struct flowi fl = { .nl_u = { .ip4_u =
2106 { .daddr = daddr, 2103 { .daddr = daddr,
2107 .saddr = saddr, 2104 .saddr = saddr,
@@ -2179,7 +2176,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2179 2176
2180 err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos); 2177 err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
2181done: 2178done:
2182 in_dev_put(in_dev);
2183 if (free_res) 2179 if (free_res)
2184 fib_res_put(&res); 2180 fib_res_put(&res);
2185out: return err; 2181out: return err;
@@ -2288,16 +2284,18 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2288 unsigned hash; 2284 unsigned hash;
2289 int iif = dev->ifindex; 2285 int iif = dev->ifindex;
2290 struct net *net; 2286 struct net *net;
2287 int res;
2291 2288
2292 net = dev_net(dev); 2289 net = dev_net(dev);
2293 2290
2291 rcu_read_lock();
2292
2294 if (!rt_caching(net)) 2293 if (!rt_caching(net))
2295 goto skip_cache; 2294 goto skip_cache;
2296 2295
2297 tos &= IPTOS_RT_MASK; 2296 tos &= IPTOS_RT_MASK;
2298 hash = rt_hash(daddr, saddr, iif, rt_genid(net)); 2297 hash = rt_hash(daddr, saddr, iif, rt_genid(net));
2299 2298
2300 rcu_read_lock();
2301 for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; 2299 for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
2302 rth = rcu_dereference(rth->u.dst.rt_next)) { 2300 rth = rcu_dereference(rth->u.dst.rt_next)) {
2303 if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) | 2301 if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
@@ -2321,7 +2319,6 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2321 } 2319 }
2322 RT_CACHE_STAT_INC(in_hlist_search); 2320 RT_CACHE_STAT_INC(in_hlist_search);
2323 } 2321 }
2324 rcu_read_unlock();
2325 2322
2326skip_cache: 2323skip_cache:
2327 /* Multicast recognition logic is moved from route cache to here. 2324 /* Multicast recognition logic is moved from route cache to here.
@@ -2336,12 +2333,11 @@ skip_cache:
2336 route cache entry is created eventually. 2333 route cache entry is created eventually.
2337 */ 2334 */
2338 if (ipv4_is_multicast(daddr)) { 2335 if (ipv4_is_multicast(daddr)) {
2339 struct in_device *in_dev; 2336 struct in_device *in_dev = __in_dev_get_rcu(dev);
2340 2337
2341 rcu_read_lock(); 2338 if (in_dev) {
2342 if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
2343 int our = ip_check_mc(in_dev, daddr, saddr, 2339 int our = ip_check_mc(in_dev, daddr, saddr,
2344 ip_hdr(skb)->protocol); 2340 ip_hdr(skb)->protocol);
2345 if (our 2341 if (our
2346#ifdef CONFIG_IP_MROUTE 2342#ifdef CONFIG_IP_MROUTE
2347 || 2343 ||
@@ -2349,15 +2345,18 @@ skip_cache:
2349 IN_DEV_MFORWARD(in_dev)) 2345 IN_DEV_MFORWARD(in_dev))
2350#endif 2346#endif
2351 ) { 2347 ) {
2348 int res = ip_route_input_mc(skb, daddr, saddr,
2349 tos, dev, our);
2352 rcu_read_unlock(); 2350 rcu_read_unlock();
2353 return ip_route_input_mc(skb, daddr, saddr, 2351 return res;
2354 tos, dev, our);
2355 } 2352 }
2356 } 2353 }
2357 rcu_read_unlock(); 2354 rcu_read_unlock();
2358 return -EINVAL; 2355 return -EINVAL;
2359 } 2356 }
2360 return ip_route_input_slow(skb, daddr, saddr, tos, dev); 2357 res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
2358 rcu_read_unlock();
2359 return res;
2361} 2360}
2362EXPORT_SYMBOL(ip_route_input_common); 2361EXPORT_SYMBOL(ip_route_input_common);
2363 2362