From: Eggert, Lars <hidden> Date: 2016-06-10 11:22:59
Hi,
I see an issue with TCP_REPAIR on kernel 4.6.0, where a migrated connection is only sending minimum-sized segments (~500 bytes), although the interfaces and path support Ethernet-sized MTUs. A connection that doesn't use TCP_REPAIR over the same path uses full-sized segments.
Know issue? Any workaround?
Thanks,
Lars
From: Eggert, Lars <hidden> Date: 2016-06-14 11:40:05
On 2016-06-14, at 13:28, Pavel Emelyanov [off-list ref] wrote:
Andrey (in Cc) has played with TCP_REPAIR recently, I guess he can know something.
Thanks for CC'ing him. We looked a little bit more into this:
When TCP_REPAIR is on, tcp_connect() directly calls tcp_finish_connect() before returning, passing NULL for skb, which causes sk_rx_dst_set() to be bypassed. Later, when TCP_REPAIR is being turned off, do_tcp_setsockopt() just does tcp_send_window_probe(), but apparently all the "dst" stuff is being bypassed then also, so the mss remains at TCP_MSS_DEFAULT.
Lars
From: Pavel Emelyanov <hidden> Date: 2016-06-14 11:56:37
On 06/10/2016 02:22 PM, Eggert, Lars wrote:
Hi,
I see an issue with TCP_REPAIR on kernel 4.6.0, where a migrated connection is only sending minimum-sized
segments (~500 bytes), although the interfaces and path support Ethernet-sized MTUs. A connection that
doesn't use TCP_REPAIR over the same path uses full-sized segments.
Know issue? Any workaround?
Andrey (in Cc) has played with TCP_REPAIR recently, I guess he can know something.
From: Eric Dumazet <hidden> Date: 2016-06-14 13:03:38
On Tue, 2016-06-14 at 11:40 +0000, Eggert, Lars wrote:
On 2016-06-14, at 13:28, Pavel Emelyanov [off-list ref] wrote:
quoted
Andrey (in Cc) has played with TCP_REPAIR recently, I guess he can know something.
Thanks for CC'ing him. We looked a little bit more into this:
When TCP_REPAIR is on, tcp_connect() directly calls tcp_finish_connect() before returning, passing NULL for skb, which causes sk_rx_dst_set() to be bypassed. Later, when TCP_REPAIR is being turned off, do_tcp_setsockopt() just does tcp_send_window_probe(), but apparently all the "dst" stuff is being bypassed then also, so the mss remains at TCP_MSS_DEFAULT.
Lars
What gives :
sysctl net/ipv4/ip_no_pmtu_disc net/ipv4/tcp_mtu_probing
From: Eric Dumazet <hidden> Date: 2016-06-14 13:10:05
On Tue, 2016-06-14 at 06:03 -0700, Eric Dumazet wrote:
On Tue, 2016-06-14 at 11:40 +0000, Eggert, Lars wrote:
quoted
On 2016-06-14, at 13:28, Pavel Emelyanov [off-list ref] wrote:
quoted
Andrey (in Cc) has played with TCP_REPAIR recently, I guess he can know something.
Thanks for CC'ing him. We looked a little bit more into this:
When TCP_REPAIR is on, tcp_connect() directly calls tcp_finish_connect() before returning, passing NULL for skb, which causes sk_rx_dst_set() to be bypassed. Later, when TCP_REPAIR is being turned off, do_tcp_setsockopt() just does tcp_send_window_probe(), but apparently all the "dst" stuff is being bypassed then also, so the mss remains at TCP_MSS_DEFAULT.
Lars
What gives :
sysctl net/ipv4/ip_no_pmtu_disc net/ipv4/tcp_mtu_probing
Also, is it a regression ? Was this working better with an older linux
version ?
Hi,
Recently we found that we have to restore more parameters for tcp
sockets.
https://patchwork.kernel.org/patch/9144995/
As for your problem, criu saves and restores mss_clamp. Could you check
that it works for your case?
on dump:
static int tcp_stream_get_options(int sk, struct tcp_info *ti,
TcpStreamEntry *tse)
{
int ret;
socklen_t auxl;
int val;
auxl = sizeof(tse->mss_clamp);
ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
if (ret < 0)
goto err_sopt;
on restore:
pr_debug("Will set mss clamp to %u\n", tse->mss_clamp);
opts[onr].opt_code = TCPOPT_MAXSEG;
opts[onr].opt_val = tse->mss_clamp;
onr++;
if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS,
opts, onr * sizeof(struct tcp_repair_opt)) < 0) {
pr_perror("Can't repair options");
return -1;
}
Thanks,
Andrew
On Tue, Jun 14, 2016 at 11:40:01AM +0000, Eggert, Lars wrote:
On 2016-06-14, at 13:28, Pavel Emelyanov [off-list ref] wrote:
quoted
Andrey (in Cc) has played with TCP_REPAIR recently, I guess he can know something.
Thanks for CC'ing him. We looked a little bit more into this:
When TCP_REPAIR is on, tcp_connect() directly calls tcp_finish_connect() before returning, passing NULL for skb, which causes sk_rx_dst_set() to be bypassed. Later, when TCP_REPAIR is being turned off, do_tcp_setsockopt() just does tcp_send_window_probe(), but apparently all the "dst" stuff is being bypassed then also, so the mss remains at TCP_MSS_DEFAULT.
Lars
From: Eggert, Lars <hidden> Date: 2016-06-16 07:51:25
Hi,
On 2016-06-14, at 23:21, Andrey Vagin [off-list ref] wrote:
On my host, I see that dst is set in tcp_v4_connect() -> sk_setup_caps()
sorry, are you saying that you don't see the issue with TCP_MSS_DEFAULT-sized segments after TCP_REPAIR on your kernel? Or are you saying my quick attempt at analyzing the cause was wrong?
Thanks,
Lars
On Thu, Jun 16, 2016 at 07:51:22AM +0000, Eggert, Lars wrote:
Hi,
On 2016-06-14, at 23:21, Andrey Vagin [off-list ref] wrote:
quoted
On my host, I see that dst is set in tcp_v4_connect() -> sk_setup_caps()
sorry, are you saying that you don't see the issue with TCP_MSS_DEFAULT-sized segments after TCP_REPAIR on your kernel? Or are you saying my quick attempt at analyzing the cause was wrong?
I can't reproduce this issue, now I'm trying to understand why it works
for me and doesn't work for you.
I've read you version of a reason:
When TCP_REPAIR is on, tcp_connect() directly calls tcp_finish_connect() before
returning, passing NULL for skb, which causes sk_rx_dst_set() to be bypassed.
Later, when TCP_REPAIR is being turned off, do_tcp_setsockopt() just does
tcp_send_window_probe(), but apparently all the "dst" stuff is being bypassed
then also, so the mss remains at TCP_MSS_DEFAULT.
I found where dst is set for a socket when a tcp connection is restored. Then I
added a debug message into tcp_sync_mss and found that mss is intialized to
TCP_MSS_DEFAULT, but then it's updated after unlocking network. So here is a
question why mss isn't updated in your case.
From: Eggert, Lars <hidden> Date: 2016-07-18 09:06:07
Hi,
On 2016-06-16, at 23:09, Andrey Vagin [off-list ref] wrote:
I can't reproduce this issue, now I'm trying to understand why it works
for me and doesn't work for you.
just to conclude this thread for the list:
Andrey and me debugged this off-list. The issue arose, because my code did a bind() to 0.0.0.0 in TCP_REPAIR mode. When turning off TCP_REPAIR and sending into the socket, this caused minimum-MSS-sized segments to be transmitted. The issue goes away when I bind() to the local IP address of my local egress interface.
To me at least, this is a POLA violation (excuse the FreeBSD terminology :-) Either binding to 0.0.0.0 should fail, or it should succeed and full-sized segments should be sent. But at least I have a work-around now.
Thanks,
Lars