* NAT stops forwarding ACKs after PMTU discovery @ 2013-08-18 5:55 Corey Hickey 2013-08-18 15:24 ` Eric Dumazet 0 siblings, 1 reply; 32+ messages in thread From: Corey Hickey @ 2013-08-18 5:55 UTC (permalink / raw) To: Linux Netdev List Hi, If there is a better user-oriented list I should ask this question on, please tell me; I've asked a couple similar questions on netdev before and gotten some great help. I'm having a problem wherein some NATted connections stop forwarding packets. I've troubleshot the problem far enough to tell that it happens when path MTU discovery happens--the ACK to the retransmitted packet never gets forwarded back to my local client (and neither do the retransmitted ACKs). This is my setup: ---------------------------------------------------------------------- MTU 9100 MTU 1355 MTU 1500 client --> linux router --> vpn --> work host 198.18.0.3 198.18.0.1 (eth0) 10.15.24.13 192.168.61.54 (tun0) ---------------------------------------------------------------------- I'm running openconnect on a Linux router to connect to a cisco VPN at work. The Linux router does SNAT (MASQUERADE) over the virtual tun0 interface created by openconnect. This is the best test I have so far: $ sudo ip route flush cache ; ssh workhost.example.com exit Read from socket failed: Connection reset by peer Most of the time, this hangs for a few minutes before giving up; sometimes it just works fine. tcpdumps indicate that when it works, all packets transmitted are below the VPN's MTU; when it fails, MTU discovery has happened: 1. client sends large packet, for example 1832 bytes 2. router sends ICMP fragmentation needed 3. client retransmits with a smaller packet, for example 1303 bytes 4. router forwards packet over VPN 5. work host ACKs packet 6. router receives ACK but does not forward it 7. both endpoints retransmit, but ACKs never get forwarded The NAT table maintains an entry throughout (and continues to SNAT retransmits from the client), but the ACKs from the server never get forwarded. fire:~# netstat-nat -n -d 10.15.24.13 Proto NATed Address Destination Address State tcp 198.18.0.3:51076 10.15.24.13:22 ESTABLISHED I put a LOG target on the INPUT chain, though, and apparently these packets are bypassing the NAT; the kernel does not think they should be forwarded (else they would be on the FORWARD chain). [23335.509084] IN=tun0 OUT= MAC= SRC=10.15.24.13 DST=192.168.61.54 LEN=64 TOS=0x00 PREC=0x00 TTL=62 ID=28270 DF PROTO=TCP SPT=22 DPT=51076 WINDOW=134 RES=0x00 ACK FIN URGP=0 The kernel on the router is 3.10-2-amd64 (from Debian testing). I had the same problem with 3.2.0-4-amd64 (from Debian stable), before I tried to see if I could upgrade the problem away. Any help would be much appreciated. I can send full tcpdumps if needed. Thanks, Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-18 5:55 NAT stops forwarding ACKs after PMTU discovery Corey Hickey @ 2013-08-18 15:24 ` Eric Dumazet 2013-08-18 16:59 ` Corey Hickey 2013-08-18 21:23 ` Jozsef Kadlecsik 0 siblings, 2 replies; 32+ messages in thread From: Eric Dumazet @ 2013-08-18 15:24 UTC (permalink / raw) To: Corey Hickey; +Cc: Linux Netdev List, netfilter-devel On Sat, 2013-08-17 at 22:55 -0700, Corey Hickey wrote: > Hi, > > If there is a better user-oriented list I should ask this question on, > please tell me; I've asked a couple similar questions on netdev before > and gotten some great help. > > > I'm having a problem wherein some NATted connections stop forwarding > packets. I've troubleshot the problem far enough to tell that it happens > when path MTU discovery happens--the ACK to the retransmitted packet > never gets forwarded back to my local client (and neither do the > retransmitted ACKs). > > This is my setup: > ---------------------------------------------------------------------- > MTU 9100 MTU 1355 MTU 1500 > client --> linux router --> vpn --> work host > 198.18.0.3 198.18.0.1 (eth0) 10.15.24.13 > 192.168.61.54 (tun0) > ---------------------------------------------------------------------- > > I'm running openconnect on a Linux router to connect to a cisco VPN at > work. The Linux router does SNAT (MASQUERADE) over the virtual tun0 > interface created by openconnect. > > This is the best test I have so far: > > $ sudo ip route flush cache ; ssh workhost.example.com exit > Read from socket failed: Connection reset by peer > > Most of the time, this hangs for a few minutes before giving up; > sometimes it just works fine. tcpdumps indicate that when it works, all > packets transmitted are below the VPN's MTU; when it fails, MTU > discovery has happened: > > 1. client sends large packet, for example 1832 bytes > 2. router sends ICMP fragmentation needed > 3. client retransmits with a smaller packet, for example 1303 bytes > 4. router forwards packet over VPN > 5. work host ACKs packet > 6. router receives ACK but does not forward it > 7. both endpoints retransmit, but ACKs never get forwarded > > The NAT table maintains an entry throughout (and continues to SNAT > retransmits from the client), but the ACKs from the server never get > forwarded. > > fire:~# netstat-nat -n -d 10.15.24.13 > Proto NATed Address Destination Address State > tcp 198.18.0.3:51076 10.15.24.13:22 ESTABLISHED > > > I put a LOG target on the INPUT chain, though, and apparently these > packets are bypassing the NAT; the kernel does not think they should be > forwarded (else they would be on the FORWARD chain). > > [23335.509084] IN=tun0 OUT= MAC= SRC=10.15.24.13 DST=192.168.61.54 > LEN=64 TOS=0x00 PREC=0x00 TTL=62 ID=28270 DF PROTO=TCP SPT=22 DPT=51076 > WINDOW=134 RES=0x00 ACK FIN URGP=0 > > > The kernel on the router is 3.10-2-amd64 (from Debian testing). I had > the same problem with 3.2.0-4-amd64 (from Debian stable), before I tried > to see if I could upgrade the problem away. > > Any help would be much appreciated. I can send full tcpdumps if needed. This looks like the bug we had to fix recently : http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=356d7d88e088687b6578ca64601b0a2c9d145296 Could you try latest net tree ? ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-18 15:24 ` Eric Dumazet @ 2013-08-18 16:59 ` Corey Hickey 2013-08-18 21:23 ` Jozsef Kadlecsik 1 sibling, 0 replies; 32+ messages in thread From: Corey Hickey @ 2013-08-18 16:59 UTC (permalink / raw) To: Eric Dumazet; +Cc: Linux Netdev List, netfilter-devel On 2013-08-18 08:24, Eric Dumazet wrote: > This looks like the bug we had to fix recently : > > http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=356d7d88e088687b6578ca64601b0a2c9d145296 > > Could you try latest net tree ? Thanks, I will do so, hopefully this evening (busy today). -Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-18 15:24 ` Eric Dumazet 2013-08-18 16:59 ` Corey Hickey @ 2013-08-18 21:23 ` Jozsef Kadlecsik 2013-08-19 0:00 ` Eric Dumazet 1 sibling, 1 reply; 32+ messages in thread From: Jozsef Kadlecsik @ 2013-08-18 21:23 UTC (permalink / raw) To: Eric Dumazet; +Cc: Corey Hickey, Linux Netdev List, netfilter-devel On Sun, 18 Aug 2013, Eric Dumazet wrote: > On Sat, 2013-08-17 at 22:55 -0700, Corey Hickey wrote: > > Hi, > > > > If there is a better user-oriented list I should ask this question on, > > please tell me; I've asked a couple similar questions on netdev before > > and gotten some great help. > > > > > > I'm having a problem wherein some NATted connections stop forwarding > > packets. I've troubleshot the problem far enough to tell that it happens > > when path MTU discovery happens--the ACK to the retransmitted packet > > never gets forwarded back to my local client (and neither do the > > retransmitted ACKs). > > > > This is my setup: > > ---------------------------------------------------------------------- > > MTU 9100 MTU 1355 MTU 1500 > > client --> linux router --> vpn --> work host > > 198.18.0.3 198.18.0.1 (eth0) 10.15.24.13 > > 192.168.61.54 (tun0) > > ---------------------------------------------------------------------- > > > > I'm running openconnect on a Linux router to connect to a cisco VPN at > > work. The Linux router does SNAT (MASQUERADE) over the virtual tun0 > > interface created by openconnect. > > > > This is the best test I have so far: > > > > $ sudo ip route flush cache ; ssh workhost.example.com exit > > Read from socket failed: Connection reset by peer > > > > Most of the time, this hangs for a few minutes before giving up; > > sometimes it just works fine. tcpdumps indicate that when it works, all > > packets transmitted are below the VPN's MTU; when it fails, MTU > > discovery has happened: > > > > 1. client sends large packet, for example 1832 bytes > > 2. router sends ICMP fragmentation needed > > 3. client retransmits with a smaller packet, for example 1303 bytes > > 4. router forwards packet over VPN > > 5. work host ACKs packet > > 6. router receives ACK but does not forward it > > 7. both endpoints retransmit, but ACKs never get forwarded > > > > The NAT table maintains an entry throughout (and continues to SNAT > > retransmits from the client), but the ACKs from the server never get > > forwarded. > > > > fire:~# netstat-nat -n -d 10.15.24.13 > > Proto NATed Address Destination Address State > > tcp 198.18.0.3:51076 10.15.24.13:22 ESTABLISHED > > > > > > I put a LOG target on the INPUT chain, though, and apparently these > > packets are bypassing the NAT; the kernel does not think they should be > > forwarded (else they would be on the FORWARD chain). > > > > [23335.509084] IN=tun0 OUT= MAC= SRC=10.15.24.13 DST=192.168.61.54 > > LEN=64 TOS=0x00 PREC=0x00 TTL=62 ID=28270 DF PROTO=TCP SPT=22 DPT=51076 > > WINDOW=134 RES=0x00 ACK FIN URGP=0 > > > > > > The kernel on the router is 3.10-2-amd64 (from Debian testing). I had > > the same problem with 3.2.0-4-amd64 (from Debian stable), before I tried > > to see if I could upgrade the problem away. > > > > Any help would be much appreciated. I can send full tcpdumps if needed. > > This looks like the bug we had to fix recently : > > http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=356d7d88e088687b6578ca64601b0a2c9d145296 > > Could you try latest net tree ? It's a PMTU related problem, so I'd suggest to check first the next ones: Aren't the ICMP error messages (i.e. fragmentation-needed) filtered out? If not, does adding an explicit TCPMSS rule to the mangle table help? Isn't there SACK options involved? Maybe there's a "smart" sequence number "anonymizer" device in the path which forgets about the SEQ numbers in the SACK options and thus such packets are marked as INVALID. So tcpdumps captured at both sides could really help to tell what goes wrong. Best regards, Jozsef - E-mail : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences H-1525 Budapest 114, POB. 49, Hungary ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-18 21:23 ` Jozsef Kadlecsik @ 2013-08-19 0:00 ` Eric Dumazet 2013-08-19 0:03 ` Eric Dumazet 0 siblings, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 0:00 UTC (permalink / raw) To: Jozsef Kadlecsik; +Cc: Corey Hickey, Linux Netdev List, netfilter-devel On Sun, 2013-08-18 at 23:23 +0200, Jozsef Kadlecsik wrote: > It's a PMTU related problem, so I'd suggest to check first the next ones: > > Aren't the ICMP error messages (i.e. fragmentation-needed) filtered out? > If not, does adding an explicit TCPMSS rule to the mangle table help? Thats totally irrelevant. tcp conntrack should not care of ICMP messages anyway. > Isn't there SACK options involved? Maybe there's a "smart" sequence > number "anonymizer" device in the path which forgets about the SEQ numbers > in the SACK options and thus such packets are marked as INVALID. > As I understood the report, they were no SACK at all, but plain ACK messages, and conntrack believes these ACK are outside the window because it remembers the @end sequence of the probe, and the @maxwin of receiver. Lets say the probe is 2000 bytes, seq 1:2001 conntrack records end = 2001 Of course this packet is lost. The retransmit sends a 1000 bytes packet, seq 1:1001 conntrack pass the packet. Receiver acks it using ack 1001 conntrack drops this ack because of some confusion about the prior 2001 end, and the window (might be as small as 1000) Code like this seems very suspect to me : before(sack, receiver->td_end + 1) It basically says that conntrack doesn't deal with reorders on the network. > So tcpdumps captured at both sides could really help to tell what goes wrong. We probably can reproduce this bug using packetdrill. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 0:00 ` Eric Dumazet @ 2013-08-19 0:03 ` Eric Dumazet 2013-08-19 8:43 ` Corey Hickey 0 siblings, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 0:03 UTC (permalink / raw) To: Jozsef Kadlecsik; +Cc: Corey Hickey, Linux Netdev List, netfilter-devel On Sun, 2013-08-18 at 17:00 -0700, Eric Dumazet wrote: > Code like this seems very suspect to me : > > before(sack, receiver->td_end + 1) > My suggestion would be to try : diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 2f80107..1862902 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -656,12 +656,12 @@ static bool tcp_in_window(const struct nf_conn *ct, pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), (in_recv_win ? 1 : 0), - before(sack, receiver->td_end + 1), + before(sack, receiver->td_end + MAXACKWINDOW(sender) + 1), after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); if (before(seq, sender->td_maxend + 1) && in_recv_win && - before(sack, receiver->td_end + 1) && + before(sack, receiver->td_end + MAXACKWINDOW(sender) + 1) && after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { /* * Take into account window scaling (RFC 1323). ^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 0:03 ` Eric Dumazet @ 2013-08-19 8:43 ` Corey Hickey 2013-08-19 12:33 ` Christoph Paasch 0 siblings, 1 reply; 32+ messages in thread From: Corey Hickey @ 2013-08-19 8:43 UTC (permalink / raw) To: Eric Dumazet; +Cc: Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 2013-08-18 17:03, Eric Dumazet wrote: > On Sun, 2013-08-18 at 17:00 -0700, Eric Dumazet wrote: > >> Code like this seems very suspect to me : >> >> before(sack, receiver->td_end + 1) >> > > My suggestion would be to try : > > diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c [...] Thanks for all your suggestions--I really wasn't expecting so much on a weekend. Here's all the data I have for tonight. I tried the linux-next kernel, then linux-next with your patch applied. Neither of them fix the problem, unfortunately. I have taken tcpdumps for a working SSH and a failing SSH. http://fatooh.org/files/tmp/linux-next-patch1.tar.bz2 [localhost] sudo tcpdump -ni br0 -s 0 -w /tmp/local.pcap 'host 10.15.24.13 or icmp' [router eth0] tcpdump -ni eth0 -s 0 -w /tmp/eth0.pcap \ 'host 10.15.24.13 or (icmp and host not 69.78.33.132)' * the exclusion here is just to remove some unrelated clutter [router tun0] tcpdump -ni tun0 -s 0 -w /tmp/tun0.pcap -s 0 'host 10.15.24.13 or icmp' [remote] tcpdump -ni eth0 -s 0 -w remote.pcap 'host 192.168.61.56' Some notes: 1. I tested the new kernels only on the Linux router, assuming that is where it was intended. 2. I take back what I wrote earlier about every connection that involves PMTU discovery failed; I may have been observing this wrong. For now, the situation is that some connections stop forwarding packets from the remote host immediately after the retransmit, while other work fine. 3. From local.pcap, you can see that my localhost doesn't actually transmit a large packet, yet the router's eth0 sees a large packet come in. I think this is due to TSO, but I'm not completely sure. 4. For some reason, I cannot reproduce this when SSHing to a host at work that is running Debian sid with 3.10-1-amd64, but I can reproduce it when SSHing to hosts running Centos 6.4 with 2.6.32-358.6.1.el6.x86_64 (which surely has a ton of patches applied, for whatever that's worth). 5. I have only a vague understanding of SACK; I will be reading up on this soon. I will also look into packetdrill for reproducing the problem, if the SSH results aren't good enough. 6. If I reduce the MTU on localhost to match the path MTU, the problem does go away. Thanks again for all the help, Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 8:43 ` Corey Hickey @ 2013-08-19 12:33 ` Christoph Paasch 2013-08-19 13:24 ` Eric Dumazet 2013-08-19 18:22 ` Corey Hickey 0 siblings, 2 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 12:33 UTC (permalink / raw) To: Corey Hickey Cc: Eric Dumazet, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel Hello, I would say, the problem is due to a sequence-number rewriting middlebox, who does not correctly handle the SACK-blocks. In remote.pcap, you see: Packet#10: A Dup-ACK: ACK 1005503816, SACK: 1005505184-1005505648 The SACK actually covers Packet#9 In tun0.pcap, you have: Packet#9: The one that is SACK'ed: SEQ: 3514869772 Packet#11: The Dup-ACK: ACK: 3514868404, SACK: 3570452498-3570452962 You can see that the SACK-block is not really aligned with the ACK-numbers. Netfilter is probably dropping the Dup-ACK, because the SACK-block is acknowledging unseen data. There are middleboxes out there that randomize the sequence numbers, due to an old bug in Windows, where the initial sequence number was not sufficiently randomized. There are some of these middleboxes, who simply do not support SACK, thus modify only the sequence numbers of the TCP-header (https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK). This results in a TCP retransmission timeout on the sender, because of the invalid SACK-blocks, the duplicate ACKs are not accounted. This completly kills the performance, as you can see in our presentation given at IETF87: http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf We have a patch that accounts DUP-ACKs with invalid SACK-blocks effectively as duplicate acknowledgments. I can send the patches, if the netdev-community is interested in accepting these upstream. Cheers, Christoph On 19/08/13 - 01:43:18, Corey Hickey wrote: > On 2013-08-18 17:03, Eric Dumazet wrote: > > On Sun, 2013-08-18 at 17:00 -0700, Eric Dumazet wrote: > > > >> Code like this seems very suspect to me : > >> > >> before(sack, receiver->td_end + 1) > >> > > > > My suggestion would be to try : > > > > diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c > > [...] > > Thanks for all your suggestions--I really wasn't expecting so much on a > weekend. Here's all the data I have for tonight. > > > I tried the linux-next kernel, then linux-next with your patch applied. > Neither of them fix the problem, unfortunately. I have taken tcpdumps > for a working SSH and a failing SSH. > > http://fatooh.org/files/tmp/linux-next-patch1.tar.bz2 > > [localhost] > sudo tcpdump -ni br0 -s 0 -w /tmp/local.pcap 'host 10.15.24.13 or icmp' > > [router eth0] > tcpdump -ni eth0 -s 0 -w /tmp/eth0.pcap \ > 'host 10.15.24.13 or (icmp and host not 69.78.33.132)' > * the exclusion here is just to remove some unrelated clutter > > [router tun0] > tcpdump -ni tun0 -s 0 -w /tmp/tun0.pcap -s 0 'host 10.15.24.13 or icmp' > > [remote] > tcpdump -ni eth0 -s 0 -w remote.pcap 'host 192.168.61.56' > > > Some notes: > > 1. I tested the new kernels only on the Linux router, assuming that is > where it was intended. > > 2. I take back what I wrote earlier about every connection that involves > PMTU discovery failed; I may have been observing this wrong. For now, > the situation is that some connections stop forwarding packets from the > remote host immediately after the retransmit, while other work fine. > > 3. From local.pcap, you can see that my localhost doesn't actually > transmit a large packet, yet the router's eth0 sees a large packet come > in. I think this is due to TSO, but I'm not completely sure. > > 4. For some reason, I cannot reproduce this when SSHing to a host at > work that is running Debian sid with 3.10-1-amd64, but I can reproduce > it when SSHing to hosts running Centos 6.4 with > 2.6.32-358.6.1.el6.x86_64 (which surely has a ton of patches applied, > for whatever that's worth). > > 5. I have only a vague understanding of SACK; I will be reading up on > this soon. I will also look into packetdrill for reproducing the > problem, if the SSH results aren't good enough. > > 6. If I reduce the MTU on localhost to match the path MTU, the problem > does go away. > > Thanks again for all the help, > Corey > -- > To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 12:33 ` Christoph Paasch @ 2013-08-19 13:24 ` Eric Dumazet 2013-08-19 13:49 ` Christoph Paasch 2013-08-19 18:22 ` Corey Hickey 1 sibling, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 13:24 UTC (permalink / raw) To: Christoph Paasch Cc: Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 14:33 +0200, Christoph Paasch wrote: > Hello, > > I would say, the problem is due to a sequence-number rewriting > middlebox, who does not correctly handle the SACK-blocks. > > In remote.pcap, you see: > Packet#10: A Dup-ACK: ACK 1005503816, SACK: 1005505184-1005505648 > The SACK actually covers Packet#9 > > In tun0.pcap, you have: > Packet#9: The one that is SACK'ed: SEQ: 3514869772 > Packet#11: The Dup-ACK: ACK: 3514868404, SACK: 3570452498-3570452962 > > You can see that the SACK-block is not really aligned with the ACK-numbers. > > Netfilter is probably dropping the Dup-ACK, because the SACK-block is > acknowledging unseen data. > > > There are middleboxes out there that randomize the sequence numbers, due to > an old bug in Windows, where the initial sequence number was not > sufficiently randomized. There are some of these middleboxes, who simply do > not support SACK, thus modify only the sequence numbers of the TCP-header > (https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK). > > This results in a TCP retransmission timeout on the sender, because of > the invalid SACK-blocks, the duplicate ACKs are not accounted. This > completly kills the performance, as you can see in our presentation given at > IETF87: http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf > > We have a patch that accounts DUP-ACKs with invalid SACK-blocks effectively > as duplicate acknowledgments. I can send the patches, if the > netdev-community is interested in accepting these upstream. > You mean a netfilter patch, a tcp patch, or both ? ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 13:24 ` Eric Dumazet @ 2013-08-19 13:49 ` Christoph Paasch 2013-08-19 13:58 ` Eric Dumazet 0 siblings, 1 reply; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 13:49 UTC (permalink / raw) To: Eric Dumazet Cc: Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 19/08/13 - 06:24:17, Eric Dumazet wrote: > On Mon, 2013-08-19 at 14:33 +0200, Christoph Paasch wrote: > > Hello, > > > > I would say, the problem is due to a sequence-number rewriting > > middlebox, who does not correctly handle the SACK-blocks. > > > > In remote.pcap, you see: > > Packet#10: A Dup-ACK: ACK 1005503816, SACK: 1005505184-1005505648 > > The SACK actually covers Packet#9 > > > > In tun0.pcap, you have: > > Packet#9: The one that is SACK'ed: SEQ: 3514869772 > > Packet#11: The Dup-ACK: ACK: 3514868404, SACK: 3570452498-3570452962 > > > > You can see that the SACK-block is not really aligned with the ACK-numbers. > > > > Netfilter is probably dropping the Dup-ACK, because the SACK-block is > > acknowledging unseen data. > > > > > > There are middleboxes out there that randomize the sequence numbers, due to > > an old bug in Windows, where the initial sequence number was not > > sufficiently randomized. There are some of these middleboxes, who simply do > > not support SACK, thus modify only the sequence numbers of the TCP-header > > (https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK). > > > > This results in a TCP retransmission timeout on the sender, because of > > the invalid SACK-blocks, the duplicate ACKs are not accounted. This > > completly kills the performance, as you can see in our presentation given at > > IETF87: http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf > > > > We have a patch that accounts DUP-ACKs with invalid SACK-blocks effectively > > as duplicate acknowledgments. I can send the patches, if the > > netdev-community is interested in accepting these upstream. > > > > You mean a netfilter patch, a tcp patch, or both ? It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as duplicate acks in tcp_sock->sacked_out. Christoph ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 13:49 ` Christoph Paasch @ 2013-08-19 13:58 ` Eric Dumazet 2013-08-19 14:35 ` Phil Oester ` (2 more replies) 0 siblings, 3 replies; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 13:58 UTC (permalink / raw) To: Christoph Paasch Cc: Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as > duplicate acks in tcp_sock->sacked_out. Yeah, but here, this is conntrack who is blocking the thing. TCP receiver has no chance to 'fix' it. See conntrack is one of those buggy middle box as well. So if you want to properly handle this mess, you'll also have to fix conntrack. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 13:58 ` Eric Dumazet @ 2013-08-19 14:35 ` Phil Oester 2013-08-19 15:32 ` Eric Dumazet 2013-08-19 15:33 ` Christoph Paasch 2013-08-19 14:43 ` NAT stops forwarding ACKs after PMTU discovery Christoph Paasch 2013-08-19 20:13 ` Jozsef Kadlecsik 2 siblings, 2 replies; 32+ messages in thread From: Phil Oester @ 2013-08-19 14:35 UTC (permalink / raw) To: Eric Dumazet Cc: Christoph Paasch, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, Aug 19, 2013 at 06:58:05AM -0700, Eric Dumazet wrote: > Yeah, but here, this is conntrack who is blocking the thing. > > TCP receiver has no chance to 'fix' it. > > See conntrack is one of those buggy middle box as well. > > So if you want to properly handle this mess, you'll also have to fix > conntrack. Better to fix the box which is randomizing the acks and ignoring the SACKs. Usually these are older Cisco PIX/ASA devices which just need a code upgrade. Phil ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 14:35 ` Phil Oester @ 2013-08-19 15:32 ` Eric Dumazet 2013-08-19 15:33 ` Christoph Paasch 1 sibling, 0 replies; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 15:32 UTC (permalink / raw) To: Phil Oester Cc: Christoph Paasch, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 07:35 -0700, Phil Oester wrote: > On Mon, Aug 19, 2013 at 06:58:05AM -0700, Eric Dumazet wrote: > > Yeah, but here, this is conntrack who is blocking the thing. > > > > TCP receiver has no chance to 'fix' it. > > > > See conntrack is one of those buggy middle box as well. > > > > So if you want to properly handle this mess, you'll also have to fix > > conntrack. > > Better to fix the box which is randomizing the acks and ignoring > the SACKs. Usually these are older Cisco PIX/ASA devices which just > need a code upgrade. Having a patch to relax things could be evaluated, if not adding new problems ( http://en.wikipedia.org/wiki/Robustness_principle ) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 14:35 ` Phil Oester 2013-08-19 15:32 ` Eric Dumazet @ 2013-08-19 15:33 ` Christoph Paasch 2013-08-19 16:00 ` Eric Dumazet 1 sibling, 1 reply; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 15:33 UTC (permalink / raw) To: Phil Oester Cc: Eric Dumazet, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 19/08/13 - 07:35:09, Phil Oester wrote: > On Mon, Aug 19, 2013 at 06:58:05AM -0700, Eric Dumazet wrote: > > Yeah, but here, this is conntrack who is blocking the thing. > > > > TCP receiver has no chance to 'fix' it. > > > > See conntrack is one of those buggy middle box as well. > > > > So if you want to properly handle this mess, you'll also have to fix > > conntrack. > > Better to fix the box which is randomizing the acks and ignoring > the SACKs. Usually these are older Cisco PIX/ASA devices which just > need a code upgrade. I agree, the problem are these horrid middleboxes... Unfortunately, they will hardly go away in the near futur. Rather the opposite is the case. If you have a public server running, I would be interested in the count of invalid SACK-blocks received (netstat -s | grep TCPSACKDiscard). This is an indication for such kind of middlebox between your server and the client, implying that these connections cannot benefit from TCP-FastRetransmission and each packet-loss will require an RTO to recover. Cheers, Christoph ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 15:33 ` Christoph Paasch @ 2013-08-19 16:00 ` Eric Dumazet 2013-08-19 17:15 ` Christoph Paasch 0 siblings, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 16:00 UTC (permalink / raw) To: Christoph Paasch Cc: Phil Oester, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 17:33 +0200, Christoph Paasch wrote: > > Unfortunately, they will hardly go away in the near futur. Rather the > opposite is the case. > > > If you have a public server running, I would be interested in the count of > invalid SACK-blocks received (netstat -s | grep TCPSACKDiscard). This is an > indication for such kind of middlebox between your server and the client, > implying that these connections cannot benefit from TCP-FastRetransmission > and each packet-loss will require an RTO to recover. > If the (random) sequence offset is small rather than completely out of window, it's going to be hard to detect all problems. Show us your patch ;) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 16:00 ` Eric Dumazet @ 2013-08-19 17:15 ` Christoph Paasch 2013-08-19 18:00 ` Phil Oester 2013-08-19 18:10 ` Eric Dumazet 0 siblings, 2 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 17:15 UTC (permalink / raw) To: Eric Dumazet Cc: Phil Oester, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 19/08/13 - 09:00:31, Eric Dumazet wrote: > On Mon, 2013-08-19 at 17:33 +0200, Christoph Paasch wrote: > > Unfortunately, they will hardly go away in the near futur. Rather the > > opposite is the case. > > > > > > If you have a public server running, I would be interested in the count of > > invalid SACK-blocks received (netstat -s | grep TCPSACKDiscard). This is an > > indication for such kind of middlebox between your server and the client, > > implying that these connections cannot benefit from TCP-FastRetransmission > > and each packet-loss will require an RTO to recover. > > > > If the (random) sequence offset is small rather than completely out of > window, it's going to be hard to detect all problems. Yes, it is not possible to make it 100% perfect. But considering the size of the seq-space, the probability is rather low that the SACK-block falls in-window. > Show us your patch ;) Will send it soon. Have to rebase on net-next,... :) (it's several months ago that I did this) Christoph ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 17:15 ` Christoph Paasch @ 2013-08-19 18:00 ` Phil Oester 2013-08-19 18:10 ` Eric Dumazet 1 sibling, 0 replies; 32+ messages in thread From: Phil Oester @ 2013-08-19 18:00 UTC (permalink / raw) To: Christoph Paasch Cc: Eric Dumazet, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, Aug 19, 2013 at 07:15:19PM +0200, Christoph Paasch wrote: > On 19/08/13 - 09:00:31, Eric Dumazet wrote: > > On Mon, 2013-08-19 at 17:33 +0200, Christoph Paasch wrote: > > > Unfortunately, they will hardly go away in the near futur. Rather the > > > opposite is the case. > > > > > > > > > If you have a public server running, I would be interested in the count of > > > invalid SACK-blocks received (netstat -s | grep TCPSACKDiscard). This is an > > > indication for such kind of middlebox between your server and the client, > > > implying that these connections cannot benefit from TCP-FastRetransmission > > > and each packet-loss will require an RTO to recover. > > > > > > > If the (random) sequence offset is small rather than completely out of > > window, it's going to be hard to detect all problems. It is not small unfortunately. The bug is that with ISN randomization enabled the PIX leaves the SACK sequence numbers untouched. For reference, the cisco bug is CSCse14419. > Yes, it is not possible to make it 100% perfect. But considering the size of > the seq-space, the probability is rather low that the SACK-block falls > in-window. s/rather low/nil/ > > Show us your patch ;) Or just disable SACK on the box behind the problematic PIX. Phil ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 17:15 ` Christoph Paasch 2013-08-19 18:00 ` Phil Oester @ 2013-08-19 18:10 ` Eric Dumazet 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch 1 sibling, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 18:10 UTC (permalink / raw) To: Christoph Paasch Cc: Phil Oester, Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 19:15 +0200, Christoph Paasch wrote: > > Will send it soon. Have to rebase on net-next,... :) > (it's several months ago that I did this) No hurry. This is a very unlikely problem anyway. Trace taken on a random Google server : TcpExtTCPSACKDiscard 44666 TcpExtTCPSACKReneging 173593 TcpExtTCPSACKReorder 1331306 TcpExtTCPSackFailures 791292 TcpExtTCPSackMerged 261702691 TcpExtTCPSackRecovery 57267494 TcpExtTCPSackRecoveryFail 2008511 TcpExtTCPSackShiftFallback 841017416 TcpExtTCPSackShifted 619337144 ... TcpOutSegs 42215528084 TcpRetransSegs 441868477 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks 2013-08-19 18:10 ` Eric Dumazet @ 2013-08-19 19:29 ` Christoph Paasch 2013-08-19 19:29 ` [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out Christoph Paasch ` (3 more replies) 0 siblings, 4 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw) To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans There exist sequence-number rewriting middleboxes, who do not modify the sequence-number in the SACK-blocks. Duplicate acknowledgments with these (invalid) SACK-blocks will not be accounted in sacked_out, and thus no fast-retransmit will trigger. So, the only way to recover from a packet-loss is through an RTO, effectively killing the performance of TCP in this case. Performance-results can be seen here: http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf Another solution might be to simply disable SACK, as soon as an invalid SACK-block has been received (as suggested by Phil Oester). This however might be too aggressive. Christoph Paasch (2): Use acked_out for reno-style ack acounting instead of sacked_out Account acked_out in sack, if the sack is invalid include/linux/tcp.h | 1 + include/net/tcp.h | 17 +++++--- net/ipv4/tcp_input.c | 103 ++++++++++++++++++++++++++++++++--------------- net/ipv4/tcp_minisocks.c | 1 + net/ipv4/tcp_output.c | 6 +-- net/ipv4/tcp_timer.c | 2 +- 6 files changed, 89 insertions(+), 41 deletions(-) -- 1.8.1.2 ^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch @ 2013-08-19 19:29 ` Christoph Paasch 2013-08-19 19:29 ` [RFC 2/2] Account acked_out in sack, if the sack is invalid Christoph Paasch ` (2 subsequent siblings) 3 siblings, 0 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw) To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans This patch adds acked_out to tcp_sock, so that all acounting of acked packets in case of non-sack connections is done within this field. tcp_acked_out() sums up sacked_out and acked_out. Tested-by: Benjamin Hesmans <benjamin.hesmans@uclouvain.be> Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be> --- include/linux/tcp.h | 1 + include/net/tcp.h | 17 ++++++++++++----- net/ipv4/tcp_input.c | 44 +++++++++++++++++++++++++++----------------- net/ipv4/tcp_minisocks.c | 1 + net/ipv4/tcp_output.c | 2 +- net/ipv4/tcp_timer.c | 2 +- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index d686334..6622595 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -241,6 +241,7 @@ struct tcp_sock { u32 pushed_seq; /* Last pushed seq, required to talk to windows */ u32 lost_out; /* Lost packets */ u32 sacked_out; /* SACK'd packets */ + u32 acked_out; /* DupACK'd packets */ u32 fackets_out; /* FACK'd packets */ u32 tso_deferred; diff --git a/include/net/tcp.h b/include/net/tcp.h index 09cb5c1..8210057 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -871,9 +871,14 @@ static inline void tcp_disable_early_retrans(struct tcp_sock *tp) tp->do_early_retrans = 0; } +static inline unsigned int tcp_acked_out(const struct tcp_sock *tp) +{ + return tp->sacked_out + tp->acked_out; +} + static inline unsigned int tcp_left_out(const struct tcp_sock *tp) { - return tp->sacked_out + tp->lost_out; + return tcp_acked_out(tp) + tp->lost_out; } /* This determines how many packets are "in the network" to the best @@ -1446,12 +1451,12 @@ static inline void tcp_push_pending_frames(struct sock *sk) } /* Start sequence of the skb just after the highest skb with SACKed - * bit, valid only if sacked_out > 0 or when the caller has ensured + * bit, valid only if sacked_out or acked_out > 0 or when the caller has ensured * validity by itself. */ static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp) { - if (!tp->sacked_out) + if (!tp->sacked_out && !tp->acked_out) return tp->snd_una; if (tp->highest_sack == NULL) @@ -1481,8 +1486,10 @@ static inline void tcp_highest_sack_combine(struct sock *sk, struct sk_buff *old, struct sk_buff *new) { - if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack)) - tcp_sk(sk)->highest_sack = new; + struct tcp_sock *tp = tcp_sk(sk); + + if ((tp->sacked_out || tp->acked_out) && (old == tp->highest_sack)) + tp->highest_sack = new; } /* Determines whether this is a thin stream (which may suffer from diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e965cc7..af764d0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1748,8 +1748,8 @@ out: return state.flag; } -/* Limits sacked_out so that sum with lost_out isn't ever larger than - * packets_out. Returns false if sacked_out adjustement wasn't necessary. +/* Limits acked_out so that sum with lost_out isn't ever larger than + * packets_out. Returns false if acked_out adjustement wasn't necessary. */ static bool tcp_limit_reno_sacked(struct tcp_sock *tp) { @@ -1758,8 +1758,8 @@ static bool tcp_limit_reno_sacked(struct tcp_sock *tp) holes = max(tp->lost_out, 1U); holes = min(holes, tp->packets_out); - if ((tp->sacked_out + holes) > tp->packets_out) { - tp->sacked_out = tp->packets_out - holes; + if ((tp->acked_out + holes) > tp->packets_out) { + tp->acked_out = tp->packets_out - holes; return true; } return false; @@ -1781,7 +1781,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend) static void tcp_add_reno_sack(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); - tp->sacked_out++; + tp->acked_out++; tcp_check_reno_reordering(sk, 0); tcp_verify_left_out(tp); } @@ -1794,10 +1794,10 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked) if (acked > 0) { /* One ACK acked hole. The rest eat duplicate ACKs. */ - if (acked - 1 >= tp->sacked_out) - tp->sacked_out = 0; + if (acked - 1 >= tp->acked_out) + tp->acked_out = 0; else - tp->sacked_out -= acked - 1; + tp->acked_out -= acked - 1; } tcp_check_reno_reordering(sk, acked); tcp_verify_left_out(tp); @@ -1805,7 +1805,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked) static inline void tcp_reset_reno_sack(struct tcp_sock *tp) { - tp->sacked_out = 0; + tp->acked_out = 0; } static void tcp_clear_retrans_partial(struct tcp_sock *tp) @@ -1823,6 +1823,7 @@ void tcp_clear_retrans(struct tcp_sock *tp) tp->fackets_out = 0; tp->sacked_out = 0; + tp->acked_out = 0; } /* Enter Loss state. If "how" is not zero, forget all SACK information @@ -1857,6 +1858,7 @@ void tcp_enter_loss(struct sock *sk, int how) tp->undo_marker = tp->snd_una; if (how) { tp->sacked_out = 0; + tp->acked_out = 0; tp->fackets_out = 0; } tcp_clear_all_retrans_hints(tp); @@ -1921,7 +1923,7 @@ static bool tcp_check_sack_reneging(struct sock *sk, int flag) static inline int tcp_fackets_out(const struct tcp_sock *tp) { - return tcp_is_reno(tp) ? tp->sacked_out + 1 : tp->fackets_out; + return tcp_is_reno(tp) ? tp->acked_out + 1 : tp->fackets_out; } /* Heurestics to calculate number of duplicate ACKs. There's no dupACKs @@ -1941,7 +1943,7 @@ static inline int tcp_fackets_out(const struct tcp_sock *tp) */ static inline int tcp_dupack_heuristics(const struct tcp_sock *tp) { - return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1; + return tcp_is_fack(tp) ? tp->fackets_out : tcp_acked_out(tp) + 1; } static bool tcp_pause_early_retransmit(struct sock *sk, int flag) @@ -2077,7 +2079,7 @@ static bool tcp_time_to_recover(struct sock *sk, int flag) */ packets_out = tp->packets_out; if (packets_out <= tp->reordering && - tp->sacked_out >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) && + tcp_acked_out(tp) >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) && !tcp_may_send_now(sk)) { /* We have nothing to send. This connection is limited * either by receiver window or by application. @@ -2100,8 +2102,8 @@ static bool tcp_time_to_recover(struct sock *sk, int flag) * Mitigation A.3 in the RFC and delay the retransmission for a short * interval if appropriate. */ - if (tp->do_early_retrans && !tp->retrans_out && tp->sacked_out && - (tp->packets_out >= (tp->sacked_out + 1) && tp->packets_out < 4) && + if (tp->do_early_retrans && !tp->retrans_out && (tp->sacked_out || tp->acked_out) && + (tp->packets_out >= (tcp_acked_out(tp) + 1) && tp->packets_out < 4) && !tcp_may_send_now(sk)) return !tcp_pause_early_retransmit(sk, flag); @@ -2701,9 +2703,11 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, (tcp_fackets_out(tp) > tp->reordering)); int fast_rexmit = 0; - if (WARN_ON(!tp->packets_out && tp->sacked_out)) + if (WARN_ON(!tp->packets_out && (tp->sacked_out || tp->acked_out))) { tp->sacked_out = 0; - if (WARN_ON(!tp->sacked_out && tp->fackets_out)) + tp->acked_out = 0; + } + if (WARN_ON(!tp->sacked_out && !tp->acked_out && tp->fackets_out)) tp->fackets_out = 0; /* Now state machine starts. @@ -3078,6 +3082,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, #if FASTRETRANS_DEBUG > 0 WARN_ON((int)tp->sacked_out < 0); + WARN_ON((int)tp->acked_out < 0); WARN_ON((int)tp->lost_out < 0); WARN_ON((int)tp->retrans_out < 0); if (!tp->packets_out && tcp_is_sack(tp)) { @@ -3092,6 +3097,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, tp->sacked_out, icsk->icsk_ca_state); tp->sacked_out = 0; } + if (tp->acked_out) { + pr_debug("Leak a=%u %d\n", + tp->acked_out, icsk->icsk_ca_state); + tp->acked_out = 0; + } if (tp->retrans_out) { pr_debug("Leak r=%u %d\n", tp->retrans_out, icsk->icsk_ca_state); @@ -3270,7 +3280,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) u32 prior_in_flight; u32 prior_fackets; int prior_packets = tp->packets_out; - const int prior_unsacked = tp->packets_out - tp->sacked_out; + const int prior_unsacked = tp->packets_out - tcp_acked_out(tp); int acked = 0; /* Number of packets newly acked */ s32 sack_rtt = -1; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 58a3e69..a2f5279 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -407,6 +407,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->packets_out = 0; newtp->retrans_out = 0; newtp->sacked_out = 0; + newtp->acked_out = 0; newtp->fackets_out = 0; newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tcp_enable_early_retrans(newtp); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 884efff..17ebbff 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1033,7 +1033,7 @@ static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int de /* Reno case is special. Sigh... */ if (tcp_is_reno(tp) && decr > 0) - tp->sacked_out -= min_t(u32, tp->sacked_out, decr); + tp->acked_out -= min_t(u32, tp->acked_out, decr); tcp_adjust_fackets_out(sk, skb, decr); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 4b85e6f..82acaea 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -405,7 +405,7 @@ void tcp_retransmit_timer(struct sock *sk) } else if (icsk->icsk_ca_state == TCP_CA_Loss) { mib_idx = LINUX_MIB_TCPLOSSFAILURES; } else if ((icsk->icsk_ca_state == TCP_CA_Disorder) || - tp->sacked_out) { + tp->sacked_out || tp->acked_out) { if (tcp_is_sack(tp)) mib_idx = LINUX_MIB_TCPSACKFAILURES; else -- 1.8.1.2 ^ permalink raw reply related [flat|nested] 32+ messages in thread
* [RFC 2/2] Account acked_out in sack, if the sack is invalid 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch 2013-08-19 19:29 ` [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out Christoph Paasch @ 2013-08-19 19:29 ` Christoph Paasch 2013-08-19 21:22 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Corey Hickey 2013-08-22 3:32 ` David Miller 3 siblings, 0 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw) To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans In case of a sequence-number rewriting firewall (e.g., a Cisco Firewall: https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK) the SACK-blocks are not rewritten. As we receive these ACK-packets, the sackblock is marked as invalid in tcp_is_sackblock_valid(), and sacked_out will not be incremented. Thus, fast-retransmit will not trigger and the stack will timeout after an RTO. This completly kills the performance across this kind of firewalls. This patch allows acked_out to increase, in case a sackblog is marked as invalid. Further, it considers acked_out in the accounting when SACK has been enabled on the connection. Tested-by: Benjamin Hesmans <benjamin.hesmans@uclouvain.be> Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be> --- net/ipv4/tcp_input.c | 59 ++++++++++++++++++++++++++++++++++++++------------- net/ipv4/tcp_output.c | 4 ++-- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index af764d0..ea99017 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -75,6 +75,8 @@ #include <asm/unaligned.h> #include <net/netdma.h> +static void tcp_add_reno_sack(struct sock *sk); + int sysctl_tcp_timestamps __read_mostly = 1; int sysctl_tcp_window_scaling __read_mostly = 1; int sysctl_tcp_sack __read_mostly = 1; @@ -1542,7 +1544,7 @@ static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_bl static int tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, - u32 prior_snd_una, s32 *sack_rtt) + u32 prior_snd_una, s32 *sack_rtt, int flag) { struct tcp_sock *tp = tcp_sk(sk); const unsigned char *ptr = (skb_transport_header(ack_skb) + @@ -1554,7 +1556,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, struct sk_buff *skb; int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3); int used_sacks; - bool found_dup_sack = false; + bool found_dup_sack = false, first = true; int i, j; int first_sack_index; @@ -1562,7 +1564,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, state.reord = tp->packets_out; state.rtt = -1; - if (!tp->sacked_out) { + if (!tp->sacked_out && !tp->acked_out) { if (WARN_ON(tp->fackets_out)) tp->fackets_out = 0; tcp_highest_sack_reset(sk); @@ -1612,6 +1614,29 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, NET_INC_STATS_BH(sock_net(sk), mib_idx); if (i == 0) first_sack_index = -1; + + /* 1. Only account the dup-ack once. + * + * 2. If we are coming from tcp_ack, with an old_ack, we + * should not increase acked_out, as the ack is old :) + * + * 3. Only increase acked_out, if this is really a + * duplicate ack. Check is similar to the one in + * tcp_ack, when setting is_dupack. + * + * 4. We have to reproduce the first check of + * tcp_is_sackblock_valid, because we don't want to + * account dup-acks if the sack-blog is corrupted. + */ + if (first && + !before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una) && + !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)) && + before(sp[used_sacks].start_seq, sp[used_sacks].end_seq)) { + first = false; + /* Disable FACK, as we can't trust SACKs anymore */ + tcp_disable_fack(tp); + tcp_add_reno_sack(sk); + } continue; } @@ -1740,6 +1765,7 @@ out: #if FASTRETRANS_DEBUG > 0 WARN_ON((int)tp->sacked_out < 0); + WARN_ON((int)tp->acked_out < 0); WARN_ON((int)tp->lost_out < 0); WARN_ON((int)tp->retrans_out < 0); WARN_ON((int)tcp_packets_in_flight(tp) < 0); @@ -1852,7 +1878,7 @@ void tcp_enter_loss(struct sock *sk, int how) tcp_clear_retrans_partial(tp); - if (tcp_is_reno(tp)) + if (tcp_is_reno(tp) || tp->acked_out) tcp_reset_reno_sack(tp); tp->undo_marker = tp->snd_una; @@ -2189,7 +2215,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit) lost = 1; tcp_mark_head_lost(sk, lost, 0); } else { - int sacked_upto = tp->sacked_out - tp->reordering; + int sacked_upto = tcp_acked_out(tp) - tp->reordering; if (sacked_upto >= 0) tcp_mark_head_lost(sk, sacked_upto, 0); else if (fast_rexmit) @@ -2551,7 +2577,7 @@ void tcp_simple_retransmit(struct sock *sk) if (prior_lost == tp->lost_out) return; - if (tcp_is_reno(tp)) + if (tcp_is_reno(tp) || tp->acked_out) tcp_limit_reno_sacked(tp); tcp_verify_left_out(tp); @@ -2634,11 +2660,11 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) } if (flag & FLAG_DATA_ACKED) icsk->icsk_retransmits = 0; - if (tcp_is_reno(tp)) { + if (tcp_is_reno(tp) || tp->acked_out) { /* A Reno DUPACK means new data in F-RTO step 2.b above are * delivered. Lower inflight to clock out (re)tranmissions. */ - if (after(tp->snd_nxt, tp->high_seq) && is_dupack) + if (tcp_is_reno(tp) && after(tp->snd_nxt, tp->high_seq) && is_dupack) tcp_add_reno_sack(sk); else if (flag & FLAG_SND_UNA_ADVANCED) tcp_reset_reno_sack(tp); @@ -2739,7 +2765,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, break; case TCP_CA_Recovery: - if (tcp_is_reno(tp)) + if (tcp_is_reno(tp) || tp->acked_out) tcp_reset_reno_sack(tp); if (tcp_try_undo_recovery(sk)) return; @@ -2772,10 +2798,10 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, return; /* Fall through to processing in Open state. */ default: - if (tcp_is_reno(tp)) { + if (tcp_is_reno(tp) || tp->acked_out) { if (flag & FLAG_SND_UNA_ADVANCED) tcp_reset_reno_sack(tp); - if (is_dupack) + if (is_dupack && tcp_is_reno(tp)) tcp_add_reno_sack(sk); } @@ -2952,7 +2978,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, int flag = 0; u32 pkts_acked = 0; u32 reord = tp->packets_out; - u32 prior_sacked = tp->sacked_out; + u32 prior_sacked = tcp_acked_out(tp); s32 seq_rtt = -1; s32 ca_seq_rtt = -1; ktime_t last_ackt = net_invalid_timestamp(); @@ -3050,12 +3076,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, } else { int delta; + if (tp->acked_out) + tcp_remove_reno_sacks(sk, pkts_acked); + /* Non-retransmitted hole got filled? That's reordering */ if (reord < prior_fackets) tcp_update_reordering(sk, tp->fackets_out - reord, 0); delta = tcp_is_fack(tp) ? pkts_acked : - prior_sacked - tp->sacked_out; + prior_sacked - tcp_acked_out(tp); tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta); } @@ -3340,7 +3369,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) if (TCP_SKB_CB(skb)->sacked) flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, - &sack_rtt); + &sack_rtt, flag); if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb))) flag |= FLAG_ECE; @@ -3413,7 +3442,7 @@ old_ack: */ if (TCP_SKB_CB(skb)->sacked) { flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, - &sack_rtt); + &sack_rtt, flag); tcp_fastretrans_alert(sk, acked, prior_unsacked, is_dupack, flag); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 17ebbff..2ecb943 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1008,7 +1008,7 @@ static void tcp_adjust_fackets_out(struct sock *sk, const struct sk_buff *skb, { struct tcp_sock *tp = tcp_sk(sk); - if (!tp->sacked_out || tcp_is_reno(tp)) + if ((!tp->sacked_out && !tp->acked_out) || tcp_is_reno(tp)) return; if (after(tcp_highest_sack_seq(tp), TCP_SKB_CB(skb)->seq)) @@ -1032,7 +1032,7 @@ static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int de tp->lost_out -= decr; /* Reno case is special. Sigh... */ - if (tcp_is_reno(tp) && decr > 0) + if ((tcp_is_reno(tp) || tp->acked_out) && decr > 0) tp->acked_out -= min_t(u32, tp->acked_out, decr); tcp_adjust_fackets_out(sk, skb, decr); -- 1.8.1.2 ^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch 2013-08-19 19:29 ` [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out Christoph Paasch 2013-08-19 19:29 ` [RFC 2/2] Account acked_out in sack, if the sack is invalid Christoph Paasch @ 2013-08-19 21:22 ` Corey Hickey 2013-08-20 7:36 ` Christoph Paasch 2013-08-22 3:32 ` David Miller 3 siblings, 1 reply; 32+ messages in thread From: Corey Hickey @ 2013-08-19 21:22 UTC (permalink / raw) To: Christoph Paasch; +Cc: Eric Dumazet, netdev, Phil Oester, Benjamin Hesmans On 2013-08-19 12:29, Christoph Paasch wrote: > There exist sequence-number rewriting middleboxes, who do not modify the > sequence-number in the SACK-blocks. > Duplicate acknowledgments with these (invalid) SACK-blocks will not be > accounted in sacked_out, and thus no fast-retransmit will trigger. > So, the only way to recover from a packet-loss is through an RTO, > effectively killing the performance of TCP in this case. > > Performance-results can be seen here: > http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf > > Another solution might be to simply disable SACK, as soon as an invalid > SACK-block has been received (as suggested by Phil Oester). This however > might be too aggressive. > > Christoph Paasch (2): > Use acked_out for reno-style ack acounting instead of sacked_out > Account acked_out in sack, if the sack is invalid > > include/linux/tcp.h | 1 + > include/net/tcp.h | 17 +++++--- > net/ipv4/tcp_input.c | 103 ++++++++++++++++++++++++++++++++--------------- > net/ipv4/tcp_minisocks.c | 1 + > net/ipv4/tcp_output.c | 6 +-- > net/ipv4/tcp_timer.c | 2 +- > 6 files changed, 89 insertions(+), 41 deletions(-) I tested this patchset, and, unfortunately, the behavior seems to be the same. I'm still planning on working with the Cisco device, when I can get some of the network admin's time, but that won't happen immediately. Thanks, Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks 2013-08-19 21:22 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Corey Hickey @ 2013-08-20 7:36 ` Christoph Paasch 0 siblings, 0 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-20 7:36 UTC (permalink / raw) To: Corey Hickey; +Cc: Eric Dumazet, netdev, Phil Oester, Benjamin Hesmans On 19/08/13 - 14:22:46, Corey Hickey wrote: > On 2013-08-19 12:29, Christoph Paasch wrote: > > There exist sequence-number rewriting middleboxes, who do not modify the > > sequence-number in the SACK-blocks. > > Duplicate acknowledgments with these (invalid) SACK-blocks will not be > > accounted in sacked_out, and thus no fast-retransmit will trigger. > > So, the only way to recover from a packet-loss is through an RTO, > > effectively killing the performance of TCP in this case. > > > > Performance-results can be seen here: > > http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf > > > > Another solution might be to simply disable SACK, as soon as an invalid > > SACK-block has been received (as suggested by Phil Oester). This however > > might be too aggressive. > > > > Christoph Paasch (2): > > Use acked_out for reno-style ack acounting instead of sacked_out > > Account acked_out in sack, if the sack is invalid > > > > include/linux/tcp.h | 1 + > > include/net/tcp.h | 17 +++++--- > > net/ipv4/tcp_input.c | 103 ++++++++++++++++++++++++++++++++--------------- > > net/ipv4/tcp_minisocks.c | 1 + > > net/ipv4/tcp_output.c | 6 +-- > > net/ipv4/tcp_timer.c | 2 +- > > 6 files changed, 89 insertions(+), 41 deletions(-) > > I tested this patchset, and, unfortunately, the behavior seems to be the > same. Yes, because the problem is still on conntrack's side too. As soon as conntrack will let pass the invalid SACK-blocks, you will experience bad performance because every packet-loss can only be recovered by an RTO. My patchset tries to fix this last issue. Cheers, Christoph > > I'm still planning on working with the Cisco device, when I can get some > of the network admin's time, but that won't happen immediately. > > Thanks, > Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch ` (2 preceding siblings ...) 2013-08-19 21:22 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Corey Hickey @ 2013-08-22 3:32 ` David Miller 2013-08-22 4:15 ` Corey Hickey 3 siblings, 1 reply; 32+ messages in thread From: David Miller @ 2013-08-22 3:32 UTC (permalink / raw) To: christoph.paasch Cc: eric.dumazet, netdev, kernel, bugfood-ml, benjamin.hesmans From: Christoph Paasch <christoph.paasch@uclouvain.be> Date: Mon, 19 Aug 2013 21:29:26 +0200 > There exist sequence-number rewriting middleboxes, who do not modify the > sequence-number in the SACK-blocks. These are bugs that the vendor's should fix, not something we should cater to at all. I'm not applying patches like these, and I've rejected similar workarounds in the past 18 years, so this position is strong and consistent. Sorry. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks 2013-08-22 3:32 ` David Miller @ 2013-08-22 4:15 ` Corey Hickey 0 siblings, 0 replies; 32+ messages in thread From: Corey Hickey @ 2013-08-22 4:15 UTC (permalink / raw) To: David Miller Cc: christoph.paasch, eric.dumazet, netdev, kernel, benjamin.hesmans On 2013-08-21 20:32, David Miller wrote: > From: Christoph Paasch <christoph.paasch@uclouvain.be> > Date: Mon, 19 Aug 2013 21:29:26 +0200 > >> There exist sequence-number rewriting middleboxes, who do not modify the >> sequence-number in the SACK-blocks. > > These are bugs that the vendor's should fix, not something we should > cater to at all. > > I'm not applying patches like these, and I've rejected similar > workarounds in the past 18 years, so this position is strong and > consistent. > > Sorry. That's not terrible for me; we'll most likely be turning off SEQ randomization on the FWSM, when we have time to make sure it doesn't break anything (which it shouldn't). -Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 13:58 ` Eric Dumazet 2013-08-19 14:35 ` Phil Oester @ 2013-08-19 14:43 ` Christoph Paasch 2013-08-19 20:13 ` Jozsef Kadlecsik 2 siblings, 0 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 14:43 UTC (permalink / raw) To: Eric Dumazet Cc: Corey Hickey, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 19/08/13 - 06:58:05, Eric Dumazet wrote: > On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as > > duplicate acks in tcp_sock->sacked_out. > > Yeah, but here, this is conntrack who is blocking the thing. Yes, of course. I know that here conntrack is blocking the dup-ACKs. Sorry for having added TCP-stack specific things in a conntrack-thread. I just wanted to highlight that the TCP-stack has also problems with sequence-number rewriting middleboxes. > TCP receiver has no chance to 'fix' it. > > See conntrack is one of those buggy middle box as well. > > So if you want to properly handle this mess, you'll also have to fix > conntrack. ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 13:58 ` Eric Dumazet 2013-08-19 14:35 ` Phil Oester 2013-08-19 14:43 ` NAT stops forwarding ACKs after PMTU discovery Christoph Paasch @ 2013-08-19 20:13 ` Jozsef Kadlecsik 2013-08-19 20:43 ` Christoph Paasch 2013-08-19 21:08 ` Eric Dumazet 2 siblings, 2 replies; 32+ messages in thread From: Jozsef Kadlecsik @ 2013-08-19 20:13 UTC (permalink / raw) To: Eric Dumazet Cc: Christoph Paasch, Corey Hickey, Linux Netdev List, netfilter-devel On Mon, 19 Aug 2013, Eric Dumazet wrote: > On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as > > duplicate acks in tcp_sock->sacked_out. > > Yeah, but here, this is conntrack who is blocking the thing. > > TCP receiver has no chance to 'fix' it. > > See conntrack is one of those buggy middle box as well. > > So if you want to properly handle this mess, you'll also have to fix > conntrack. I beg you pardon: why conntrack should be relaxed, when it is expected to do more strict TCP checkings (RFC5961, Section 5.). Also, it's clearly a broken middle box. Don't shoot the messenger. Best regards, Jozsef - E-mail : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences H-1525 Budapest 114, POB. 49, Hungary ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 20:13 ` Jozsef Kadlecsik @ 2013-08-19 20:43 ` Christoph Paasch 2013-08-19 21:08 ` Eric Dumazet 1 sibling, 0 replies; 32+ messages in thread From: Christoph Paasch @ 2013-08-19 20:43 UTC (permalink / raw) To: Jozsef Kadlecsik Cc: Eric Dumazet, Corey Hickey, Linux Netdev List, netfilter-devel On 19/08/13 - 22:13:59, Jozsef Kadlecsik wrote: > On Mon, 19 Aug 2013, Eric Dumazet wrote: > > > On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > > > > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as > > > duplicate acks in tcp_sock->sacked_out. > > > > Yeah, but here, this is conntrack who is blocking the thing. > > > > TCP receiver has no chance to 'fix' it. > > > > See conntrack is one of those buggy middle box as well. > > > > So if you want to properly handle this mess, you'll also have to fix > > conntrack. > > I beg you pardon: why conntrack should be relaxed, when it is expected > to do more strict TCP checkings (RFC5961, Section 5.). There is no mention of SACK in this RFC. The duplicate ACKs with invalid SACK-blocks are valid with respect to RFC5961, Section 5. Actually, no RFC says that dup-ACKs with invalid SACK-blocks should be discarded. Cheers, Christoph ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 20:13 ` Jozsef Kadlecsik 2013-08-19 20:43 ` Christoph Paasch @ 2013-08-19 21:08 ` Eric Dumazet 2013-08-19 22:07 ` Jozsef Kadlecsik 1 sibling, 1 reply; 32+ messages in thread From: Eric Dumazet @ 2013-08-19 21:08 UTC (permalink / raw) To: Jozsef Kadlecsik Cc: Christoph Paasch, Corey Hickey, Linux Netdev List, netfilter-devel On Mon, 2013-08-19 at 22:13 +0200, Jozsef Kadlecsik wrote: > On Mon, 19 Aug 2013, Eric Dumazet wrote: > > > On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > > > > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as > > > duplicate acks in tcp_sock->sacked_out. > > > > Yeah, but here, this is conntrack who is blocking the thing. > > > > TCP receiver has no chance to 'fix' it. > > > > See conntrack is one of those buggy middle box as well. > > > > So if you want to properly handle this mess, you'll also have to fix > > conntrack. > > I beg you pardon: why conntrack should be relaxed, when it is expected > to do more strict TCP checkings (RFC5961, Section 5.). > > Also, it's clearly a broken middle box. Don't shoot the messenger. Frames are dropped by conntrack, before TCP receiver can even have a choice. So Christoph patch would be of no use for Corey. I do not think I shot anyone, only stated the truth. We have workarounds in our stack to 'fix' bugs from others, there is no shame in this. Glad to see you are interested in RFC 5961 support, as conntrack is known to break the ACK challenges in response to RST messages (section 3) ^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 21:08 ` Eric Dumazet @ 2013-08-19 22:07 ` Jozsef Kadlecsik 2013-08-20 4:18 ` Corey Hickey 0 siblings, 1 reply; 32+ messages in thread From: Jozsef Kadlecsik @ 2013-08-19 22:07 UTC (permalink / raw) To: Eric Dumazet Cc: Christoph Paasch, Corey Hickey, Linux Netdev List, netfilter-devel On Mon, 19 Aug 2013, Eric Dumazet wrote: > On Mon, 2013-08-19 at 22:13 +0200, Jozsef Kadlecsik wrote: > > On Mon, 19 Aug 2013, Eric Dumazet wrote: > > > > > On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote: > > > > > > > It's a TCP-patch, that interprets duplicate-acks with invalid > > > > SACK-blocks as duplicate acks in tcp_sock->sacked_out. > > > > > > Yeah, but here, this is conntrack who is blocking the thing. > > > > > > TCP receiver has no chance to 'fix' it. > > > > > > See conntrack is one of those buggy middle box as well. > > > > > > So if you want to properly handle this mess, you'll also have to fix > > > conntrack. > > > > I beg you pardon: why conntrack should be relaxed, when it is expected > > to do more strict TCP checkings (RFC5961, Section 5.). > > > > Also, it's clearly a broken middle box. Don't shoot the messenger. > > Frames are dropped by conntrack, before TCP receiver can even have a > choice. > > So Christoph patch would be of no use for Corey. Yes, exactly. > I do not think I shot anyone, only stated the truth. There's a middlebox in the path wich breaks SACK completely and conntrack drops (technically marks as INVALID) the packets with bogus SACK options. It can be fixed by fixing the middlebox, or disabling SACK by the TCPOPTSTRIP target, or by relaxing conntrack. For the latter, the next untested patch may be sufficient: diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 7dcc376..8b5d783 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -649,6 +649,11 @@ static bool tcp_in_window(const struct nf_conn *ct, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); + /* Fall back to ACK when SACK is bogus */ + if (!(before(sack, receiver->td_end + 1) && + after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1))) + sack = ack; + pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), after(end, sender->td_end - receiver->td_maxwin - 1), However it is good to cover the issue thus? > We have workarounds in our stack to 'fix' bugs from others, there > is no shame in this. > > Glad to see you are interested in RFC 5961 support, as conntrack is > known to break the ACK challenges in response to RST messages (section > 3) *Any* netfilter configuration where the non-allowed TCP packets are dropped and not rejected breaks the ACK challenges. That is why I consider only section 5 useful from RFC 5961. Best regards, Jozsef - E-mail : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences H-1525 Budapest 114, POB. 49, Hungary ^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 22:07 ` Jozsef Kadlecsik @ 2013-08-20 4:18 ` Corey Hickey 0 siblings, 0 replies; 32+ messages in thread From: Corey Hickey @ 2013-08-20 4:18 UTC (permalink / raw) To: Jozsef Kadlecsik Cc: Eric Dumazet, Christoph Paasch, Linux Netdev List, netfilter-devel On 2013-08-19 15:07, Jozsef Kadlecsik wrote: > It can be fixed by fixing the middlebox, or disabling SACK by the > TCPOPTSTRIP target, or by relaxing conntrack. For the latter, the next > untested patch may be sufficient: > > diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c > index 7dcc376..8b5d783 100644 > --- a/net/netfilter/nf_conntrack_proto_tcp.c > +++ b/net/netfilter/nf_conntrack_proto_tcp.c > @@ -649,6 +649,11 @@ static bool tcp_in_window(const struct nf_conn *ct, > receiver->td_end, receiver->td_maxend, receiver->td_maxwin, > receiver->td_scale); > > + /* Fall back to ACK when SACK is bogus */ > + if (!(before(sack, receiver->td_end + 1) && > + after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1))) > + sack = ack; > + > pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", > before(seq, sender->td_maxend + 1), > after(end, sender->td_end - receiver->td_maxwin - 1), > > However it is good to cover the issue thus? This didn't quite apply to my kernel tree, but I let patch apply it with fuzz=2 and got: diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 2f80107..94b326b 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -653,6 +653,11 @@ static bool tcp_in_window(const struct nf_conn *ct, in_recv_win = !receiver->td_maxwin || after(end, sender->td_end - receiver->td_maxwin - 1); + /* Fall back to ACK when SACK is bogus */ + if (!(before(sack, receiver->td_end + 1) && + after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1))) + sack = ack; + pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), (in_recv_win ? 1 : 0), I can confirm, that does indeed work! Thank you. I will continue watching this thread for other things to test, if need be. -Corey ^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: NAT stops forwarding ACKs after PMTU discovery 2013-08-19 12:33 ` Christoph Paasch 2013-08-19 13:24 ` Eric Dumazet @ 2013-08-19 18:22 ` Corey Hickey 1 sibling, 0 replies; 32+ messages in thread From: Corey Hickey @ 2013-08-19 18:22 UTC (permalink / raw) To: Christoph Paasch Cc: Eric Dumazet, Jozsef Kadlecsik, Linux Netdev List, netfilter-devel On 2013-08-19 05:33, Christoph Paasch wrote: > Hello, > > I would say, the problem is due to a sequence-number rewriting > middlebox, who does not correctly handle the SACK-blocks. > > In remote.pcap, you see: > Packet#10: A Dup-ACK: ACK 1005503816, SACK: 1005505184-1005505648 > The SACK actually covers Packet#9 > > In tun0.pcap, you have: > Packet#9: The one that is SACK'ed: SEQ: 3514869772 > Packet#11: The Dup-ACK: ACK: 3514868404, SACK: 3570452498-3570452962 > > You can see that the SACK-block is not really aligned with the ACK-numbers. > > Netfilter is probably dropping the Dup-ACK, because the SACK-block is > acknowledging unseen data. > > > There are middleboxes out there that randomize the sequence numbers, due to > an old bug in Windows, where the initial sequence number was not > sufficiently randomized. There are some of these middleboxes, who simply do > not support SACK, thus modify only the sequence numbers of the TCP-header > (https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK). > > This results in a TCP retransmission timeout on the sender, because of > the invalid SACK-blocks, the duplicate ACKs are not accounted. This > completly kills the performance, as you can see in our presentation given at > IETF87: http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf This makes good sense. I normally look at these in wireshark with relative sequence numbers turned on, and I see in bad/tun0.pcap that the SACK values are very high, but are normal in bad/remote.pcap. I see the same thing in good/tun0.pcap, though, so I don't fully understand what is making it work sometimes and not others. I will show this thread and the Cisco docs to the network engineer at work, and maybe we can get the SEQ randomization turned off (or at least test it). > We have a patch that accounts DUP-ACKs with invalid SACK-blocks effectively > as duplicate acknowledgments. I can send the patches, if the > netdev-community is interested in accepting these upstream. I'll keep my eye out and test them if they come up. Thanks, Corey ^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2013-08-22 4:15 UTC | newest] Thread overview: 32+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-08-18 5:55 NAT stops forwarding ACKs after PMTU discovery Corey Hickey 2013-08-18 15:24 ` Eric Dumazet 2013-08-18 16:59 ` Corey Hickey 2013-08-18 21:23 ` Jozsef Kadlecsik 2013-08-19 0:00 ` Eric Dumazet 2013-08-19 0:03 ` Eric Dumazet 2013-08-19 8:43 ` Corey Hickey 2013-08-19 12:33 ` Christoph Paasch 2013-08-19 13:24 ` Eric Dumazet 2013-08-19 13:49 ` Christoph Paasch 2013-08-19 13:58 ` Eric Dumazet 2013-08-19 14:35 ` Phil Oester 2013-08-19 15:32 ` Eric Dumazet 2013-08-19 15:33 ` Christoph Paasch 2013-08-19 16:00 ` Eric Dumazet 2013-08-19 17:15 ` Christoph Paasch 2013-08-19 18:00 ` Phil Oester 2013-08-19 18:10 ` Eric Dumazet 2013-08-19 19:29 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Christoph Paasch 2013-08-19 19:29 ` [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out Christoph Paasch 2013-08-19 19:29 ` [RFC 2/2] Account acked_out in sack, if the sack is invalid Christoph Paasch 2013-08-19 21:22 ` [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks Corey Hickey 2013-08-20 7:36 ` Christoph Paasch 2013-08-22 3:32 ` David Miller 2013-08-22 4:15 ` Corey Hickey 2013-08-19 14:43 ` NAT stops forwarding ACKs after PMTU discovery Christoph Paasch 2013-08-19 20:13 ` Jozsef Kadlecsik 2013-08-19 20:43 ` Christoph Paasch 2013-08-19 21:08 ` Eric Dumazet 2013-08-19 22:07 ` Jozsef Kadlecsik 2013-08-20 4:18 ` Corey Hickey 2013-08-19 18:22 ` Corey Hickey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).