| // SPDX-License-Identifier: GPL-2.0 |
| // When tcp_receive_window() < tcp_max_receive_window(), tcp_sequence() accepts |
| // packets that would be dropped under normal conditions (i.e. tcp_receive_window() |
| // equal to tcp_max_receive_window()). |
| // Test that such packets are handled as expected for RWIN == 0 and for RWIN > 0. |
| |
| --mss=1000 |
| |
| `./defaults.sh` |
| |
| 0 `nstat -n` |
| |
| // Establish a connection. |
| +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 |
| +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 |
| +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1000000], 4) = 0 |
| +0 bind(3, ..., ...) = 0 |
| +0 listen(3, 1) = 0 |
| |
| +0 < S 0:0(0) win 32792 <mss 1000,nop,nop,sackOK,nop,wscale 7> |
| +0 > S. 0:0(0) ack 1 win 65535 <mss 1460,nop,nop,sackOK,nop,wscale 4> |
| +0 < . 1:1(0) ack 1 win 257 |
| |
| +0 accept(3, ..., ...) = 4 |
| |
| // Put 1040000 bytes into the receive buffer |
| +0 < P. 1:65001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 65001 |
| +0 < P. 65001:130001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 130001 |
| +0 < P. 130001:195001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 195001 |
| +0 < P. 195001:260001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 260001 |
| +0 < P. 260001:325001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 325001 |
| +0 < P. 325001:390001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 390001 |
| +0 < P. 390001:455001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 455001 |
| +0 < P. 455001:520001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 520001 |
| +0 < P. 520001:585001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 585001 |
| +0 < P. 585001:650001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 650001 |
| +0 < P. 650001:715001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 715001 |
| +0 < P. 715001:780001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 780001 |
| +0 < P. 780001:845001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 845001 |
| +0 < P. 845001:910001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 910001 |
| +0 < P. 910001:975001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 975001 |
| +0 < P. 975001:1040001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 1040001 |
| |
| // Trigger an extreme memory squeeze by shrinking SO_RCVBUF |
| +0 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [16000], 4) = 0 |
| |
| +0 < P. 1040001:1105001(65000) ack 1 win 257 |
| * > . 1:1(0) ack 1040001 win 0 |
| // Check LINUX_MIB_TCPRCVQDROP has been incremented |
| +0 `nstat -s | grep TcpExtTCPRcvQDrop| grep -q " 1 "` |
| |
| // RWIN == 0: rcv_wup = 1040001, rcv_wnd = 0, rcv_mwnd_seq > 1105001 (significantly larger, typically ~1970000) |
| |
| // Accept pure ack with seq in max adv. window |
| +0 write(4, ..., 1000) = 1000 |
| +0 > P. 1:1001(1000) ack 1040001 win 0 |
| +0 < . 1105001:1105001(0) ack 1001 win 257 |
| |
| // In order segment, in max adv. window -> drop (SKB_DROP_REASON_TCP_ZEROWINDOW) |
| +0 < P. 1040001:1041001(1000) ack 1001 win 257 |
| +0 > . 1001:1001(0) ack 1040001 win 0 |
| // Ooo partial segment, in max adv. window -> drop (SKB_DROP_REASON_TCP_ZEROWINDOW) |
| +0 < P. 1039001:1041001(2000) ack 1001 win 257 |
| +0 > . 1001:1001(0) ack 1040001 win 0 <nop,nop,sack 1039001:1040001> |
| // Check LINUX_MIB_TCPZEROWINDOWDROP has been incremented twice |
| +0 `nstat -s | grep TcpExtTCPZeroWindowDrop| grep -q " 2 "` |
| |
| // Ooo segment, in max adv. window -> drop (SKB_DROP_REASON_TCP_OVERWINDOW) |
| +0 < P. 1105001:1106001(1000) ack 1001 win 257 |
| +0 > . 1001:1001(0) ack 1040001 win 0 |
| // Ooo segment, beyond max adv. window -> drop (SKB_DROP_REASON_TCP_INVALID_SEQUENCE) |
| +0 < P. 2000001:2001001(1000) ack 1001 win 257 |
| +0 > . 1001:1001(0) ack 1040001 win 0 |
| // Check LINUX_MIB_BEYOND_WINDOW has been incremented twice |
| +0 `nstat -s | grep TcpExtBeyondWindow | grep -q " 2 "` |
| |
| // Read all data |
| +0 read(4, ..., 2000000) = 1040000 |
| * > . 1001:1001(0) ack 1040001 |
| |
| // RWIN > 0: rcv_wup = 1040001, 0 < rcv_wnd < 32000, rcv_mwnd_seq > 1105001 (significantly larger, typically ~1970000) |
| |
| // Accept pure ack with seq in max adv. window, beyond adv. window |
| +0 write(4, ..., 1000) = 1000 |
| +0 > P. 1001:2001(1000) ack 1040001 |
| +0 < . 1105001:1105001(0) ack 2001 win 257 |
| |
| // In order segment, in max adv. window, in adv. window -> accept |
| // Note: This also ensures that we cannot hit the empty queue exception in tcp_sequence() in the following tests |
| +0 < P. 1040001:1041001(1000) ack 2001 win 257 |
| * > . 2001:2001(0) ack 1041001 |
| |
| // Ooo partial segment, in adv. window -> accept |
| +0 < P. 1040001:1042001(2000) ack 2001 win 257 |
| +0 > . 2001:2001(0) ack 1042001 <nop,nop,sack 1040001:1041001> |
| |
| // Ooo segment, in max adv. window, beyond adv. window -> drop (SKB_DROP_REASON_TCP_OVERWINDOW) |
| +0 < P. 1105001:1106001(1000) ack 2001 win 257 |
| +0 > . 2001:2001(0) ack 1042001 |
| // Ooo segment, beyond max adv. window, beyond adv. window -> drop (SKB_DROP_REASON_TCP_INVALID_SEQUENCE) |
| +0 < P. 2000001:2001001(1000) ack 2001 win 257 |
| +0 > . 2001:2001(0) ack 1042001 |
| // Check LINUX_MIB_BEYOND_WINDOW has been incremented twice |
| +0 `nstat -s | grep TcpExtBeyondWindow | grep -q " 4 "` |
| |
| // We are allowed to go beyond the window and buffer with one packet |
| +0 < P. 1042001:1062001(20000) ack 2001 win 257 |
| * > . 2001:2001(0) ack 1062001 |
| +0 < P. 1062001:1082001(20000) ack 2001 win 257 |
| * > . 2001:2001(0) ack 1082001 win 0 |
| |
| // But not more: In order segment, in max adv. window -> drop (SKB_DROP_REASON_TCP_ZEROWINDOW) |
| +0 < P. 1082001:1083001(1000) ack 2001 win 257 |
| * > . 2001:2001(0) ack 1082001 |
| // Check LINUX_MIB_TCPZEROWINDOWDROP has been incremented again |
| +0 `nstat -s | grep TcpExtTCPZeroWindowDrop| grep -q " 3 "` |