Adventures in Linux TCP Tuning
This site is no longer being maintained so anything below could still be accurate, or very outdated.
Most of the settings I decided on for the laptop are under this Hard title and these are the most significant changes for performance and security. Changing the Soft switches further down the page may be beneficial or desirable but none are necessary and these settings should fit into any Linux distro with kernel 2.6 or newer.
Here's how the sysctl hierarchy works in Debian and Ubuntu-based distros. What's hard-coded into the kernel are obviously the defaults. However, some kernel variables are overridden by settings in the 10-* files located in /etc/sysctl.d/ which come from the essential procps package. Then /etc/sysctl.conf (which does nothing by default) can override anything in the kernel or the procps files. According to this, systemd (at least, in Arch) is supposed to ignore /etc/sysctl.conf but in Debian and Ubuntu, I've not found this to be true.
A Quick Detour for ufw
If you have ufw installed, then you have two sysctl files: one located in /etc/ and the other in /etc/ufw/. When ufw is enabled, its sysctl file becomes active and overrides some of the kernel defaults. ufw's sysctl file says that it overrides anything in the system sysctl file but I've found this to be false. ufw's sysctl file can do anything /etc/sysctl.conf can do, but the system's file seems to always take precedence. From there, sometimes applications themselves are written with their own TCP/UDP properties and these can take precedence over any sysctl file settings.
Enabling ufw also loads several conntrack kernel modules at boot for FTP and NetBIOS connection tracking. ufw was created by Canonical so it's installed in most Ubuntu-based distros by default. It's disabled by default so its sysctl file is inactive. Debian doesn't have ufw installed.
For systems with ufw enabled, you have three options: 1) Switch off ufw's sysctl file so that IPtables goes straight for /etc/sysctl.conf. 2) Forget about /etc/sysctl.conf and put all your changes in /etc/ufw/sysctl.conf. 3) Use both. Ufw's sysctl file only does three things: It switches off ICMP redirects, SYN cookies and drops source routing packets. I suggest that the best option is 1—to bypass ufw's sysctl file and use /etc/sysctl.conf since those same three things from ufw's file are already there, only commented out.
Here's how to disable ufw's sysctl file so from this point on, all sysctl changes will go in /etc/systl.conf.
gksudo gedit /etc/default/ufw
In the IPT backend section near the bottom, change the sysctl file from ufw's to the main system file.
# IPT backend # # only enable if using iptables backend IPT_SYSCTL=/etc/sysctl.conf
While you're in this ufw file, take a look at the IPT_MODULES line at the bottom. Comment this line out if you don't want to load the NetBIOS and FTP conntrack modules on boot.
To enable the changes, switch ufw off and then back on again
sudo ufw disable && sudo ufw enable
Hard Switches Continued
Now with less complexity, we can finally begin. Experiment as you like. This will not b0rk your internets but you should first make a backup copy of your config file. You shouldn't edit the sysctl.d files for anything listed here.
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak
Change maximum TCP receive window buffer size
net.core.rmem_max = 16777216
Default is 128 KB. The value is in bytes, changed to 16 MB.
Change maximum TCP send window buffer size
net.core.wmem_max = 16777216
Default is 128 KB. According to the Linux TCP man page, the maximum send and receive buffer sizes above override the maximum values in the next two strings so Ubuntu’s max window size is only 128 KB by default. Additionally, the default send/receive buffer sizes below (see the middle number) override net.core.wmem_default and net.core.rmem_default. The core window sizes I don’t get into here, but default to 224 KB.
Set the minimum, default (the advertised) and max receive buffer sizes
net.ipv4.tcp_rmem = 4096 87380 16777216
Default is 4 KB, 16 KB and 4 MB. The values are in bytes, changed to 4 KB, 82 KB and 16 MB. For reference, the advertised receive buffer size in Windows 7 and 8 is 64 KB and the max is 16 MB.
Set the min/default/max send buffer sizes
net.ipv4.tcp_wmem = 4096 87380 16777216
Default is 4 KB, 82 KB and 5.8 MB. I changed only the max to 16 MB.
Change TCP congestion avoidance algorithm
~OR~ something else ~OR~ nothing.
The default for Debian and Ubuntu is currently Cubic and that’s what you’ll be using if you don’t add this string. Some searching brought up studies concluding that TCP Vegas provided the best throughput compared to Cubic, BIC, Reno and several others (  ) so I thought it a good choice to look into. I was also particularly interested in TCP Westwood. It’s based on New Reno but optimized for large BDPs over lossy networks, (theoretically) perfect for public WiFi.
There are numerous other congestion algorithms (TCP Hamilton is often recommended and Windows uses Compound) but I went with Vegas on the laptop. On the two lossy wireless networks, it was fast though not quite as consistent as Cubic. I found Westwood to be unconvincing. There’s no right answer here though, and I do think that more testing would reveal that all three algorithms are closer than my numbers indicate. I could just as easily have kept Cubic or used whatever else and not tell any difference other than by record keeping.
To change your TCP congestion avoidance algorithm, you first need to load the correct module on boot because only Cubic and Reno are immediately available. Edit /etc/modules and add tcp_vegas or tcp_westwood or whatever other you prefer. This is in addition to adding the string to sysctl.conf as shown above.
Disable slow start threshold caching
net.ipv4.tcp_no_metrics_save = 1
From the man page, “…TCP saves various connection metrics in the route cache when the connection closes, so that connections established in the near future can use these to set initial conditions. Usually, this increases overall performance…” The default is 0, enabled.
I disabled this for my cURL downloads thinking it would better to use results not influenced by cached metrics, then set it back to 0 when finished. Personal computers (client machines) are the ones initiating connections, not the servers themselves. For devices used by people who frequent the same sites and favorite services, this would be useful to keep enabled.
Disable TCP Timestamps
net.ipv4.tcp_timestamps = 0
Timestamping is intended to more accurately measure RTT and prevent packets from falling out of sequence but it isn’t necessary on low speed connections. The Pittsburgh Supercomputing Center quotes RFC 6349 when they say, "Wrapped sequence numbers do not pose a serious risk below 100 Mb/s..." The default is 1, enabled.
Windows XP, 7 and 8 all disable TCP timestamping by default while Vista, Apple OS X and much Linux I’ve seen, do not. No timestamps means less CPU use and packet sizes are reduced by 12 bytes so you use less bandwidth. If you remember tSc’s fingerprinting article, you may also recall how network traffic fingerprinting through TCP timestamps can be performed. On the other hand, Deep Packet Inspection will reveal a Linux machine with a number of attributes which can be used to fingerprint it, one of which being the non-default setting of disabled TCP timestamps.
Though I disabled timestamps for all testing except for when running the default Ubuntu settings, I wonder if it would have helped with the two lossy networks. Since I didn’t examine specifically what the traffic was doing, I can’t say for sure.
Enable TCP MTU probing (PLPMTUD)
net.ipv4.tcp_mtu_probing = 1
From RFC 4821, PLPMTUD "...is a method for TCP or other Packetization Protocols to dynamically discover the MTU of a path by probing with progressively larger packets. By default, the Linux kernel’s MTU size is 1500 bytes and many routers use the same, but some don’t."
By setting this to 1, the traditional MTU path discovery (the ICMP method, same as if it were set to 0) is used until you encounter a router which doesn’t support your 1500 byte MTU size. When this happens, the progressive TCP packet sizing is used for that connection, which is called an ICMP black hole.
Setting this to 2 switches off ICMP path discovery and relies only on TCP MTU probing for every connection. IPv6 is heavily reliant on MTU discovery but for IPv4, it’s optional. To quote PSC again, "It [PLPMTUD] raises the robustness of RFC 1191 and RFC 1981 [ICMP] path MTU discovery with no significant downside" and they recommend using it, so I did. Default is 0, disabled.
Time-wait delay after assassination hazards
net.ipv4.tcp_rfc1337 = 1
A very good explanation of this setting is in the Frozentux Ipsysctl Tutorial. RFC 1773 says that the fixes were tested in an environment specially tailored to create the three hazards—an environment very dissimilar to native TCP behavior. Frozentux goes on to say that this setting, combined with the native Linux TCP stack behavior to drop reset (RST) segments, should cover all the hazards mentioned in the RFC paper. If it’s helpful and has no negative impact, I see no reason not to enable it. Default is 0, disabled.
Decrease keepalive probes
net.ipv4.tcp_keepalive_probes = 3
When the keepalive time is reached and your computer receives no response from the server, it sends a series of retransmissions in an attempt to recover the connection. By default, 9 probes are sent every 75 seconds and if there is still no response, the connection is closed. The probe time interval is designated by net.ipv4.tcp_keepalive_intvl.
There’s a lot more on keepalive further down but I reduced this to minimize unnecessary traffic. A small impact, yes, but if a connection was terminated for some reason, closed is closed. No need to retry it 9 times.
You will have some presets in /etc/sysctl.conf but they’re all commented out by default. What you enable here will override anything in sysctl.d and ufw's sysctl file but there are several duplicate entries between the three sources. Let's go through them so we know what's sourced where. If you've disabled ufw's sysctl file, then it becomes irrelevant and these changes below from /etc/sysctl.conf are what matters. Don't uncomment any of the forward=* lines unless you have reason to.
net.ipv4.conf.default.rp_filter = 1 | net.ipv4.conf.all.rp_filter = 1
In Ubuntu, these are controlled by /etc/sysctl.d/10-network-security.conf but appear yet again in ufw's file. You don't need to uncomment these in /etc/sysctl.conf. In Debian with no 10-* entries in sysctl.d and no ufw, reverse path filtering is set to 0 (off) by the kernel so you can uncomment them here.
By default on Debian and Ubuntu, SYN cookies are enabled by the kernel and for Ubuntu, again enabled by /etc/sysctl.d/10-network-security.conf. However, turning ufw on turns SYN cookies off with ufw's sysctl file. But you're not a server, both your computer and router will reject any SYN packets sent to you so enabling SYN cookies is pointless, even for public WiFi.
net.ipv4.conf.all.accept_redirects = 0 | net.ipv6.conf.all.accept_redirects = 0
For both Debian and Ubuntu, the kernel sets the TCP stack to accept ICMP redirects for IPv4 and IPv6. Trning ufw on disables this.
net.ipv4.conf.all.secure_redirects = 1 | net.ipv4.conf.all.send_redirects = 0
Sending redirects and accepting redirects from secure network gateways are both enabled by default in the kernel and otherwise present only in /etc/sysctl.conf. Changes to these should be made here.
net.ipv4.conf.all.accept_source_route = 0 | net.ipv6.conf.all.accept_source_route = 0
By default, the kernel will not allow the network stack to accept source route packets, with or without ufw so we're fine. Nothing to change here.
net.ipv4.conf.all.log_martians = 1
Martian packet logging is disabled by default everywhere but also present (and disabled) in ufw's sysctl file.
kernel.dmesg_restrict = 1
This last string is not network related and not already in any config file or kernel setting but it’s pertinent to sysctl hardening so we may as well add it since we’re editing things. This renders any user unable to access your dmesg logs unless they have admin privileges (CAP_SYS_ADMIN). In plain English, it means you must run dmesg commands with sudo.
There are many other writings about TCP tuning floating around the internet, some by professionals and others by various degrees of knowledgeable amateurs. I generally found that the less pro these writeups got, the more complicated they became by including unnecessary and at times, even questionable suggestions.
The main point of what’s below is to explain that it’s NOT necessary to enter these into any sysctl location because they are already the defaults on Ubuntu 12.04 and 14.04. I will keep this article updated as new long-term releases come out but many guides I came across added these switches regardless, which there is no reason for.
I’ve dubbed them Soft settings because for our home and non-server purposes, there is little to no reason to change them and some you wouldn’t want to anyway. Debian has some differences to what’s below, as will other distros. To verify what’s in your specific system, run the following command. It will create a text file on your desktop which includes the sysctl settings you’ll find below.
sysctl -a | grep -e core -e tcp > ~/Desktop/tcpsettings
Window scaling and buffer auto-tuning
net.ipv4.tcp_window_scaling = 1 | net.ipv4.tcp_moderate_rcvbuf = 1
The first string switches on the window scaling factor for both receive and send windows. Without this, your system will not support a TCP window size greater than 64 KB and you’ll get unsavory performance, even on high speed network connections.
The second string, rcvbuf, is for receive buffer auto-tuning so the system scales socket memory within what’s specified by net.ipv4.tcp_rmem, which we increased above in Hard Switches. Window size depends on the receive buffer being scalable so these two settings go hand-in-hand. You shouldn’t disable them unless you have a specific reason to do so. Defaults for both are enabled. RFC 1323
net.ipv4.tcp_sack = 1
This switches on selective acknowledgments in place of cumulative acknowledgments and it's controlled by /etc/ufw/sysctl.conf. SACK more efficiently deals with packet loss and reduces its impact on throughput by allowing a receiver to inform the sender exactly which segments were lost and must be retransmitted. Default is enabled. RFC 2018
net.ipv4.tcp_fack = 1
FACK is a way of improving congestion control during TCP’s recovery from dropped packets. It was intended as a fix for how Reno handles multiple packet loss and is meant to be used with SACK. Since this was designed to supplement Reno, I don’t know how necessary or not it would when using other congestion control algorithms. For more information, see Mathis & Mahdavi (Pittsburgh Supercomputing Center). Default is enabled.
Congestion control handling after retransmission timeouts
net.ipv4.tcp_frto = 2
F-RTO is a slow-start control algorithm for retransmission timeout recovery. Sometimes these timeouts can happen under false pretenses and "...cause unnecessary retransmissions when no segments have been lost" as said in RFC 5682.
F-RTO response controls how TCP recovers from the loss. See the Linux TCP manual for explanations of the available response options. I found that setting it to 2 is often recommended for wireless or lossy networks but if your low bandwidth wired network uses heavy QoS or other traffic shaping, it could be useful there, too. Default is 2 in Ubuntu and Debian 8, 0 (disabled) in Debian 7.
net.ipv4.tcp_keepalive_time = 7200
A keepalive packet will be sent to a server you’re connected to if that connection remains idle for this amount of time. The default is 7200 seconds so for example, say you’re signed into your webmail. Every 2 hours your computer sends a keepalive probe to make sure the connection is still open. That’s if the connection isn’t closed for some other reason like expired login duration. The server will also have a keepalive time, possibly a different duration than 2 hours.
Keepalive does use network bandwidth which, though small, could be of concern. Keepalive’s TCP bandwidth expense is described in this analysis from 2003, "...at about ten connections or less, it consumes less than five percent of the bandwidth, but at about 50 connections, it consumes over 15 percent."
If you want to reduce keepalive traffic, raise the keepalive time, lower the amount of retransmission probes and adjust retransmission interval to taste. Yet also consider this: Here is more info on TCP keepalive than you probably care to spend time on. It comes to us from the Linux Documentation Foundation and Section 3 states that even though TCP keepalive is enabled by default in the Linux kernel, it is only used when a program which is written to use keepalive needs to use it.
Nearly everything I found recommended lowering keepalive time to 1800 seconds, perhaps because this is what’s used (though commented out) in /etc/ufw/sysctl.conf. There was even a Red Hat server guide which set it to 700 seconds but I can’t find the link now. I struggle to find a compelling reason for why I would want the laptop sending keepalives every 1 hour or less instead of 2 hours, so I left this alone. Keepalive is good for servers because they don’t want to assign resources to a client which has crashed and disconnected but IMO, this is another switch not worth spending time on for 99.9% of users.
net.ipv6.conf.all.disable_ipv6 = 0 | net.ipv6.conf.default.disable_ipv6 = 0
IPv6 is still not widely used (about 1-2% of worldwide traffic) but generally more common in Europe and Asia than North America. It's is enabled by default in most distros but you'll read recommendations to disable IPv6 from a security and browsing speed standpoint unless you are actually using it. Axing IPv6 would be fine for a stationary computer behind networking equipment which doesn't support the protocol. It actually would decrease boot time a tiny bit since NetworkManager doesn't try to activate IPv6, find out it can't, then go through the timeout phases; or you could just buy a modem which does support it. Anyway, a laptop can travel anywhere so I kept IPv6 enabled.
IPv6 privacy extensions
net.ipv6.conf.default.use_tempaddr = 2 | net.ipv6.conf.all.use_tempaddr = 2
Ubuntu has IPv6 privacy extensions enabled by default so your IPv6 address is not fixed to your hardware’s MAC address (yeah...really). Debian 7 does not have privacy extensions enabled out of the box but Debian 8 does. This is controlled by /etc/sysctl.d/etc/sysctl.d/10-ipv6-privacy.conf in Ubuntu but you'll have to add these to /etc/sysctl.conf for Debian.
Other Linux distros will do differently and if you use TAILS or another high-security distro, verify for yourself. To do so, first enable the network interface (this has to be done) and use sudo sysctl -a | grep use_tempaddr. If enabled, the result will be a 2. Windows XP-8 use IPv6 privacy extensions. Apple and Android do too, though not for all OS versions so do a search to be sure. RFC 4941
Connection request backlog queue
Synchronize (SYN) packets are part of the TCP handshake which establishes a connection between you and a server or other remote host. The backlog request queue is the amount of SYN packets which still have not received an acknowledgement from the other end of the connection. Servers often increase the maximum amount of SYNs possible the backlog queue to mitigate denial of service attacks and Frozentux points out that for this switch to have any effect, net.ipv4.tcp_syncookies must be enabled..
Yet, this not a very strong DoS deterrent. Someone who can send you a deluge of 2,000 SYNs (close to 12.04's default) can just as easily do it for 4,000 or 8,000 and we’re not even considering anything over UDP or ICMP. Other precautions must accompany increasing the backlog queue and in this article from CISCO’s Internet Protocol Journal, a Verizon contractor writes how we should not put much weight on this tactic alone (see End-Host Countermeasures).
If you were a server taking in huge amounts of connection requests then you should care more about SYN flooding than most people. That’s not to say denial of service is an insignificant concern for home users but it’s much less likely. Just be careful who sees your IP address and you should also be behind a router, part of whose job is to ward off DoS.But what about denial of service attacks from within the local network? Home networks are made up of so-called 'trusted' devices so the risk should be small; a client device on the network would have to contract malware to do this. Sure, possible, but malware to DoS only the local network would almost be more of a prank than a real malicious infection, like breaking into a store to steal all their pens.
On the other hand, while public WiFi is unquestionably hostile territory, SYN flooding from within, for example, an airport’s WLAN is also not a likely encounter. Being specifically targeted within that wireless network for DoS from any point within or outside the network, even more unlikely. While it’s certainly wise to borrow from server DoS countermeasures for your local network's gateways, you could easily argue that it’s unnecessary for client devices on the network. The choice is yours, but I see no reason to change this unless it's a busy server. The default in Ubuntu 12.04 is 2048 and 14.04, 256. Debian 7 is 512 and it's 128 in Debian 8.
Max number of simultaneous TIME-WAIT sockets
net.ipv4.tcp_max_tw_buckets = 8192
TIME-WAIT is a rest state state for both server and client after FIN-WAIT to ensure delayed packets from one client’s connection won’t be accepted by a later client’s connection. Instead of SYN flooding like above, denial of service can occur here by excessive amounts of time-wait requests. Increasing this number allows more simultaneous time-wait connections (time-wait usually lasts about 2 minutes) and this is another setting used by servers to lessen the chances for DoS.
Nearly all recommendations I found were to change this to 1444000 and I don’t know where that specific number comes from. As with SYN backlog queue, raising tw_buckets will consume more system resources if those sockets are used, but if you’re not already maxing out the default, you won’t use more unless you are under attack. You computer won’t have many time-wait connections under most circumstances, even with dozens of browser tabs open. To see your open connections, their state and what program is using them, run in a terminal: sudo netstat -anpt.
If you are hitting the default limit for some reason, syslog files will tell you. I didn’t change this either because I think time-wait flooding of clients from within a even public WLAN would be extremely unlikely. On the other hand, it doesn’t seem like there are any repercussions to changing this to 1.4 million. I won't, but again, do as you will. Debian 7 sets this to 65536 by default and Debian 8 to 4096; Ubuntu 12.04 to 262144 and Ubuntu 14.04 to 8192.
Decrease the time sockets are held as FIN-WAIT
net.ipv4.tcp_fin_timeout = 60
This specifically controls fin-wait-2, meaning that a program on your computer has begun the process to close its connection to a server, but it’s still waiting for the server to acknowledge this before you enter TIME-WAIT. By reducing this number, you close connections quicker, which opens those sockets up for reuse faster, not like that’s a problem on home computers.
I’m not sure what effect potentially forcibly closing connections has on the server because if you don’t receive the server’s CLOSE-WAIT FIN segment within the fin-wait timeout window, you won’t send the server an acknowledgment, which it expects to receive before releasing the socket on its end.
But Linux servers commonly(?) use this string at 15 or 30 seconds for its applications and from what I can find, it's not an issue there. The Linux TCP manual does say the fin_timeout switch is itself a violation of the TCP specification. I’m not really sure what to do here so I left it alone. Default is 60 seconds.
Buffer size caching
net.ipv4.route.flush = 1
This is a deprecated switch and only applies to Linux kernel 2.4 and earlier. It caches a connection's maximum return window size for near-future use, but from kernel 2.6 we have no_metrics_save which is the updated implementation of route.flush.
I read this was often disabled because a segment loss on a new connection would artificially set the buffer size and you’d not be using the full capability of window scaling within your bandwidth. If you’re on a lossy network, that could be a reason you may want to disable no_metrics_save but I don’t know the differences between the two implementations. Regardless, don’t add route.flush to anything.
net.ipv4.ip_local_port_range = 32768 61000
This specifies the dynamic port range available to your computer’s applications. To see this in action, run netstat again: sudo netstat -anpt. The dynamic outbound port will be the 5 digit number after the colon for IPs under Local Address. The main reason you would want to widen this range is to accept a very large amounts of simultaneous connections to your web server or other kind of heavily used host. Otherwise, giving Firefox or Synaptic an extra 20,000 available ports accomplishes nothing.
TCP prequeue processing
net.ipv4.tcp_low_latency = 0
The Linux TCP manual says that changing this would result in lower latency at the expense of throughput. However, I found two benchmark tests which show that disabling prequeue processing gives only very small drop in latency.  
There’s two interesting things here. From the first link, both the client (you) and the server need to have this setting enabled OR disabled simultaneously or else it will increase latency. The second link shows that the difference between the two return times is initially larger, but certain kernel processes takes longer with this enabled so the end result is reduced and you get only a minuscule improvement.
I kept prequeue processing enabled (the default) because it seems unnecessary to make changes here on a desktop. The minimal gain it gives; that I would prefer throughput over a potential but tiny decrease in latency, plus any compatibility issues when connecting to Linux servers with this disabled when my computer sets it enabled; then what about increased CPU use because of the increase in kernel context switching...? KISS.
net.ipv4.ip_default_ttl = 64
I have no idea where I found this quote but it describes packet TTL very well. It "...is there to prevent packets endlessly looping when there happens to be forwarding loop. For example, imagine two routers directly attached to each other, routers A and B. For a particular destination, Router A lists router B as its next hop. For the same destination, Router B lists router A as its next hop. Packets that match this destination will the be forwarded back and forth between the two routers. As each router forward the packet, the TTL field will be reduced by 1, until the TTL field reaches the value of zero, and the packet is dropped.
The initial value of the TTL field has to be large enough that it doesn’t prevent the packet reaching its actual destination, yet small enough so that it prevents packets being caught in forwarding loops for too long. The current default initial TTL field value is 64, and doesn’t currently benefit from being set to any larger value."
I left this alone and I caution you against changing it. Gentoo’s wiki suggests changing this to a random number, stating that, "...many attackers use the TTL (time to live) as a parameter for profiling your operating system." However, changing this number will make profiling you by TTL easier than leaving it alone because your traffic won’t fit in with any default segment lifespans of any operating system. Sure, different servers often use a TTL that doesn’t match any over-the-counter OS, we could even try to spoof as Windows to blend in, but then there are so many other ways to fingerprint your computer’s network traffic that trying to safeguard against TTL profiling alone becomes completely insignificant.
System fingerprinting is not something you can wiggle out of unless you use throwaway machines or VMs—one system per use, Mission Impossible style. Even Tails and Whonix both keep TTL at the default 64 hops. Apple OS X is also set to 64 hops but Windows uses 128 and that is the only value you should consider if you do want to change this for non-technical reasons. You can find time-to-live in packet headers using tcpdump, Wireshark or similar.
Thin stream TCP traffic control
net.ipv4.tcp_thin_dupack = 0 | net.ipv4.tcp_thin_linear_timeouts = 0
The July 2012 issue of Linux Journal has a superb article which lays out what this means and why you would want to use these switches. Basically, if you experience lag with interactive TCP programs like online games or remote desktop, or VoIP or SSH applications, enabling this could improve their responsiveness. Note that the application you’re having trouble with may already be written to use thin stream control.
The thin_dupack switch turns on fast retransmission for all TCP streams which drop below 4 packets in flight between source and destination. The linear_timeouts switch concerns recovery from packet loss for thin TCP streams. Enabling this means that instead of one retransmission attempt followed by exponentially backing off the recovery time, six retransmissions are tried before exponential backoff. See page 86 of the Linux Journal article for a graphical representation of this. Default is disabled.
Recycle time-wait sockets
net.ipv4.tcp_tw_recycle = 0
This enables fast recycling of time-wait sockets. This can cause problems with network load balancing and dropped connections with network address translation (NAT), a very often enabled feature in network appliances, including consumer routers. It is a welcome security boost for home users to be behind a router with NAT as opposed to connecting directly to the modem, so don’t disable NAT just to use TCP recycling.
By default, recycling is disabled and the Linux TCP manual recommends keeping it that way, but SpeedGuide.net says it can be enabled “in many cases.” For a stationary computer using only one network and doing its own PPoE authentication, this may have some positive effect but mobile devices will use multiple networks and access points with NAT enabled so I kept time-wait recycling disabled for the laptop.
Reuse time-wait sockets
net.ipv4.tcp_tw_reuse = 0
From the Linux TCP man page, "Allow to reuse TIME_WAIT sockets for new connections when it is safe from protocol viewpoint. It should not be changed without advice/request of technical experts."
The general consensus among other guides I found was that reuse is safer than recycle because it’s based on sender/receiver protocols which must first be met. A SUSE server guide by IBM (2005) says that if you enable reuse, you should enable recycling too (p.42). Still, I’m keeping reuse disabled in hopes of avoiding uncertainties with public networks or until I read more about what these "protocols" specify.
Initial Congestion Window Size
This setting was not part of the initial testing but here's a 2010 paper by Google titled An Argument for Increasing TCP's Initial Congestion Window. The whole read is interesting but here's a quote from the conclusion:
...increasing TCP’s initial congestion window to a value commensurate with current network speeds and Web page sizes is practical, easily deployable, and immediately useful in improving Web transfer latency.
The downside is that the average TCP retransmission rate increased by 0.5% by applications in the study which don't use the system-set slow start configuration. Google recommends increasing the cwnd size to at least 10 segments from the default of 3. To do this and make it persistent across reboots and network connects/disconnects for both ethernet and WiFi, we can't use rc.local. We need an if-up script.
Create a script file /etc/network/if-up.d/initcwnd with the contents:
#!/bin/sh #On network interface up, set TCP initial #congestion window size to 10 segments. defaultroute=`ip route | grep "^default" | head -1` ip route change $defaultroute initcwnd 10
Then make it executable.
sudo chmod +x /etc/network/if-up.d/initcwnd
Disconnect and reconnect the network connection to run the script. To verify the change, run ip route. The result should be similar to this.
default via 192.168.1.1 dev eth0 initcwnd 10
Using a different DNS provider can be one more way to give your internet access new life. Since DNS lookup is the first thing your computer does in its truly unexceptional journey to your inbox, you should consider a DNS provider geographically closer to you, and/or supported by a company which would be more reliable than what you may have now. If you want malicious URL filtering for help with browser security, some DNS providers do this too. tSc has covered DNS provider choices in the past so be sure to check that out.
These can hold an extra edge as well. Firefox's about:config list allows you to finely adjust caching, prefetching and many other things. You’re in luck too, because I've also written on Firefox tweaks for performance, security and privacy. If you're looking for some switches to optimeze Chrome/Chromium, take a look here. It’s a good day to be a control freak with a computer, is it not?
- Ubuntu 12.10 TCP test results – .odf spreadsheet (2013).
- tSc’s sysctl cheat file – This is exactly what was used in the Final Results section of the spreadsheet with ufw enabled. You can cut and paste its contents into /etc/sysctl.conf.
- Arch Wiki – sysctl (2013).
- Enabling High Performance Data Transfers – System Specific Notes for System Administrators (and Privileged Users). Pittsburgh Supercomputing Center (2012).
- Energy Sciences Network – Host Tuning (2012). Also has info for Windows and OS X.
- Framework for TCP Throughput Testing. Internet Engineering Task Force – RFC 6349 (2011).
- Gentoo Wiki – TCP Tuning (2011).
- Ubuntu forums – How to Optimize your Internet Connection using MTU and RWIN (2008).
- Linux TCP Tweaking – Speedguide.net (2003).
- Ipsysctl tutorial 1.0.4 – Oscar Andreasson (2002). This was the reference point for numerous other guides I found.
- Linux TCP man page
- RFC Repository Search
- Bits/bytes conversion calculator by Matisse Enzer