Commit 89b02126 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 897dc80b
...@@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ...@@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
struct net_device_stats *stats = &t->dev->stats; struct net_device_stats *stats = &t->dev->stats;
struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ipv6_tel_txoption opt; struct ipv6_tel_txoption opt;
struct dst_entry *dst; struct dst_entry *dst, *ndst = NULL;
struct net_device *tdev; struct net_device *tdev;
int mtu; int mtu;
unsigned int max_headroom = sizeof(struct ipv6hdr); unsigned int max_headroom = sizeof(struct ipv6hdr);
...@@ -897,19 +897,19 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ...@@ -897,19 +897,19 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
int err = -1; int err = -1;
int pkt_len; int pkt_len;
if ((dst = ip6_tnl_dst_check(t)) != NULL) dst = ip6_tnl_dst_check(t);
dst_hold(dst); if (!dst) {
else { ndst = ip6_route_output(net, NULL, fl6);
dst = ip6_route_output(net, NULL, fl6);
if (dst->error) if (ndst->error)
goto tx_err_link_failure; goto tx_err_link_failure;
dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0); ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
if (IS_ERR(dst)) { if (IS_ERR(ndst)) {
err = PTR_ERR(dst); err = PTR_ERR(ndst);
dst = NULL; ndst = NULL;
goto tx_err_link_failure; goto tx_err_link_failure;
} }
dst = ndst;
} }
tdev = dst->dev; tdev = dst->dev;
...@@ -955,7 +955,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ...@@ -955,7 +955,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
skb = new_skb; skb = new_skb;
} }
skb_dst_drop(skb); skb_dst_drop(skb);
skb_dst_set(skb, dst_clone(dst)); skb_dst_set_noref(skb, dst);
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
...@@ -987,13 +987,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ...@@ -987,13 +987,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
stats->tx_errors++; stats->tx_errors++;
stats->tx_aborted_errors++; stats->tx_aborted_errors++;
} }
ip6_tnl_dst_store(t, dst); if (ndst)
ip6_tnl_dst_store(t, ndst);
return 0; return 0;
tx_err_link_failure: tx_err_link_failure:
stats->tx_carrier_errors++; stats->tx_carrier_errors++;
dst_link_failure(skb); dst_link_failure(skb);
tx_err_dst_release: tx_err_dst_release:
dst_release(dst); dst_release(ndst);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment