aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-07-28 00:32:25 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-01 03:12:00 -0400
commit89b0212697e92bc59a021a2338cd8c09f919325c (patch)
tree633279786602d3677ea5c4959528aa00219afed2 /net/ipv6
parent897dc80b951e996ba4d26c0038e81a505b92aec1 (diff)
ip6tnl: avoid touching dst refcount in ip6_tnl_xmit2()
Even using percpu stats, we still hit tunnel dst_entry refcount in ip6_tnl_xmit2() Since we are in RCU locked section, we can use skb_dst_set_noref() and avoid these atomic operations, leaving dst shared on cpus. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_tunnel.c27
1 files changed, 14 insertions, 13 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 0bc98886c383..6fb1fb3624bf 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
889 struct net_device_stats *stats = &t->dev->stats; 889 struct net_device_stats *stats = &t->dev->stats;
890 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 890 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
891 struct ipv6_tel_txoption opt; 891 struct ipv6_tel_txoption opt;
892 struct dst_entry *dst; 892 struct dst_entry *dst, *ndst = NULL;
893 struct net_device *tdev; 893 struct net_device *tdev;
894 int mtu; 894 int mtu;
895 unsigned int max_headroom = sizeof(struct ipv6hdr); 895 unsigned int max_headroom = sizeof(struct ipv6hdr);
@@ -897,19 +897,19 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
897 int err = -1; 897 int err = -1;
898 int pkt_len; 898 int pkt_len;
899 899
900 if ((dst = ip6_tnl_dst_check(t)) != NULL) 900 dst = ip6_tnl_dst_check(t);
901 dst_hold(dst); 901 if (!dst) {
902 else { 902 ndst = ip6_route_output(net, NULL, fl6);
903 dst = ip6_route_output(net, NULL, fl6);
904 903
905 if (dst->error) 904 if (ndst->error)
906 goto tx_err_link_failure; 905 goto tx_err_link_failure;
907 dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0); 906 ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
908 if (IS_ERR(dst)) { 907 if (IS_ERR(ndst)) {
909 err = PTR_ERR(dst); 908 err = PTR_ERR(ndst);
910 dst = NULL; 909 ndst = NULL;
911 goto tx_err_link_failure; 910 goto tx_err_link_failure;
912 } 911 }
912 dst = ndst;
913 } 913 }
914 914
915 tdev = dst->dev; 915 tdev = dst->dev;
@@ -955,7 +955,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
955 skb = new_skb; 955 skb = new_skb;
956 } 956 }
957 skb_dst_drop(skb); 957 skb_dst_drop(skb);
958 skb_dst_set(skb, dst_clone(dst)); 958 skb_dst_set_noref(skb, dst);
959 959
960 skb->transport_header = skb->network_header; 960 skb->transport_header = skb->network_header;
961 961
@@ -987,13 +987,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
987 stats->tx_errors++; 987 stats->tx_errors++;
988 stats->tx_aborted_errors++; 988 stats->tx_aborted_errors++;
989 } 989 }
990 ip6_tnl_dst_store(t, dst); 990 if (ndst)
991 ip6_tnl_dst_store(t, ndst);
991 return 0; 992 return 0;
992tx_err_link_failure: 993tx_err_link_failure:
993 stats->tx_carrier_errors++; 994 stats->tx_carrier_errors++;
994 dst_link_failure(skb); 995 dst_link_failure(skb);
995tx_err_dst_release: 996tx_err_dst_release:
996 dst_release(dst); 997 dst_release(ndst);
997 return err; 998 return err;
998} 999}
999 1000