Skip to content

Commit 852e82e

Browse files
matttbePatchew Applier
authored and
Patchew Applier
committed
mptcp: fix full TCP keep-alive support
SO_KEEPALIVE support has been added a while ago, as part of a series "adding SOL_SOCKET" support. To have a full control of this keep-alive feature, it is important to also support TCP_KEEP* socket options at the SOL_TCP level. Supporting them on the setsockopt() part is easy, it is just a matter of remembering each value in the MPTCP sock structure, and calling tcp_sock_set_keep*() helpers on each subflow. If the value is not modified (0), calling these helpers will not do anything. For the getsockopt() part, the corresponding value from the MPTCP sock structure or the default one is simply returned. It looks important for kernels supporting SO_KEEPALIVE, to also support TCP_KEEP* options as well: some apps seem to (wrongly) consider that if the former is supported, the latter ones will be supported as well. But also, not having this simple and isolated change is preventing MPTCP support in some apps, and libraries like GoLang [1]. This is why this patch is seen as a fix. Closes: #383 Fixes: 1b3e7ed ("mptcp: setsockopt: handle SO_KEEPALIVE and SO_PRIORITY") Link: golang/go#56539 [1] Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> Message-Id: <20240508-mptcp-tcp-keepalive-sockopts-v1-2-fdf7e03e14c4@kernel.org>
1 parent 73f5f5a commit 852e82e

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

net/mptcp/protocol.h

+3
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ struct mptcp_sock {
309309
in_accept_queue:1,
310310
free_first:1,
311311
rcvspace_init:1;
312+
u8 keepalive_cnt;
313+
unsigned int keepalive_idle;
314+
unsigned int keepalive_intvl;
312315
u32 notsent_lowat;
313316
struct work_struct work;
314317
struct sk_buff *ooo_last_skb;

net/mptcp/sockopt.c

+57
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,30 @@ static int mptcp_setsockopt_sol_tcp_congestion(struct mptcp_sock *msk, sockptr_t
622622
return ret;
623623
}
624624

625+
static int __mptcp_setsockopt_set_val(struct mptcp_sock *msk, int max,
626+
int (*set_val)(struct sock *, int),
627+
unsigned int *msk_val, int val)
628+
{
629+
struct mptcp_subflow_context *subflow;
630+
int ret = 0;
631+
632+
if (val < 1 || val > max)
633+
return -EINVAL;
634+
635+
*msk_val = val;
636+
sockopt_seq_inc(msk);
637+
638+
mptcp_for_each_subflow(msk, subflow) {
639+
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
640+
641+
lock_sock(ssk);
642+
ret |= set_val(ssk, val);
643+
release_sock(ssk);
644+
}
645+
646+
return ret;
647+
}
648+
625649
static int __mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, int val)
626650
{
627651
struct mptcp_subflow_context *subflow;
@@ -818,6 +842,22 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
818842
case TCP_NODELAY:
819843
ret = __mptcp_setsockopt_sol_tcp_nodelay(msk, val);
820844
break;
845+
case TCP_KEEPIDLE:
846+
ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPIDLE,
847+
&tcp_sock_set_keepidle_locked,
848+
&msk->keepalive_idle, val);
849+
break;
850+
case TCP_KEEPINTVL:
851+
ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPINTVL,
852+
&tcp_sock_set_keepintvl,
853+
&msk->keepalive_intvl, val);
854+
break;
855+
case TCP_KEEPCNT:
856+
ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPCNT,
857+
&tcp_sock_set_keepcnt,
858+
(unsigned int *)&msk->keepalive_cnt,
859+
val);
860+
break;
821861
default:
822862
ret = -ENOPROTOOPT;
823863
}
@@ -1332,6 +1372,8 @@ static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval,
13321372
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
13331373
char __user *optval, int __user *optlen)
13341374
{
1375+
struct sock *sk = (void *)msk;
1376+
13351377
switch (optname) {
13361378
case TCP_ULP:
13371379
case TCP_CONGESTION:
@@ -1352,6 +1394,18 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
13521394
return mptcp_put_int_option(msk, optval, optlen, msk->nodelay);
13531395
case TCP_NOTSENT_LOWAT:
13541396
return mptcp_put_int_option(msk, optval, optlen, msk->notsent_lowat);
1397+
case TCP_KEEPIDLE:
1398+
return mptcp_put_int_option(msk, optval, optlen,
1399+
msk->keepalive_idle ? :
1400+
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_time) / HZ);
1401+
case TCP_KEEPINTVL:
1402+
return mptcp_put_int_option(msk, optval, optlen,
1403+
msk->keepalive_intvl ? :
1404+
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_intvl) / HZ);
1405+
case TCP_KEEPCNT:
1406+
return mptcp_put_int_option(msk, optval, optlen,
1407+
msk->keepalive_cnt ? :
1408+
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_probes));
13551409
}
13561410
return -EOPNOTSUPP;
13571411
}
@@ -1467,6 +1521,9 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
14671521
tcp_set_congestion_control(ssk, msk->ca_name, false, true);
14681522
__tcp_sock_set_cork(ssk, !!msk->cork);
14691523
__tcp_sock_set_nodelay(ssk, !!msk->nodelay);
1524+
tcp_sock_set_keepidle_locked(ssk, msk->keepalive_idle);
1525+
tcp_sock_set_keepintvl(ssk, msk->keepalive_intvl);
1526+
tcp_sock_set_keepcnt(ssk, msk->keepalive_cnt);
14701527

14711528
inet_assign_bit(TRANSPARENT, ssk, inet_test_bit(TRANSPARENT, sk));
14721529
inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));

0 commit comments

Comments
 (0)