1 #!/bin/sh /etc/rc.common
3 # Internal uci firewall chains are flushed and recreated on reload, so
4 # put custom rules into the root chains e.g. INPUT or FORWARD or into the
5 # special user chains, e.g. input_wan_rule or postrouting_lan_rule.
16 echo_err
"$APPNAME[$level]: $*"
19 LOGLEVEL
=${LOGLEVEL:-2}
27 APPNAME
="trafficshaper"
38 e
"exec[err=$err]: $*"
44 IP4T
="debug_exec iptables -w 5"
45 IP6T
="debug_exec ip6tables -w 5"
47 #QDISC="cake autorate_ingress internet ethernet diffserv4 triple-isolate"
50 REQ_MODULES
="sch_htb sch_cake act_connmark act_mirred em_u32"
51 REQ_CMDS
="ip tc iptables"
54 [ "$LOGLEVEL" -ge 1 ] && e
() { msg ERROR
"$@"; } || e
() { true
; }
55 [ "$LOGLEVEL" -ge 2 ] && v
() { msg INFO
"$@"; } || v
() { true
; }
56 [ "$LOGLEVEL" -ge 3 ] && d
() { msg DEBUG
"$@"; } || d
() { true
; }
57 [ "$LOGLEVEL" -ge 4 ] && set -x
62 for module
in $REQ_MODULES; do
63 [ -d /sys
/module
/$module ] || insert_modules
"$module" ||
64 die
2 "cannot load $module. Please install kmod-$module"
66 for cmd
in $REQ_CMDS; do
67 command -v $cmd &>/dev
/null ||
68 die
2 "cannot find command $cmd. Please install $cmd"
71 if ! command -v ip6tables
&>/dev
/null
; then
72 v
"Disabling IPv6 as ip6tables was not found"
76 .
/lib
/functions
/network.sh
87 v
"Stopping $APPNAME${only_int:+ for interface $only_int}"
88 if [ -z "$only_int" ]; then
91 for IPT
in "$IP4T" "$IP6T"; do
92 $IPT -t mangle
-D FORWARD
-j $IPT_CHAIN &>/dev
/null ||
:
93 $IPT -t mangle
-F $IPT_CHAIN &>/dev
/null ||
:
94 $IPT -t mangle
-X $IPT_CHAIN &>/dev
/null ||
:
95 $IPT -t mangle
-F $IPT_CHAIN-classify &>/dev
/null ||
:
96 $IPT -t mangle
-X $IPT_CHAIN-classify &>/dev
/null ||
:
101 local dev_done int dev ifb interfaces
102 if [ "$only_int" ]; then
103 config_get
type $only_int TYPE
104 if [ "$type" != "wan" ]; then
105 d
"interface $only_int not found in trafficshaper config. Ignoring"
108 interfaces
="$only_int"
111 interfaces
="$(config_foreach echo wan)"
114 for int
in $interfaces; do
115 d
"Cleaning tc for interface $int"
116 network_get_physdev dev
"$int" ||
117 die
1 "failed to get physical dev of interface $int"
119 if echo "$dev_done" |
grep -x -F -q "$dev"; then
123 if [ ${#ifb} -gt 15 ]; then
124 die
1 "ifb name too long: ${ifb}"
127 $TC qdisc del dev
${ifb} root
2> /dev
/null ||
:
128 $TC qdisc del dev
${dev} root
2> /dev
/null ||
:
129 $TC qdisc del dev
${dev} ingress
2> /dev
/null ||
:
131 d
"Removing ${ifb}..."
132 $IP link
set dev
${ifb} down
2>/dev
/null ||
:
133 $IP link delete dev
${ifb} 2>/dev
/null ||
:
135 intdev_done
="$(echo "$dev_done"; echo -n $dev)"
141 local value
=$1 reference
=$2
143 *%) echo "$((${value%\%} * reference / 100 ))";;
149 local mask
=$
(($1)) n
=0 fsb
150 if [ $mask -le 0 ]; then
151 e
"mask '$1' must be greater than 0 (have a sequence of set bit)"
154 while [ "$((mask & 0x1))" -eq 0 ]; do
159 while [ "$((mask & 0x1))" -eq 1 ]; do
163 if [ $mask -ne 0 ]; then
164 e
"mask '$1' must be a continuos sequence of set bit"
172 d
"Creating iptables mangle rules"
174 config_get mark_mask globals mark_mask
0xFF
175 mark_mask
=$
(printf '0x%X\n' $
(($mark_mask)))
177 local fsb_lst class_id_max class_id_shift
178 fsb_lst
=$
(mask_range
$mark_mask)
179 class_id_max
=$
(((1<<(${fsb_lst#* } - ${fsb_lst% *} +1))+1))
180 class_id_shift
=$
((${fsb_lst% *}))
182 d
"General iptables rules:"
183 for IPT
in "$IP4T" "$IP6T"; do
184 $IPT -t mangle
-N $IPT_CHAIN
185 $IPT -t mangle
-N $IPT_CHAIN-classify
187 $IPT -t mangle
-A FORWARD
-j $IPT_CHAIN
188 $IPT -t mangle
-A $IPT_CHAIN -j CONNMARK
--restore-mark --nfmask $mark_mask --ctmask $mark_mask \
189 -m comment
--comment "Get previous class"
190 $IPT -t mangle
-A $IPT_CHAIN -m mark
--mark 0x0/$mark_mask -j $IPT_CHAIN-classify \
191 -m comment
--comment "If no class, try to classify"
194 d
"Classes iptables rules:"
195 local class_reserved_uplink class_reserved_downlink class_nets i
=2 xi default_class_id
196 for class
in $
(config_foreach
echo class
); do
197 config_get class_reserved_uplink
$class reserved_uplink
198 config_get class_reserved_downlink
$class reserved_downlink
199 config_get class_nets
$class network
200 if [ "$class" = default
]; then
202 if [ -z "$class_reserved_uplink" -a -z "$class_reserved_downlink" ] ; then
203 die
2 "class default must defined either reserved uplink or downlink!"
205 if [ "$class_nets" ]; then
206 die
2 "class default must not have any network defined!"
209 if [ "$i" -ge "$class_id_max" ]; then
210 die
1 "Max client classes reached. Please, use less classes or increase option mark_mask '$mark_mask' in globals. Current mask allows only $((class_id_max-2)) classes if default is the last one."
214 xi
=$
(printf '0x%X\n' $
(((i-1
)<<class_id_shift)))
216 for class_net in $class_nets; do
220 *) die 2 "Unknown address family of network $class_net in class $class!"
222 if [ "$class_reserved_uplink" ]; then
223 $IPT -t mangle -A $IPT_CHAIN-classify -s $class_net -m mark --mark 0x0/$mark_mask -j MARK --set-mark ${xi}/$mark_mask \
224 -m comment --comment "$APPNAME-$class up"
226 if [ "$class_reserved_downlink" ]; then
227 $IPT -t mangle -A $IPT_CHAIN-classify -d $class_net -m mark --mark 0x0/$mark_mask -j MARK --set-mark ${xi}/$mark_mask \
228 -m comment --comment "$APPNAME-$class down"
233 if [ -z "$default_class_id" ]; then
234 die 2 "No default class defined!"
237 $IP4T -t mangle -A $IPT_CHAIN-classify -j CONNMARK --save-mark --nfmask $mark_mask --ctmask $mark_mask
238 $IP6T -t mangle -A $IPT_CHAIN-classify -j CONNMARK --save-mark --nfmask $mark_mask --ctmask $mark_mask
243 start_tc_interface() {
246 local default_class_id=$1; shift
248 config_get mark_mask globals mark_mask 0xFF
249 local fsb_lst class_id_max class_id_shift
250 fsb_lst
=$
(mask_range
$mark_mask)
251 class_id_max
=$
(((1<<(${fsb_lst#* } - ${fsb_lst% *} +1))))
252 class_id_shift
=$
((${fsb_lst% *}))
254 local downlink uplink
type
255 config_get downlink
$int downlink
256 config_get uplink
$int uplink
258 d
"Creating tc rules for $int ($dev)"
259 local dev_down dev_up
260 if [ "$downlink" ]; then
262 if [ ${#ifb} -gt 15 ]; then
263 die
1 "ifb name too long: ${ifb}"
266 d
"Creating ${ifb}..."
267 $IP link add name
${ifb} type ifb
268 $IP link
set dev
$ifb up
269 d
"Redirect ingress $dev to $ifb..."
270 $TC qdisc add dev
$dev handle ffff
: ingress
271 $TC filter add dev
$dev parent ffff
: protocol all u32 match u32
0 0 action connmark action mirred egress redirect dev
$ifb
276 if [ "$uplink" ]; then
281 if [ "$dev_down" ]; then
282 tc qdisc add dev
$dev_down root handle
1: htb default
"$default_class_id"
283 tc class add dev
$dev_down parent
1: classid
1:1 htb rate $
(calc_bw
${downlink})kbit burst
500k quantum
1500
286 if [ "$dev_up" ]; then
287 tc qdisc add dev
$dev_up root handle
1: htb default
"$default_class_id"
288 tc class add dev
$dev_up parent
1: classid
1:1 htb rate $
(calc_bw
${uplink})kbit burst
500k quantum
1500
292 "${downlink:+downlink of ${downlink}kbit}"\
293 "${uplink:+uplink of ${uplink}kbit}"\
295 local class class_reserved_downlink class_reserved_uplink class_allowed_downlink class_allowed_uplink class_nets class_net i
=2
296 for class
in $
(config_foreach
echo class
); do
297 config_get class_reserved_downlink
$class reserved_downlink
298 if [ "$class_reserved_downlink" ]; then
299 if [ "$dev_down" ]; then
300 class_reserved_downlink
=$
(calc_bw
$class_reserved_downlink $downlink)
301 config_get class_allowed_downlink
$class allowed_downlink
"$class_reserved_downlink"
302 class_allowed_downlink
=$
(calc_bw
$class_allowed_downlink $downlink)
304 e
"class $class defines reserved downlink but not wan $int. Downlink shapping will be ignored"
305 class_reserved_downlink
=
307 elif [ "$dev_down" ]; then
308 e
"class $class does not define reserved downlink but wan $int does. Downlink shapping will use default class"
311 if [ "$class_allowed_downlink" -lt "$class_reserved_downlink" ]; then
312 die
1 "Allowed downlink bandwitdh in class $class must not be smaller than reserved downlink."
315 config_get class_reserved_uplink
$class reserved_uplink
316 if [ "$class_reserved_uplink" ]; then
317 if [ "$dev_up" ]; then
318 class_reserved_uplink
=$
(calc_bw
$class_reserved_uplink $uplink)
319 config_get class_allowed_uplink
$class allowed_uplink
"$class_reserved_uplink"
320 class_allowed_uplink
=$
(calc_bw
$class_allowed_uplink $uplink)
322 e
"class $class defines reserved uplink but not wan $int. Downlink shapping will be ignored"
323 class_reserved_uplink
=
325 elif [ "$dev_up" ]; then
326 e
"class $class does not define reserved uplink but wan $int does. Downlink shapping will use default class"
329 if [ -n "$class_allowed_uplink" -a -n "$class_reserved_uplink" ] && [ "$class_allowed_uplink" -lt "$class_reserved_uplink" ]; then
330 die
1 "Allowed uplink bandwitdh in class $class must not be smaller than reserved uplink."
333 v
"$int($dev): $class(class 1:$i) will have" \
334 "${class_reserved_downlink:+download of ${class_reserved_downlink}kbit (up to ${class_allowed_downlink}kbit)}"\
335 "${class_reserved_uplink:+upload of ${class_reserved_uplink}kbit up (up to ${class_allowed_uplink}kbit)}"
337 xi
=$
(printf '0x%X\n' $
(((i-1
)<<class_id_shift)))
338 if [ "$class_reserved_uplink" ]; then
339 $TC class add dev $dev_up parent 1:1 classid 1:$i htb rate ${class_reserved_uplink}kbit ceil ${class_allowed_uplink}kbit quantum 1500 burst 50k
340 $TC qdisc add dev $dev_up parent 1:$i handle $i: $QDISC
341 if [ "$class" != default ]; then
342 $TC filter add dev $dev_up parent 1: protocol ip prio $i handle ${xi}/$mark_mask fw flowid 1:$i
345 if [ "$class_reserved_downlink" ]; then
346 $TC class add dev $dev_down parent 1:1 classid 1:$i htb rate ${class_reserved_downlink}kbit ceil ${class_allowed_downlink}kbit quantum 1500 burst 50k
347 $TC qdisc add dev $dev_down parent 1:$i handle $i: $QDISC
348 if [ "$class" != default ]; then
349 $TC filter add dev $dev_down parent 1: protocol ip prio $i handle ${xi}/$mark_mask fw flowid 1:$i
357 d "Creating tc rules"
358 local dev_done int dev interfaces
359 local default_class_id=$1; shift
362 if [ "$only_int" ]; then
363 config_get type $only_int TYPE
364 if [ "$type" != "wan" ]; then
365 d "interface $only_int not found in trafficshaper config. Ignoring"
368 interfaces="$only_int"
371 interfaces="$(config_foreach echo wan)"
374 for int in $interfaces; do
375 network_get_physdev dev "$int" ||
376 die 1 "failed to get physical dev of interface $int"
378 if echo "$dev_done" | grep -x -F -q "$dev"; then
379 e "$int uses $dev which was already configured. Only list each WAN once. Skipping..."
383 start_tc_interface $int $dev $ifb "$default_class_id"
384 intdev_done="$(echo "$dev_done"; echo -n $dev)"
389 local only_int=$1 type
392 (LOGLEVEL=0 do_stop "$only_int")
395 trap "set +e; do_stop $only_int" EXIT
397 v "Starting $APPNAME${only_int:+ for interface $only_int}"
399 local default_class_id
400 if ! default_class_id=$(i=2 config_foreach 'eval echo $((i++))' class '| grep " default"'); then
401 die 2 "No default class defined!"
403 default_class_id=${default_class_id% *}
405 [ "$only_int" ] || start_iptables
406 start_tc "$default_class_id" "$only_int"
424 $IP4T -t mangle -L $IPT_CHAIN &>/dev/null
429 if ! is_running; then
430 d "Not running. Nothing to reload"
433 logger -t "$APPNAME" "Reloading $*..."
437 add_interface_trigger() {
438 procd_add_interface_trigger "interface.update" "$1" /etc/init.d/$APPNAME reload $1
445 procd_add_reload_trigger "$APPNAME"
446 config_foreach add_interface_trigger wan
449 validate_trafficshaper_global
450 validate_trafficshaper_wan
451 validate_trafficshaper_class
455 validate_trafficshaper_global() {
456 uci_validate_section $APPNAME global "${1}" \
457 'mark_mask:uinteger:0xFF'
460 validate_trafficshaper_wan() {
461 uci_validate_section "$APPNAME" wan "${1}" \
462 'downlink:uinteger' \
466 validate_trafficshaper_class() {
467 uci_validate_section "$APPNAME" class "${1}" \
469 'reserved_downlink:or(uinteger, string)' \
470 'reserved_uplink:or(uinteger, string)' \
471 'allowed_downlink:or(uinteger, string)' \
472 'allowed_uplink:or(uinteger, string)'