← See all notes

Table of Contents

TCP optimizations

Generic sysctl TCP optimizations 🔗

Enable BBR kernel module 🔗

$ sudo modprobe tcp_bbr
$ echo "tcp_bbr" | sudo tee /etc/modules-load.d/bbr.conf

Apply changes 🔗

sudo vim /etc/sysctl.d/99-network-tuning.conf and paste these in:

# These were taken from:
# - https://github.com/zchee/docker-h2o/blob/master/sysctl.conf
# - https://hpbn.co/building-blocks-of-tcp/

# Turn on the tcp_window_scaling
net.ipv4.tcp_window_scaling = 1

# Increase the write-buffer-space allocatable
net.ipv4.tcp_wmem = 8192 65536 16777216
net.ipv4.udp_wmem_min = 16384
net.core.wmem_default = 131072
net.core.wmem_max = 16777216

# Increase the read-buffer-space allocatable
net.ipv4.tcp_rmem = 8192 65536 16777216
net.ipv4.udp_rmem_min = 16384
net.core.rmem_default = 131072
net.core.rmem_max = 16777216

# Allow the TCP fastopen flag to be used, beware some firewalls do not like TFO! (kernel > 3.7)
net.ipv4.tcp_fastopen=3

# Avoid falling back to slow start after a connection goes idle
# keeps our cwnd large with the keep alive connections (kernel > 3.6)
net.ipv4.tcp_slow_start_after_idle=0

# Connection backlog (important for servers under load)
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Ephemeral port range (if you make many outbound connections)
net.ipv4.ip_local_port_range = 1024 65535

# SYN flood protection
net.ipv4.tcp_syncookies = 1

# BBR generally outperforms CUBIC, at least on lossy or high-latency links
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# More generous file descriptors
fs.file-max=2097152
fs.nr_open=2097152

Confirm changes 🔗

$ sudo sysctl --system

Configure TCP Initial Congestion Window 🔗

Network interface can be found by running:

$ ip route | awk '/default/ {print $5}'
enp0s6

Confirm the metadata destination route is correct and exists (169.254.0.0/16 in this case):

$ ip route
default via 10.0.0.1 dev enp0s6 proto dhcp src 10.0.0.28 metric 100
10.0.0.0/24 dev enp0s6 proto kernel scope link src 10.0.0.28 metric 100
10.0.0.1 dev enp0s6 proto dhcp scope link src 10.0.0.28 metric 100
169.254.0.0/16 dev enp0s6 proto dhcp scope link src 10.0.0.28 metric 100
169.254.169.254 dev enp0s6 proto dhcp scope link src 10.0.0.28 metric 100

Apply changes 🔗

Run sudo vim /etc/systemd/network/05-enp0s6.network and add these in (base values are from /run/systemd/network/10-netplan-enp0s6.network):

[Match]
Name=enp0s6

[Link]
MTUBytes=9000

[Network]
DHCP=ipv4
LinkLocalAddressing=ipv6

[DHCP]
RouteMetric=100
UseMTU=true
UseRoutes=false
UseGateway=false

[Route]
Gateway=10.0.0.1
InitialCongestionWindow=15
InitialAdvertisedReceiveWindow=15

[Route]
Destination=169.254.0.0/16
Scope=link

Confirm changes 🔗

And then run:

$ sudo networkctl reload
# or sudo systemctl restart systemd-networkd

# Now you should see:
$ ip route show
default via 10.0.0.1 dev enp0s6 proto static onlink initcwnd 15 initrwnd 15
10.0.0.0/24 dev enp0s6 proto kernel scope link src 10.0.0.28 metric 100
169.254.0.0/16 dev enp0s6 proto static scope link
169.254.169.254 dev enp0s6 proto dhcp scope link src 10.0.0.28 metric 100