summaryrefslogtreecommitdiffstats
path: root/debloat.sh
blob: ee2768da22303471579b65e26248a48721146c17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/bin/bash
# debloat.sh -	improves network latency by reducing excessive buffering
#		and offloads on common devices and enabling fq_codel.
# Copyright 2012 M D Taht. Released into the public domain.

# This script is presently targetted to go into
# /etc/network/ifup.d on debian derived systems
# /sbin/ifup-local on rhel / centos / fedora derived systems
#
# References: http://www.bufferbloat.net/projects/codel/wiki/Best_practices_for_benchmarking_Codel_and_FQ_Codel

IFACE=$1
[[ "$IFACE" == "lo" ]] && exit 0

LL=1 # go for lowest latency
ECN=1 # enable ECN
BQLLIMIT100=3000 # at speeds below 100Mbit, 2 big packets is enough
BQLLIMIT10=1514 # at speeds below 10Mbit, 1 big packet is enough.
		# Actually it would be nice to go to just one packet
QDISC=fq_codel # There are multiple variants of fq_codel in testing
FQ_LIMIT="" # the default 10000 packet limit mucks with slow start at speeds
            # at 1Gbit and below. Somewhat arbitrary figures selected.

[ -z "$IFACE" ] && echo error: $0 expects IFACE parameter in environment && exit 1
ethtool=/sbin/ethtool
[ -z $ethtool ] && echo error: ethtool is required && exit 1
tc=/sbin/tc
[ -z $tc ] && echo error: tc is required && exit 1
# FIXME see if $QDISC is available. modprobe?

# BUGS - need to detect bridges.
#      - Need filter to distribute across mq ethernet devices
#      - needs an "undebloat" script for ifdown to restore BQL autotuning

S=/sys/class/net
FQ_OPTS=""
#FQ_OPTS="FLOWS 2048 TARGET 5ms"

[ $LL -eq 1 ] && FQ_OPTS="$FQ_OPTS quantum 500"
[ $ECN -eq 1 ] && FQ_OPTS="$FQ_OPTS ecn"

FLOW_KEYS="src,dst,proto,proto-src,proto-dst"
# For 5-tuple (flow) fairness when the same device is performing NAT
#FLOW_KEYS="nfct-src,nfct-dst,nfct-proto,nfct-proto-src,nfct-proto-dst"


# Offloads are evil in the quest for low latency
# And ethtool will abort if you attempt to turn off a
# nonexistent offload.

et() {
(
	$ethtool -K $IFACE tso off
	$ethtool -K $IFACE gso off
	$ethtool -K $IFACE ufo off
# Presently unknown if gro/lro affect latency much
	$ethtool -K $IFACE gro off
	$ethtool -K $IFACE lro off
) 2> /dev/null
}

# Wifi is special in that how the queues work is pre-defined
# to be voice, video, best effort and background

wifi() {
	$tc qdisc add dev $IFACE handle 1 root mq
	$tc qdisc add dev $IFACE parent 1:1 $QDISC $FQ_OPTS noecn
	$tc qdisc add dev $IFACE parent 1:2 $QDISC $FQ_OPTS
	$tc qdisc add dev $IFACE parent 1:3 $QDISC $FQ_OPTS
	$tc qdisc add dev $IFACE parent 1:4 $QDISC $FQ_OPTS noecn
}

# Hardware mq ethernet devs are special and need some sort of filter
# attached to actually use in most cases. FIXME. (see tg3)

mq() {
	local I=1
	$tc qdisc add dev $IFACE handle 1 root mq

	for i in $S/$IFACE/queues/tx-*
	do
		$tc qdisc add dev $IFACE parent 1:$(printf "%x" $I) $QDISC $FQ_OPTS
		I=`expr $I + 1`
	done
	I=`expr $I - 1`
	$tc filter add dev $IFACE prio 1 protocol ip parent 1: handle 100 \
		flow hash keys ${FLOW_KEYS} divisor $I baseclass 1:1
}

fq_codel() {
	$tc qdisc add dev $IFACE root $QDISC $FQ_OPTS $FQ_LIMIT
}

fix_speed() {
local SPEED=`cat $S/$IFACE/speed` 2> /dev/null
if [ -n "$SPEED" ]
then
	[ "$SPEED" = 4294967295 ] && echo "no ethernet speed selected. debloat estimate will be WRONG"
	[ "$SPEED" -lt 1001 ] && FQ_LIMIT="limit 1200"
	if [ "$SPEED" -lt 101 ]
	then
	[ $LL -eq 1 ] && et # for lowest latency disable offloads
	BQLLIMIT=$BQLLIMIT100
	FQ_LIMIT="limit 800"
	[ "$SPEED" -lt 11 ] && BQLLIMIT=$BQLLIMIT10 && FQ_LIMIT="limit 400"
	for I in /sys/class/net/$IFACE/queues/tx-*/byte_queue_limits/limit_max
		do
			echo $BQLLIMIT > $I
		done
	fi
fi
}

fix_queues() {
local QUEUES=`ls -d $S/$IFACE/queues/tx-* | wc -l | awk '{print $1}'`
if [ $QUEUES -gt 1 ]
then
	if [ -x $S/$IFACE/phy80211 ]
	then
		wifi
	else
		mq
	fi
else
	fq_codel
fi
}


$tc qdisc del dev $IFACE root 2> /dev/null
fix_speed
fix_queues
/sbin/ip link set $IFACE txqueuelen 100

exit 0