Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+14 −13
Original line number Diff line number Diff line
@@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
	struct net_device_stats *stats = &t->dev->stats;
	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
	struct ipv6_tel_txoption opt;
	struct dst_entry *dst;
	struct dst_entry *dst, *ndst = NULL;
	struct net_device *tdev;
	int mtu;
	unsigned int max_headroom = sizeof(struct ipv6hdr);
@@ -897,19 +897,19 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
	int err = -1;
	int pkt_len;

	if ((dst = ip6_tnl_dst_check(t)) != NULL)
		dst_hold(dst);
	else {
		dst = ip6_route_output(net, NULL, fl6);
	dst = ip6_tnl_dst_check(t);
	if (!dst) {
		ndst = ip6_route_output(net, NULL, fl6);

		if (dst->error)
		if (ndst->error)
			goto tx_err_link_failure;
		dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
		if (IS_ERR(dst)) {
			err = PTR_ERR(dst);
			dst = NULL;
		ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
		if (IS_ERR(ndst)) {
			err = PTR_ERR(ndst);
			ndst = NULL;
			goto tx_err_link_failure;
		}
		dst = ndst;
	}

	tdev = dst->dev;
@@ -955,7 +955,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
		skb = new_skb;
	}
	skb_dst_drop(skb);
	skb_dst_set(skb, dst_clone(dst));
	skb_dst_set_noref(skb, dst);

	skb->transport_header = skb->network_header;

@@ -987,13 +987,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
		stats->tx_errors++;
		stats->tx_aborted_errors++;
	}
	ip6_tnl_dst_store(t, dst);
	if (ndst)
		ip6_tnl_dst_store(t, ndst);
	return 0;
tx_err_link_failure:
	stats->tx_carrier_errors++;
	dst_link_failure(skb);
tx_err_dst_release:
	dst_release(dst);
	dst_release(ndst);
	return err;
}