// Limited transmit KASSERT "sent too much" from tcp_maxseg() overestimating // SACK option space: no timestamps, five SACK blocks pending, one full // segment sent after an RTO. Panics an INVARIANTS kernel without the fix. --ip_version=ipv4 0.000 `sysctl -w net.inet.tcp.hostcache.purgenow=1` +0.000 `sysctl -w net.inet.tcp.syncookies_only=0` +0.000 `sysctl -w net.inet.tcp.syncookies=1` +0.000 `sysctl -w net.inet.tcp.sack.enable=1` +0.000 `sysctl -w net.inet.tcp.functions_default=freebsd` +0.000 `sysctl -w net.inet.tcp.cc.algorithm=cubic` +0.000 `sysctl -w kern.timecounter.alloweddeviation=0` +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 // No timestamps, no window scaling; t_maxseg = 1000. +0.000 < S 0:0(0) win 65535 +0.000 > S. 0:0(0) ack 1 win 65535 <...> +0.050 < . 1:1(0) ack 1 win 65535 +0.000 accept(3, ..., ...) = 4 +0.000 close(3) = 0 // Five out-of-order blocks: rcv_numsacks = 5, only 4 fit on the wire. +0.000 < . 101:201(100) ack 1 win 65535 +0.000 > . 1:1(0) ack 1 <...> +0.000 < . 301:401(100) ack 1 win 65535 +0.000 > . 1:1(0) ack 1 <...> +0.000 < . 501:601(100) ack 1 win 65535 +0.000 > . 1:1(0) ack 1 <...> +0.000 < . 701:801(100) ack 1 win 65535 +0.000 > . 1:1(0) ack 1 <...> +0.000 < . 901:1001(100) ack 1 win 65535 +0.000 > . 1:1(0) ack 1 <...> // One small segment, lost; the RTO leaves cwnd = 1000, t_rxtshift = 1. +0.000 send(4, ..., 300, 0) = 300 +0.000 > P. 1:301(300) ack 1 <...> +1.000~+1.200 > P. 1:301(300) ack 1 <...> // 700 bytes of cwnd left, below a full segment, so Nagle holds the rest. +0.010 send(4, ..., 5000, 0) = 5000 // First dup ACK: limited transmit sends one full 964-byte segment // (1000 - 36 bytes of options), while tcp_maxseg() said 960. +0.010 < . 1:1(0) ack 1 win 65535 +0.000 > . 301:1265(964) ack 1 <...>