-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtrickleshaper
More file actions
executable file
·307 lines (256 loc) · 9.66 KB
/
trickleshaper
File metadata and controls
executable file
·307 lines (256 loc) · 9.66 KB
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#! /usr/bin/env bash
#
# This shaping script was developed to support host-fair bandwidth
# allocation in networks with very low aggregate backhaul bandwidth
# (<500k) and on hosts where fq_cake is not yet available. It is
# loosely adapted from Wondershaper's
# (https://github.com/magnific0/wondershaper) simple CLI and with much
# technical inspiration from the Bufferbloat Project's
# (https://www.bufferbloat.net/projects/) excellent work. It has not
# been optimized for high throughput networks. If you find yourself
# operating at throughputs consistently higher than 1Mbps, you should
# strongly consdier fq_codel or fq_cake, which are much more general,
# flexible, and optimized.
#
# This script as written assumes a local area /24 network, and creates
# 256 host specific queues keyed on the last octet of the IP
# address. If you're reading this and running a different size
# network, you should probably modify to meet your network specific
# conditions.
#
# This code has no warranty to the greatest extent of the law, implied
# or otherwise. Use at your own risk.
#
# Copyright 2019 Matthew Johnson <matt9j@cs.washington.edu>
# Licensed under the GPLv3 https://www.gnu.org/licenses/gpl-3.0.en.html
VERSION=1.0.0
usage()
{
cat << EOF
USAGE: $0 [-hcs] [-a <adapter>] [-d <rate>] [-u <rate>]
Limit the bandwidth of an adapter
OPTIONS:
-h Show this message
-a <adapter> Set the adapter
-d <rate> Set maximum download rate (in Kbps) and/or
-u <rate> Set maximum upload rate (in Kbps)
-p Use presets in /etc/conf.d/wondershaper.conf
-c Clear the limits from adapter
-s Show the current status of adapter
-v Show the current version
MODES:
trickleshaper -a <adapter> -d <rate> -u <rate>
trickleshaper -c -a <adapter>
trickleshaper -s -a <adapter>
EXAMPLES:
trickleshaper -a eth0 -d 1024 -u 512
trickleshaper -a eth0 -u 512
trickleshaper -c -a eth0
EOF
}
IFACE=
IFB=ifb0
while getopts hvd:u:a:csz: o
do case "$o" in
h) usage
exit 1;;
v) echo "Version $VERSION"
exit 0;;
d) DSPEED=$OPTARG;;
u) USPEED=$OPTARG;;
a) IFACE=$OPTARG;;
c) MODE="clear";;
s) MODE="status";;
z) ADMIN_IP=$OPTARG;;
[?]) usage
exit 1;;
esac
done
clearUplink()
{
echo "Clearing existing uplink"
tc qdisc del dev $IFACE root
}
clearDownlink()
{
echo "Clearing existing downlink"
tc qdisc del dev $IFB ingress
tc qdisc del dev $IFB root
tc qdisc del dev $IFACE ingress
}
if [[ ! -z $MODE ]] && [[ -z $IFACE ]]
then
echo "Please supply the adapter name for the mode."
echo ""
usage
exit 1
fi
if [ "$MODE" = "status" ]
then
echo "=================================="
echo "=============Interface============"
echo "=================================="
tc -g -s -p qdisc show dev $IFACE
tc -g -s -p class show dev $IFACE
tc -g -s -p filter show dev $IFACE
echo "=================================="
echo "==========Ingress Buffer=========="
echo "=================================="
tc -g -s -p qdisc show dev $IFB
tc -g -s -p class show dev $IFB
tc -g -s -p filter show dev $IFB
exit
fi
if [ "$MODE" = "clear" ]
then
clearUplink
clearDownlink
exit
fi
if ( [[ -z $DSPEED ]] && [[ -z $USPEED ]] ) || [[ -z $IFACE ]]
then
usage
exit 1
fi
echo "---Start Egress---"
clearUplink
echo " ---Add root qdiscs"
tc qdisc add dev $IFACE root handle 1: tbf rate ${USPEED}kbit burst 30kbit latency 10ms
# The latency parameter does not matter since we overwrite the TBF's
# internal qdisc with QFQ, but it is required. See `$man tc-tbf` for
# more information.
tc qdisc add dev $IFACE parent 1:1 handle 2: qfq
echo " ---Add app classes"
# 2:1 for EF and voice traffic
tc class add dev $IFACE parent 2: classid 2:1 qfq weight 20
# 2:2 for small packets (dangerous since not flow aware, could cause reordering)
# TODO(matt9j) Use CAKE to target small *flows*
tc class add dev $IFACE parent 2: classid 2:2 qfq weight 20
# 2:3 normal best effort traffic
tc class add dev $IFACE parent 2: classid 2:3 qfq weight 10
# Bulk
tc class add dev $IFACE parent 2: classid 2:4 qfq weight 5
for appIndex in `seq 1 4`
do
echo " ===============Class "$appIndex"==========="
echo " ---Use QFQ in each class"
qdiscHandle=2$appIndex
tc qdisc add dev $IFACE parent 2:$appIndex handle $qdiscHandle: qfq
echo " ---Add shapers per ip"
for i in `seq 1 256`
do
classid=$qdiscHandle:$(printf %x $i)
tc class add dev $IFACE parent $qdiscHandle: classid $classid qfq weight 10
tc qdisc add dev $IFACE parent $classid sfq\
perturb 30 headdrop probability 0.5 redflowlimit 20000 ecn harddrop
done
echo " ---Add ip source filter"
tc filter add dev $IFACE parent $qdiscHandle: protocol all prio 1\
handle 0xff$qdiscHandle\
flow map key nfct-src and 0xff divisor 256 baseclass $qdiscHandle:1
done
echo " ---Add app class filters"
# TODO(matt9j) Identify heavy flows and send to bottom band
# Prioritize DSCP EF
tc filter add dev $IFACE parent 2: protocol ip prio 10 u32 \
match ip dsfield 0xb8 0xfc flowid 2:1
tc filter add dev $IFACE parent 2: protocol ip prio 10 u32 \
match ip6 priority 0xb8 0xfc flowid 2:1
# Prioritize slightly larger UDP packets to support realtime audio streaming
# This catches WhatsApp and Signal voice at <256 bytes/packet
tc filter add dev $IFACE parent 2: protocol ip prio 11 u32 \
match u16 0x0000 0xff00 at 2 \
match ip protocol 0x11 0xff flowid 2:2
tc filter add dev $IFACE parent 2: protocol ip prio 11 u32 \
match u16 0x0000 0xff00 at 4 \
match ip6 protocol 0x11 0xff flowid 2:2
# Prioritize all small packets (<128 bytes payload)
tc filter add dev $IFACE parent 2: protocol ip prio 12 u32 \
match u16 0x0000 0xff80 at 2 flowid 2:2
tc filter add dev $IFACE parent 2: protocol ip prio 12 u32 \
match u16 0x0000 0xff80 at 4 flowid 2:2
# By default send all traffic to the middle band.
# Large prio ("low priority") ensures other filters take precedence
# over this default.
tc filter add dev $IFACE parent 2: prio 1000 matchall flowid 2:3
echo ""
echo "---Start Ingress--"
echo " ---Add IFB"
# Add the IFB interface
modprobe ifb numifbs=1
ip link set dev $IFB up
echo " ---Clear existing ingress"
clearDownlink
echo " ---Redirect to the ifb"
# Redirect ingress (incoming) to egress ifb0
tc qdisc add dev $IFACE handle ffff: ingress
tc filter add dev $IFACE parent ffff: matchall action mirred egress redirect dev $IFB
echo " ---Add root qdiscs"
tc qdisc add dev $IFB root handle 1: tbf rate ${DSPEED}kbit burst 30kbit latency 10ms
# The latency parameter does not matter since we overwrite the TBF's
# internal qdisc with QFQ, but it is required. See `$man tc-tbf` for
# more information.
tc qdisc add dev $IFB parent 1: handle 2: qfq
echo " ---Add app classes"
# 2:1 for EF and voice traffic
tc class add dev $IFB parent 2: classid 2:1 qfq weight 20
# 2:2 for small packets (dangerous since not flow aware, could cause reordering)
# TODO(matt9j) Use CAKE to target small *flows*
tc class add dev $IFB parent 2: classid 2:2 qfq weight 20
# 2:3 normal best effort traffic
tc class add dev $IFB parent 2: classid 2:3 qfq weight 10
# Bulk
tc class add dev $IFB parent 2: classid 2:4 qfq weight 5
if [[ ! -z $ADMIN_IP ]]
then
echo " ---Add admin shortcut"
tc class add dev $IFB parent 2: classid 2:5 qfq weight 30
tc qdisc add dev $IFB parent 2:5 sfq\
perturb 30 headdrop probability 0.5 redflowlimit 20000 ecn harddrop
# Add exception filter
tc filter add dev $IFB parent 2: protocol ip prio 1 handle 0x1337 \
u32 match ip dst $ADMIN_IP flowid 2:5
fi
for appIndex in `seq 1 4`
do
echo " ===============Class "$appIndex"==========="
echo " ---Use QFQ in each class"
qdiscHandle=2$appIndex
tc qdisc add dev $IFB parent 2:$appIndex handle $qdiscHandle: qfq
echo " ---Add shapers per ip"
for i in `seq 1 256`
do
classid=$qdiscHandle:$(printf %x $i)
tc class add dev $IFB parent $qdiscHandle: classid $classid qfq weight 10
tc qdisc add dev $IFB parent $classid sfq\
perturb 30 headdrop probability 0.5 redflowlimit 20000 ecn harddrop
done
echo " ---Add ip dest filter"
tc filter add dev $IFB parent $qdiscHandle: protocol all prio 1\
handle 0xff$qdiscHandle\
flow map key nfct-dst and 0xff divisor 256 baseclass $qdiscHandle:1
done
echo " ---Add app class filters"
# TODO(matt9j) Identify heavy flows and send to bottom band
# Prioritize DSCP EF
tc filter add dev $IFB parent 2: protocol ip prio 10 u32 \
match ip dsfield 0xb8 0xfc flowid 2:1
tc filter add dev $IFB parent 2: protocol ip prio 10 u32 \
match ip6 priority 0xb8 0xfc flowid 2:1
# Prioritize slightly larger UDP packets to support realtime audio streaming
# This catches WhatsApp and Signal voice at <256 bytes/packet
tc filter add dev $IFB parent 2: protocol ip prio 11 u32 \
match u16 0x0000 0xff00 at 2 \
match ip protocol 0x11 0xff flowid 2:2
tc filter add dev $IFB parent 2: protocol ip prio 11 u32 \
match u16 0x0000 0xff00 at 4 \
match ip6 protocol 0x11 0xff flowid 2:2
# Prioritize Small packets (<128 bytes payload)
tc filter add dev $IFB parent 2: protocol ip prio 12 u32 \
match u16 0x0000 0xff80 at 2 flowid 2:2
tc filter add dev $IFB parent 2: protocol ip prio 12 u32 \
match u16 0x0000 0xff80 at 4 flowid 2:2
# By default send all traffic to the middle band.
# Large prio ("low priority") ensures other filters take precedence
# over this default.
tc filter add dev $IFB parent 2: prio 1000 matchall flowid 2:3