Create a pkt drill script that does the mtu change and sacks the last bytes
and then stops talking. We can then monitor to make sure we only retransmit one time.
This packet drill script shows the problem without the patch, it will not get a TLP but get a retransmit of the first packet
(which would in theory loop forever).
// Copyright (c) 2018 Randall Stewart
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
--ip_version=ipv4
0.00 `kldload -n tcp_bbr tcp_rack`
+0.00 `sysctl -w net.inet.tcp.hostcache.purgenow=1`
+0.00 `sysctl -w net.inet.tcp.syncookies_only=0`
+0.00 `sysctl -w net.inet.tcp.syncookies=1`
+0.00 `sysctl -w net.inet.tcp.rfc1323=1`
+0.00 `sysctl -w net.inet.tcp.sack.enable=1`
+0.00 `sysctl -w net.inet.tcp.ecn.enable=2`
// Create a TCP endpoint in the ESTABLISHED state.
+0.00 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0.00 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR)
+0.00 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0
+0.00 setsockopt(3, IPPROTO_TCP, TCP_LOG, [4], 4) = 0
+0.00 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+0.00 > S 0:0(0) win 65535 <mss 1460,nop,wscale 8,sackOK,TS val 100 ecr 0>
+0.10 < S. 0:0(0) ack 1 win 32767 <mss 1440,sackOK,TS val 400 ecr 100>
+0.00 > . 1:1(0) ack 1 win 65535 <nop,nop,TS val 200 ecr 400>
// Change to rack_latest
+0.00 setsockopt(3, IPPROTO_TCP, TCP_NODELAY, [1], 4) = 0
+0.00 setsockopt(3, IPPROTO_TCP, TCP_FUNCTION_BLK, {function_set_name="rack", pcbcnt=0}, 36) = 0
+0.00 send(3, ..., 1000, 0) = 1000
+0.00 > P. 1:1001(1000) ack 1 win 65535 <nop,nop,TS val 250 ecr 400>
+.10 < . 1:1(0) ack 1001 win 32000 <nop, nop, TS val 500 ecr 250>
+0.00 send(3, ..., 1000, 0) = 1000
+0.00 > P. 1001:2001(1000) ack 1 win 65535 <nop,nop,TS val 300 ecr 500>
+.10 < . 1:1(0) ack 2001 win 32000 <nop, nop, TS val 600 ecr 300>
+0.10 send(3, ..., 9700, 0) = 9700
* > . 2001:3429(1428) ack 1 win 65535 <nop,nop,TS val 400 ecr 600>
* > . 3429:4857(1428) ack 1 win 65535 <nop,nop,TS val 500 ecr 600>
* > . 4857:6285(1428) ack 1 win 65535 <nop,nop,TS val 600 ecr 600>
* > . 6285:7713(1428) ack 1 win 65535 <nop,nop,TS val 700 ecr 600>
* > . 7713:9141(1428) ack 1 win 65535 <nop,nop,TS val 800 ecr 600>
* > . 9141:10569(1428) ack 1 win 65535 <nop,nop,TS val 900 ecr 600>
* > P. 10569:11701(1132) ack 1 win 65535 <nop,nop,TS val 1000 ecr 600>
+0.00 < [2001:3429(1428)] icmp unreachable frag_needed mtu 1200
+0.00 < . 1:1(0) ack 2001 win 32000 <nop, nop, TS val 700 ecr 300, nop, nop, sack 10569:11701>
* > . 2001:3149(1148) ack 1 win 65535 <nop,nop,TS val 1100 ecr 600>
* > . 3149:3429(280) ack 1 win 65535 <nop,nop,TS val 1200 ecr 700>
* > . 3429:4577(1148) ack 1 win 65535 <nop,nop,TS val 1300 ecr 700>
* > . 4577:4857(280) ack 1 win 65535 <nop,nop,TS val 1400 ecr 700>
* > . 4857:6005(1148) ack 1 win 65535 <nop,nop,TS val 1400 ecr 700>
* > . 6005:6285(280) ack 1 win 65535 <nop,nop,TS val 1400 ecr 700>
* > . 6285:7433(1148) ack 1 win 65535 <nop,nop,TS val 1500 ecr 700>
* > . 7433:7713(280) ack 1 win 65535 <nop,nop,TS val 1500 ecr 700>
* > . 7713:8861(1148) ack 1 win 65535 <nop,nop,TS val 1600 ecr 700>
* > . 8861:9141(280) ack 1 win 65535 <nop,nop,TS val 1600 ecr 700>
* > . 9141:10289(1148) ack 1 win 65535 <nop,nop,TS val 1700 ecr 700>
* > . 10289:10569(280) ack 1 win 65535 <nop,nop,TS val 1900 ecr 700>
* > . 10289:10569(280) ack 1 win 65535 <nop,nop,TS val 2000 ecr 700>
+.10 < . 1:1(0) ack 11701 win 32000 <nop, nop, TS val 800 ecr 2000>
// Tear it down.
+0.00 close(3) = 0
+0.00 > F. 11701:11701(0) ack 1 win 65535 <nop,nop,TS val 2100 ecr 800>
+0.10 < F. 1:1(0) ack 11702 win 32767 <nop,nop,TS val 900 ecr 2100>
+0.00 > . 11702:11702(0) ack 2 win 65535 <nop,nop,TS val 2200 ecr 900>