Skip to content

Commit

Permalink
inet: implement lockless IP_MULTICAST_TTL
Browse files Browse the repository at this point in the history
inet->mc_ttl can be read locklessly.

Implement proper lockless reads and writes to inet->mc_ttl

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and davem330 committed Oct 1, 2023
1 parent 2be825e commit c9746e6
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 17 deletions.
2 changes: 1 addition & 1 deletion net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
if (cork->ttl != 0)
ttl = cork->ttl;
else if (rt->rt_type == RTN_MULTICAST)
ttl = inet->mc_ttl;
ttl = READ_ONCE(inet->mc_ttl);
else
ttl = ip_select_ttl(inet, &rt->dst);

Expand Down
31 changes: 16 additions & 15 deletions net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,17 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,

WRITE_ONCE(inet->min_ttl, val);
return 0;
case IP_MULTICAST_TTL:
if (sk->sk_type == SOCK_STREAM)
return -EINVAL;
if (optlen < 1)
return -EINVAL;
if (val == -1)
val = 1;
if (val < 0 || val > 255)
return -EINVAL;
WRITE_ONCE(inet->mc_ttl, val);
return 0;
}

err = 0;
Expand Down Expand Up @@ -1101,17 +1112,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
goto e_inval;
inet->pmtudisc = val;
break;
case IP_MULTICAST_TTL:
if (sk->sk_type == SOCK_STREAM)
goto e_inval;
if (optlen < 1)
goto e_inval;
if (val == -1)
val = 1;
if (val < 0 || val > 255)
goto e_inval;
inet->mc_ttl = val;
break;
case IP_UNICAST_IF:
{
struct net_device *dev = NULL;
Expand Down Expand Up @@ -1592,6 +1592,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_MINTTL:
val = READ_ONCE(inet->min_ttl);
goto copyval;
case IP_MULTICAST_TTL:
val = READ_ONCE(inet->mc_ttl);
goto copyval;
}

if (needs_rtnl)
Expand Down Expand Up @@ -1649,9 +1652,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
}
break;
}
case IP_MULTICAST_TTL:
val = inet->mc_ttl;
break;
case IP_UNICAST_IF:
val = (__force int)htonl((__u32) inet->uc_index);
break;
Expand Down Expand Up @@ -1718,7 +1718,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
}
if (inet_test_bit(TTL, sk)) {
int hlim = inet->mc_ttl;
int hlim = READ_ONCE(inet->mc_ttl);

put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
}
if (inet_test_bit(TOS, sk)) {
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/ipvs/ip_vs_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -1316,7 +1316,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl)

/* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
lock_sock(sk);
inet->mc_ttl = ttl;
WRITE_ONCE(inet->mc_ttl, ttl);
#ifdef CONFIG_IP_VS_IPV6
if (sk->sk_family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
Expand Down

0 comments on commit c9746e6

Please sign in to comment.