forked from foswvs/foswvs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
wondershaper
executable file
·259 lines (211 loc) · 7.16 KB
/
wondershaper
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
#!/usr/bin/env bash
#set -ex;
# Wonder Shaper
#
# Set the following values to somewhat less than your actual download
# and uplink speed. In kilobits. Also set the device that is to be shaped.
#
# License GPLv2 <https://gnu.org/licenses/gpl-2.0.html>
#
# Copyright (c) 2002-2020 Bert Hubert <[email protected]>,
# Jacco Geul <[email protected]>, Simon Séhier <[email protected]>,
#
# See the ChangeLog for information on the individual contributions of the authors.
QUANTUM="6000";
VERSION="1.4.1";
CONF="/etc/systemd/wondershaper.conf";
CONFLEGACY="/etc/conf.d/wondershaper.conf";
# shellcheck disable=SC2086
eval export HIPRIODST=$HIPRIODST;
# shellcheck disable=SC2086
eval export COMMONOPTIONS=$COMMONOPTIONS;
# shellcheck disable=SC2086
eval export NOPRIOHOSTSRC=$NOPRIOHOSTSRC;
# shellcheck disable=SC2086
eval export NOPRIOHOSTDST=$NOPRIOHOSTDST;
# shellcheck disable=SC2086
eval export NOPRIOPORTSRC=$NOPRIOPORTSRC;
# shellcheck disable=SC2086
eval export NOPRIOPORTDST=$NOPRIOPORTDST;
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 "$CONF"
-c Clear the limits from adapter
-s Show the current status of adapter
-v Show the current version
Configure HIPRIODST in "$CONF" for hosts
requiring high priority i.e. in case ssh uses dport 443.
MODES:
wondershaper -a <adapter> -d <rate> -u <rate>
wondershaper -c -a <adapter>
wondershaper -s -a <adapter>
EXAMPLES:
wondershaper -a eth0 -d 1024 -u 512
wondershaper -a eth0 -u 512
wondershaper -c -a eth0
EOF
}
DSPEED="";
USPEED="";
IFACE="";
IFB="ifb0";
MODE="";
while getopts hvd:u:a:pcs o; do
case "$o" in
h) usage;
exit 1;;
v) echo "Version $VERSION";
exit 0;;
d) DSPEED="$OPTARG";;
u) USPEED="$OPTARG";;
a) IFACE="$OPTARG";;
p) MODE="presets";;
c) MODE="clear";;
s) MODE="status";;
[?]) usage;
exit 1;;
esac;
done;
if [ "$MODE" = "presets" ]; then
if [ -f "$CONF" ]; then
# shellcheck disable=SC1090
source "$CONF";
elif [ -f "$CONFLEGACY" ]; then
# shellcheck disable=SC1090
source "$CONFLEGACY";
else
echo "$CONF not found";
exit 1;
fi;
fi;
if [[ -n "$MODE" ]] && [[ -z "$IFACE" ]]; then
echo "Please supply the adapter name for the mode."
echo "";
usage;
exit 1;
fi;
if [ "$MODE" = "status" ]; then
tc -s qdisc ls dev "$IFACE";
tc -s class ls dev "$IFACE";
exit;
fi;
if [ "$MODE" = "clear" ]; then
tc qdisc del dev "$IFACE" root 2> /dev/null > /dev/null;
tc qdisc del dev "$IFACE" ingress 2> /dev/null > /dev/null;
tc qdisc del dev "$IFB" root 2> /dev/null > /dev/null;
tc qdisc del dev "$IFB" ingress 2> /dev/null > /dev/null;
exit;
fi;
if { [[ -z "$DSPEED" ]] && [[ -z "$USPEED" ]]; } || [[ -z "$IFACE" ]]; then
usage;
exit 1;
fi;
###### uplink
# install root HTB
tc qdisc add dev "$IFACE" root handle 1: htb default 20;
# shape everything at $USPEED speed - this prevents huge queues in your
# DSL modem which destroy latency:
# main class
if [[ -n "$USPEED" ]]; then
tc class add dev "$IFACE" parent 1: classid 1:1 htb \
rate "${USPEED}kbit" \
prio 5 ${COMMONOPTIONS[@]};
# high prio class 1:10:
RATE=$((20*${USPEED}/100))
if [ "$RATE" -eq 0 ]; then RATE=1 ; fi
tc class add dev "$IFACE" parent 1:1 classid 1:10 htb \
rate "${RATE}kbit" ceil $((95*${USPEED}/100))kbit \
prio 1 ${COMMONOPTIONS[@]};
# bulk and default class 1:20 - gets slightly less traffic,
# and a lower priority:
RATE=$((40*${USPEED}/100))
if [ "$RATE" -eq 0 ]; then RATE=1 ; fi
tc class add dev "$IFACE" parent 1:1 classid 1:20 htb \
rate "${RATE}kbit" ceil $((95*${USPEED}/100))kbit \
prio 2 ${COMMONOPTIONS[@]};
# 'traffic we hate'
RATE=$((20*${USPEED}/100))
if [ "$RATE" -eq 0 ]; then RATE=1 ; fi
tc class add dev "$IFACE" parent 1:1 classid 1:30 htb \
rate "${RATE}kbit" ceil $((90*${USPEED}/100))kbit \
prio 3 ${COMMONOPTIONS[@]};
# all get Stochastic Fairness:
tc qdisc add dev "$IFACE" parent 1:10 handle 10: sfq perturb 10 quantum "$QUANTUM";
tc qdisc add dev "$IFACE" parent 1:20 handle 20: sfq perturb 10 quantum "$QUANTUM";
tc qdisc add dev "$IFACE" parent 1:30 handle 30: sfq perturb 10 quantum "$QUANTUM";
# start filters
# TOS Minimum Delay (ssh, NOT scp) in 1:10:
tc filter add dev "$IFACE" parent 1: protocol ip prio 10 u32 \
match ip tos 0x10 0xff flowid 1:10;
for dst in "${HIPRIODST[@]}"; do
[ -n "$dst" ] || continue
echo "$dst";
tc filter add dev "$IFACE" parent 1: protocol ip prio 10 u32 \
match ip dst "$dst" flowid 1:10;
done;
# ICMP (ip protocol 1) in the interactive class 1:10 so we
# can do measurements & impress our friends:
tc filter add dev "$IFACE" parent 1: protocol ip prio 11 u32 \
match ip protocol 1 0xff flowid 1:10;
# prioritize small packets (<64 bytes)
tc filter add dev "$IFACE" parent 1: protocol ip prio 12 u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
flowid 1:10;
# some traffic however suffers a worse fate
for dport in "${NOPRIOPORTDST[@]}"; do
[ -n "$dport" ] || continue
tc filter add dev "$IFACE" parent 1: protocol ip prio 14 u32 \
match ip dport "$dport" 0xffff flowid 1:30;
done;
for sport in "${NOPRIOPORTSRC[@]}"; do
[ -n "$sport" ] || continue
tc filter add dev "$IFACE" parent 1: protocol ip prio 15 u32 \
match ip sport "$sport" 0xffff flowid 1:30;
done;
for src in "${NOPRIOHOSTSRC[@]}"; do
[ -n "$src" ] || continue
tc filter add dev "$IFACE" parent 1: protocol ip prio 16 u32 \
match ip src "$src" flowid 1:30;
done;
for dst in "${NOPRIOHOSTDST[@]}"; do
[ -n "$dst" ] || continue
tc filter add dev "$IFACE" parent 1: protocol ip prio 17 u32 \
match ip dst "$dst" flowid 1:30;
done;
# rest is 'non-interactive' ie 'bulk' and ends up in 1:20
tc filter add dev "$IFACE" parent 1: protocol ip prio 18 u32 \
match ip dst 0.0.0.0/0 flowid 1:20;
fi;
########## downlink #############
# slow downloads down to somewhat less than the real speed to prevent
# queuing at our ISP. Tune to see how high you can set it.
# ISPs tend to have *huge* queues to make sure big downloads are fast
#
# attach ingress policer:
if [[ -n "$DSPEED" ]]; then
# Add the IFB interface
modprobe ifb numifbs=1;
ip link set dev "$IFB" up;
# Redirect ingress (incoming) to egress ifb0
tc qdisc add dev "$IFACE" handle ffff: ingress
tc filter add dev "$IFACE" parent ffff: protocol ip u32 match u32 0 0 \
action mirred egress redirect dev "$IFB";
# Add class and rules for virtual
tc qdisc add dev "$IFB" root handle 2: htb;
tc class add dev "$IFB" parent 2: classid 2:1 htb rate "${DSPEED}kbit";
# Add filter to rule for IP address
tc filter add dev "$IFB" protocol ip parent 2: prio 1 u32 \
match ip src 0.0.0.0/0 flowid 2:1;
fi;
### EOF
### vim:tw=80:et:sts=2:st=2:sw=2:com+=b\:###:fo+=cqtrw:tags=tags: