TL;DR - The Arris SB6183 cable modem is dropping IPv6 TCP traffic with the timestamp TCP option. See the "Workarounds" section for possible workarounds.
13 months later (October 2016), my modem was updated to D30CM-OSPREY-22.214.171.124-GA-01-NOSH. IPv6 tests show this problem is fixed with this firmware.
I have an SB6183 cable modem, and it's been dropping my IPv6 traffic. It only seems to affect TCP packets with the timestamp option set. To get some data on what's happening, I added the ability to set the TCP options in nping.
First, three different servers without the timestamp option.
The outgoing packet looks like this:
SENT (0.0271s) TCP [local]:33275 > [remote]:5001 S seq=1810675513 win=1480 <mss 1440,nop,nop,sackOK,nop,wscale 7>
There's ten probes sent to every destination every two minutes, so 10% loss is 1 out of 10 without a response. After a little over 24 hours, you can see there's not much loss. Linode Dallas ended up with the most loss, 120 packets lost out of 7220 (1.6%). I believe this is actually from congestion on their IPv6 path, as a ping6 has a similiar result. AT&T ended up with 6 out of 7220 (less than 0.1%) and Centurylink lost 26 (0.3%).
At the same time, TCP packets with timestamps were sent to the same destination.
The request packets looked like this:
SENT (0.0266s) TCP [local]:19424 > [remote]:5001 S seq=4229376706 win=1480 <mss 1440,sackOK,timestamp 1 0,nop,wscale 7>
A incrementing timestamp value was used to make it easier to match up the lost packets on the server side. Comparing packet loss by running tcpdump on both sides for a few minutes, it was all in the transmit direction (from my home network out the cable modem) rather than the response (from the cable modem into my home network).
On average, there was around 21%-25% packet loss. But you can see the amount of loss doesn't look random at all, it looks like there's some correlation with the time of day. This sucks when each SYN packet lost adds at least 1 second delay. Happy eyeballs can hide this for web browsers, but not everything has happy eyeballs enabled. This also sucks for web applications who tie your session to your IP address (which is a problem for other reasons too)
Looking closer at the TCP options, the modem is actually rewriting them. For example:
client sent: win 1480, options [wscale 7,nop] server received: win 2940, options [wscale 8,eol]
It's changing both the window and the window scaling. If you've ever seen the message
Peer X unexpectedly shrunk window Y (repaired) in Linux's dmesg (I think it was removed somewhere in 2.6.x), it might have been a cable modem rewriting the window scale without telling the endpoints. This would result in the window closing 2x faster than expected.
The modem also seems to be rewriting syn-ack packet responses:
server sent: win 14120, options [mss 1412,nop,nop,sackOK,nop,wscale 5] client recieved: win 15532, options [mss 1412,sackOK,wscale 6,eol]
This rewriting of windows bug is annoying in principal, but should be benign. TCP will think its windows are bigger, and will probably lead to more retransmissions but it'll mostly "work".
The rewriting of the TCP window and wscale happens on both IPv6 and IPv4. Oddly, the timestamp bug doesn't hit IPv4 traffic, only IPv6.
Windows: by default, TCP timestamps are disabled
echo net.ipv4.tcp_timestamps=0 >/etc/sysctl.d/tcp_timestamps.conf ; sysctl -p /etc/sysctl.d/tcp_timestamps.conf
Non Rooted Android, Roku, ChromeOS, and other embedded Linux: can't change this setting on those platforms, see below for more options
Switching cable modems: The Arris SB6141 and Arris SB6121 don't have this issue. They both use a different chipset, the Texas Instruments TNETC4830.
Stripping the TCP Timestamp from IPv6 traffic at your router - just changing to the NOP tcp option wasn't working, I created a custom iptables rule that changes the TCP timestamp option to the experimental option 253.
Credit should go to this thread on DSLReports for finding this issue first. It seems to be a problem with the Broadcom firmware on the SB6183 (chipset: BCM3383D). Comcast is pushing out the update in stages, and Time Warner Cable is working with Arris on an updated Firmware.
Other TCP options tested
To test very long tcp options, I used the MD5 signature option (rfc2385) because it is 18 bytes long.
sender: md5:d41d8cd98f00b204e9800998ecf8427e,sackOK,wscale 7,nop,mss 1440
The modem did not rewrite this packet, and there was no packet loss.
Next up, TCP Option 253 is reserved for experiments, so I sent one 10 bytes long to match the size of the timestamp option.
sender: unknown-253 0x0000000000000000,mss 1440,wscale 7,nop,nop,nop
This also was not rewritten, and there was no packet loss.
Changing this to a 4 byte TCP Option 253:
sender: win 1480, options [unknown-253 0x0000,mss 1440,wscale 7,nop] receiver: win 2920, options [unknown-253 0x0000,mss 1440,wscale 8,eol]
So it was rewritten, but still had no packet loss.
Next, I played with setting different wscale and window values. When it rewrote the packets, the modem would always add around 1400 bytes to the window value in the header and add 1 to the wscale value.
sender: win 1000, options [wscale 1,nop] receiver: win 2460, options [wscale 2,eol] sender: win 1480, options [wscale 7,nop] receiver: win 2940, options [wscale 8,eol]
What happens at max wscale (255)?
sender: win 1480, options [wscale 255,nop] receiver: win 2940, options [wscale 0,eol]
Oops, it wraps to 0. Still, this specific bug probably won't get triggered as window scale sizes over 14 are considered invalid in rfc7323.
They've considered what happens at max window size at least:
sender: win 65000, options [wscale 1,nop] receiver: win 65535, options [wscale 2,eol] sender: win 65535, options [wscale 1,nop] receiver: win 65535, options [wscale 1,nop]
That last one is interesting because not only did it leave the window size the same, it also didn't change either of the two TCP options.
With the TCPOPTSTRIP workaround applied:
sender: win 1480, options [mss 1440,sackOK,timestamp 1 0,nop,wscale 7] router rewrite: win 1480, options [mss 1440,sackOK,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,wscale 7] receiver: win 1480, options [mss 1440,sackOK,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,wscale 7]
This makes it through without the window scale rewrite, and does not experience packet loss.