ip6_tunnel: annotate data-races around t->err_count and t->err_time

ip6_tnl_xmit() and ipip6_tunnel_xmit() run locklessly (dev->lltx == true).

ip6gre_err() and ipip6_err() also run locklessly.

We need to add READ_ONCE() and WRITE_ONCE() annotations
around t->err_count and t->err_time.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260610171458.1359630-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-06-10 17:14:58 +00:00 committed by Jakub Kicinski
parent 9bbdc7dc40
commit f6033078a9
3 changed files with 22 additions and 19 deletions

View File

@ -445,11 +445,11 @@ static int ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO))
t->err_count++;
if (time_before(jiffies, READ_ONCE(t->err_time) + IP6TUNNEL_ERR_TIMEO))
WRITE_ONCE(t->err_count, READ_ONCE(t->err_count) + 1);
else
t->err_count = 1;
t->err_time = jiffies;
WRITE_ONCE(t->err_count, 1);
WRITE_ONCE(t->err_time, jiffies);
return 0;
}

View File

@ -1104,7 +1104,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
struct ipv6_tel_txoption opt;
struct dst_entry *dst = NULL, *ndst = NULL;
struct net_device *tdev;
int mtu;
int err_count, mtu;
unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0;
unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen;
unsigned int max_headroom = psh_hlen;
@ -1214,14 +1214,15 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
goto tx_err_dst_release;
}
if (t->err_count > 0) {
err_count = READ_ONCE(t->err_count);
if (err_count > 0) {
if (time_before(jiffies,
t->err_time + IP6TUNNEL_ERR_TIMEO)) {
t->err_count--;
READ_ONCE(t->err_time) + IP6TUNNEL_ERR_TIMEO)) {
WRITE_ONCE(t->err_count, err_count - 1);
dst_link_failure(skb);
} else {
t->err_count = 0;
WRITE_ONCE(t->err_count, 0);
}
}

View File

@ -595,11 +595,11 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
goto out;
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
t->err_count++;
if (time_before(jiffies, READ_ONCE(t->err_time) + IPTUNNEL_ERR_TIMEO))
WRITE_ONCE(t->err_count, READ_ONCE(t->err_count) + 1);
else
t->err_count = 1;
t->err_time = jiffies;
WRITE_ONCE(t->err_count, 1);
WRITE_ONCE(t->err_time, jiffies);
out:
return err;
}
@ -909,8 +909,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct net_device *tdev; /* Device to other host */
unsigned int max_headroom; /* The extra header space needed */
__be32 dst = tiph->daddr;
int err_count, mtu;
struct flowi4 fl4;
int mtu;
u8 ttl;
u8 protocol = IPPROTO_IPV6;
int t_hlen = tunnel->hlen + sizeof(struct iphdr);
@ -987,13 +987,15 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
}
if (tunnel->err_count > 0) {
err_count = READ_ONCE(tunnel->err_count);
if (err_count > 0) {
if (time_before(jiffies,
tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
tunnel->err_count--;
READ_ONCE(tunnel->err_time) + IPTUNNEL_ERR_TIMEO)) {
WRITE_ONCE(tunnel->err_count, err_count - 1);
dst_link_failure(skb);
} else
tunnel->err_count = 0;
} else {
WRITE_ONCE(tunnel->err_count, 0);
}
}
/*