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

inet: implement lockless IP_MULTICAST_TTL

inet->mc_ttl can be read locklessly.

Implement proper lockless reads and writes to inet->mc_ttl
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2be825eb
...@@ -1430,7 +1430,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk, ...@@ -1430,7 +1430,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
if (cork->ttl != 0) if (cork->ttl != 0)
ttl = cork->ttl; ttl = cork->ttl;
else if (rt->rt_type == RTN_MULTICAST) else if (rt->rt_type == RTN_MULTICAST)
ttl = inet->mc_ttl; ttl = READ_ONCE(inet->mc_ttl);
else else
ttl = ip_select_ttl(inet, &rt->dst); ttl = ip_select_ttl(inet, &rt->dst);
......
...@@ -1039,6 +1039,17 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, ...@@ -1039,6 +1039,17 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
WRITE_ONCE(inet->min_ttl, val); WRITE_ONCE(inet->min_ttl, val);
return 0; 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; err = 0;
...@@ -1101,17 +1112,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, ...@@ -1101,17 +1112,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
goto e_inval; goto e_inval;
inet->pmtudisc = val; inet->pmtudisc = val;
break; 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: case IP_UNICAST_IF:
{ {
struct net_device *dev = NULL; struct net_device *dev = NULL;
...@@ -1592,6 +1592,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1592,6 +1592,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_MINTTL: case IP_MINTTL:
val = READ_ONCE(inet->min_ttl); val = READ_ONCE(inet->min_ttl);
goto copyval; goto copyval;
case IP_MULTICAST_TTL:
val = READ_ONCE(inet->mc_ttl);
goto copyval;
} }
if (needs_rtnl) if (needs_rtnl)
...@@ -1649,9 +1652,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -1649,9 +1652,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
} }
break; break;
} }
case IP_MULTICAST_TTL:
val = inet->mc_ttl;
break;
case IP_UNICAST_IF: case IP_UNICAST_IF:
val = (__force int)htonl((__u32) inet->uc_index); val = (__force int)htonl((__u32) inet->uc_index);
break; break;
...@@ -1718,7 +1718,8 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, ...@@ -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); put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
} }
if (inet_test_bit(TTL, sk)) { 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); put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
} }
if (inet_test_bit(TOS, sk)) { if (inet_test_bit(TOS, sk)) {
......
...@@ -1316,7 +1316,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl) ...@@ -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)); */ /* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
lock_sock(sk); lock_sock(sk);
inet->mc_ttl = ttl; WRITE_ONCE(inet->mc_ttl, ttl);
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (sk->sk_family == AF_INET6) { if (sk->sk_family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
......
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