diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-05-10 07:31:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-17 20:18:52 -0400 |
commit | ab6e3feba1f1bc3b9418b854da6f481408d243de (patch) | |
tree | 18977292fa858067f7cc4d7a7df8a69dd5562a3d /net | |
parent | 4a94445c9a5cf5461fb41d80040033b9a8e2a85a (diff) |
net: No dst refcounting in ip_queue_xmit()
TCP outgoing packets can avoid two atomic ops, and dirtying
of previously higly contended cache line using new refdst
infrastructure.
Note 1: loopback device excluded because of !IFF_XMIT_DST_RELEASE
Note 2: UDP packets dsts are built before ip_queue_xmit().
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/ip_output.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 252897443ef9..9a4a6c96cb0d 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -318,10 +318,12 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
318 | struct ip_options *opt = inet->opt; | 318 | struct ip_options *opt = inet->opt; |
319 | struct rtable *rt; | 319 | struct rtable *rt; |
320 | struct iphdr *iph; | 320 | struct iphdr *iph; |
321 | int res; | ||
321 | 322 | ||
322 | /* Skip all of this if the packet is already routed, | 323 | /* Skip all of this if the packet is already routed, |
323 | * f.e. by something like SCTP. | 324 | * f.e. by something like SCTP. |
324 | */ | 325 | */ |
326 | rcu_read_lock(); | ||
325 | rt = skb_rtable(skb); | 327 | rt = skb_rtable(skb); |
326 | if (rt != NULL) | 328 | if (rt != NULL) |
327 | goto packet_routed; | 329 | goto packet_routed; |
@@ -359,7 +361,7 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
359 | } | 361 | } |
360 | sk_setup_caps(sk, &rt->u.dst); | 362 | sk_setup_caps(sk, &rt->u.dst); |
361 | } | 363 | } |
362 | skb_dst_set(skb, dst_clone(&rt->u.dst)); | 364 | skb_dst_set_noref(skb, &rt->u.dst); |
363 | 365 | ||
364 | packet_routed: | 366 | packet_routed: |
365 | if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) | 367 | if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) |
@@ -391,9 +393,12 @@ packet_routed: | |||
391 | skb->priority = sk->sk_priority; | 393 | skb->priority = sk->sk_priority; |
392 | skb->mark = sk->sk_mark; | 394 | skb->mark = sk->sk_mark; |
393 | 395 | ||
394 | return ip_local_out(skb); | 396 | res = ip_local_out(skb); |
397 | rcu_read_unlock(); | ||
398 | return res; | ||
395 | 399 | ||
396 | no_route: | 400 | no_route: |
401 | rcu_read_unlock(); | ||
397 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 402 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
398 | kfree_skb(skb); | 403 | kfree_skb(skb); |
399 | return -EHOSTUNREACH; | 404 | return -EHOSTUNREACH; |