2 [ -e /lib
/functions.sh
] && .
/lib
/functions.sh || . .
/functions.sh
3 [ -x /sbin
/modprobe
] && {
11 eval "export isset=\${insmod_$1}"
15 [ "$2" ] && append INSMOD
"$rmmod $1 >&- 2>&-" "$N"
16 append INSMOD
"$insmod $* >&- 2>&-" "$N"; export insmod_
$1=1
21 [ -e /etc
/config
/network
] && {
22 # only try to parse network config on openwrt
24 .
/lib
/functions
/network.sh
28 if network_get_device ifname
"$1"; then
31 echo "Device for interface $1 not found." >&2
37 echo "Interface not found." >&2
42 parse_matching_rule
() {
52 append
"$var" "$prefix" "$N"
53 for option
in $options; do
55 proto
) config_get value
"$section" proto
; proto
="${proto:-$value}";;
58 config_get
type "$section" TYPE
60 classify
) unset pkt
; append
"$var" "-m mark --mark 0/0x0f";;
61 default
) pkt
=1; append
"$var" "-m mark --mark 0/0xf0";;
64 append
"$var" "${proto:+-p $proto}"
65 for option
in $options; do
66 config_get value
"$section" "$option"
68 case "$pkt:$option" in
70 append
"$var" "-s $value"
73 append
"$var" "-d $value"
75 *:ports|
*:srcports|
*:dstports
)
76 value
="$(echo "$value" | sed -e 's,-,:,g')"
79 ""|tcp|udp
) append
"$var" "-m ${proto:-tcp -p tcp} -m multiport";;
80 *) unset "$var"; return 0;;
84 config_set
"$section" srcports
""
85 config_set
"$section" dstports
""
86 config_set
"$section" portrange
""
87 append
"$var" "--ports $value"
90 config_set
"$section" ports
""
91 config_set
"$section" dstports
""
92 config_set
"$section" portrange
""
93 append
"$var" "--sports $value"
96 config_set
"$section" ports
""
97 config_set
"$section" srcports
""
98 config_set
"$section" portrange
""
99 append
"$var" "--dports $value"
105 config_set
"$section" ports
""
106 config_set
"$section" srcports
""
107 config_set
"$section" dstports
""
108 value
="$(echo "$value" | sed -e 's,-,:,g')"
110 ""|tcp|udp
) append
"$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";;
111 *) unset "$var"; return 0;;
116 value
="$(echo "$value" | sed -e 's,-,:,g')"
117 add_insmod xt_connbytes
118 append
"$var" "-m connbytes --connbytes $value --connbytes-dir both --connbytes-mode bytes"
121 add_insmod xt_comment
122 append
"$var" "-m comment --comment '$value'"
127 !*) append
"$var" "-m tos ! --tos $value";;
128 *) append
"$var" "-m tos --tos $value"
134 [ -z "${value%%[EBCA]*}" ] && dscp_option
="--dscp-class"
136 !*) append
"$var" "-m dscp ! $dscp_option $value";;
137 *) append
"$var" "-m dscp $dscp_option $value"
141 value
="$(echo "$value" | sed -e 's,-,:,g')"
142 if [ "$value" = "out" ]; then
143 append
"$var" "-o $device"
144 elif [ "$value" = "in" ]; then
145 append
"$var" "-i $device"
149 append
"$var" "-i $value"
152 value
="$(echo "$value" | sed -e 's,-,:,g')"
154 append
"$var" "-m length --length $value"
158 append
"$var" "-m limit --limit $value"
162 tcp
) append
"$var" "-m tcp --tcp-flags ALL $value";;
163 *) unset $var; return 0;;
167 config_get class
"${value##!}" classnr
168 [ -z "$class" ] && continue;
170 !*) append
"$var" "-m mark ! --mark $class/0x0f";;
171 *) append
"$var" "-m mark --mark $class/0x0f";;
176 config_get TOS
"$rule" 'TOS'
177 suffix
="-j TOS --set-tos "${TOS:-"Normal-Service"}
181 config_get DSCP
"$rule" 'DSCP'
182 [ -z "${DSCP%%[EBCA]*}" ] && set_value
="--set-dscp-class $DSCP" \
183 || set_value
="--set-dscp $DSCP"
184 suffix
="-j DSCP $set_value"
188 append
"$var" "$suffix"
189 case "$ports:$proto" in
190 1:) parse_matching_rule
"$var" "$section" "$options" "$prefix" "$suffix" "udp";;
200 config_set
"$2" "classgroup" "Default"
201 config_set
"$2" "upload" "128"
203 classify|default|reclassify
)
205 append
"CONFIG_${CONFIG_SECTION}_options" "$1"
212 config_get TYPE
"$1" TYPE
215 config_get_bool enabled
"$1" enabled
1
216 [ 1 -eq "$enabled" ] && {
217 config_get classgroup
"$1" classgroup
218 config_set
"$1" ifbdev
"$C"
220 append INTERFACES
"$1"
221 config_set
"$classgroup" enabled
1
222 config_get device
"$1" device
223 [ -z "$device" ] && {
224 device
="$(find_ifname $1)"
225 [ -z "$device" ] && exit 1
226 config_set
"$1" device
"$device"
230 classgroup
) append CG
"$1";;
231 classify|default|reclassify
)
233 classify
) var
="ctrules";;
243 config_get classes
"$1" classes
244 config_get default
"$1" default
245 for class
in $classes; do
247 config_set
"${class}" classnr
$c
249 $default) class_default
=$c;;
252 class_default
="${class_default:-$c}"
262 config_get tmp1
"$class" "$name"
263 config_get tmp2
"${class}_${type}" "$name"
266 export ${varname}="${tmp:-$default}"
271 [ -e $_dir/tcrules.
awk ] || _dir
=.
274 -v linespeed
="$rate" \
275 -v direction
="$dir" \
282 config_get device
"$iface" device
283 config_get_bool enabled
"$iface" enabled
1
284 [ -z "$device" -o 1 -ne "$enabled" ] && {
287 config_get upload
"$iface" upload
288 config_get_bool halfduplex
"$iface" halfduplex
289 config_get download
"$iface" download
290 config_get classgroup
"$iface" classgroup
291 config_get_bool overhead
"$iface" overhead
0
293 download
="${download:-${halfduplex:+$upload}}"
294 enum_classes
"$classgroup"
295 for dir
in ${halfduplex:-up} ${download:+down}; do
298 [ "$overhead" = 1 ] && upload
=$
(($upload * 98 / 100 - (15 * 128 / $upload)))
305 [ "$(ls -d /proc/sys/net/ipv4/conf/ifb* 2>&- | wc -l)" -ne "$num_ifb" ] && add_insmod ifb numifbs
="$num_ifb"
306 config_get ifbdev
"$iface" ifbdev
307 [ "$overhead" = 1 ] && download
=$
(($download * 98 / 100 - (80 * 1024 / $download)))
316 for class
in $classes; do
317 cls_var pktsize
"$class" packetsize
$dir 1500
318 cls_var pktdelay
"$class" packetdelay
$dir 0
319 cls_var maxrate
"$class" limitrate
$dir 100
320 cls_var prio
"$class" priority
$dir 1
321 cls_var avgrate
"$class" avgrate
$dir 0
322 cls_var qdisc
"$class" qdisc
$dir ""
323 cls_var filter
"$class" filter
$dir ""
324 config_get classnr
"$class" classnr
325 append cstr
"$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate:$qdisc:$filter" "$N"
327 append
${prefix}q
"$(tcrules)" "$N"
328 export dev_
${dir}="ip link add ${dev} type ifb >&- 2>&-
329 ip link set $dev up >&- 2>&-
330 tc qdisc del dev $dev root >&- 2>&-
331 tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0
332 tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit"
334 [ -n "$download" ] && {
337 add_insmod act_connmark
338 add_insmod act_mirred
339 add_insmod sch_ingress
341 if [ -n "$halfduplex" ]; then
342 export dev_up
="tc qdisc del dev $device root >&- 2>&-
343 tc qdisc add dev $device root handle 1: hfsc
344 tc filter add dev $device parent 1: prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb$ifbdev"
345 elif [ -n "$download" ]; then
346 append dev_
${dir} "tc qdisc del dev $device ingress >&- 2>&-
347 tc qdisc add dev $device ingress
348 tc filter add dev $device parent ffff: prio 1 u32 match u32 0 0 flowid 1:1 action connmark action mirred egress redirect dev ifb$ifbdev" "$N"
354 ${INSMOD:+$INSMOD$N}${dev_up:+$dev_up
362 unset INSMOD clsq clsf clsl d_clsq d_clsl d_clsf dev_up dev_down
367 for iface
in $INTERFACES; do
368 start_interface
"$iface" "$C"
377 for rule
in $rules; do
379 config_get target
"$rule" target
380 config_get target
"$target" classnr
381 config_get options
"$rule" options
383 ## If we want to override the TOS field, let's clear the DSCP field first.
384 [ ! -z "$(echo $options | grep 'TOS')" ] && {
385 s_options
=${options%%TOS}
387 parse_matching_rule iptrule
"$rule" "$s_options" "$prefix" "-j DSCP --set-dscp 0"
388 append
"$var" "$iptrule" "$N"
392 target
=$
(($target |
($target << 4)))
393 parse_matching_rule iptrule "$rule" "$options" "$prefix" "-j MARK --set-mark $target/0xff"
394 append "$var" "$iptrule" "$N"
404 for command in $iptables; do
405 add_rules iptrules "$ctrules" "$command -w -t mangle -A qos_${cg}_ct"
407 config_get classes "$cg" classes
408 for class in $classes; do
409 config_get mark "$class" classnr
410 config_get maxsize "$class" maxsize
411 [ -z "$maxsize" -o -z "$mark" ] || {
413 for command in $iptables; do
414 append pktrules "$command -w -t mangle -A qos_${cg} -m mark --mark $mark/0x0f -m length --length $maxsize: -j MARK --set-mark 0/0xff" "$N"
418 for command in $iptables; do
419 add_rules pktrules "$rules" "$command -w -t mangle -A qos_${cg}"
421 for iface in $INTERFACES; do
422 config_get classgroup "$iface" classgroup
423 config_get device "$iface" device
424 config_get ifbdev "$iface" ifbdev
425 config_get upload "$iface" upload
426 config_get download "$iface" download
427 config_get halfduplex "$iface" halfduplex
428 download="${download:-${halfduplex:+$upload}}"
429 for command in $iptables; do
430 append up "$command -w -t mangle -A OUTPUT -o $device -j qos_${cg}" "$N"
431 append up "$command -w -t mangle -A FORWARD -o $device -j qos_${cg}" "$N"
438 for command in $iptables; do
440 $command -w -t mangle -N qos_${cg}
441 $command -w -t mangle -N qos_${cg}_ct
445 ${iptrules:+${iptrules}${N}}
447 for command in $iptables; do
449 $command -w -t mangle -A qos_${cg}_ct -j CONNMARK --save-mark --mask 0xff
450 $command -w -t mangle -A qos_${cg} -j CONNMARK --restore-mark --mask 0x0f
451 $command -w -t mangle -A qos_${cg} -m mark --mark 0/0x0f -j qos_${cg}_ct
457 for command in $iptables; do
459 $command -w -t mangle -A qos_${cg} -j CONNMARK --save-mark --mask 0xff
463 $up$N${down:+${down}$N}
469 add_insmod xt_multiport
470 add_insmod xt_connmark
478 # Builds up a list of iptables commands to flush the qos_* chains,
479 # remove rules referring to them, then delete them
481 # Print rules in the mangle table, like iptables-save
482 for command in $iptables; do
483 $command -w -t mangle -S |
484 # Find rules for the qos_* chains
485 grep -E '(^-N qos_|-j qos_)' |
486 # Exclude rules in qos_* chains (inter-qos_* refs)
488 # Replace -N with -X and hold, with -F and print
490 # Print held lines at the end (note leading newline)
491 sed -e '/^-N/{s/^-N/-X/;H;s/^-X/-F/}' \
494 # Make into proper iptables calls
495 # Note: awkward in previous call due to hold space usage
496 sed -n -e "s/^./${command} -w -t mangle &/p"
502 [ -e ./qos.conf ] && {
507 config_foreach qos_parse_config
511 for iface in $INTERFACES; do
512 export C="$(($C + 1))"
515 [ -x /usr/sbin/ip6tables ] && {
516 iptables="ip6tables iptables"
523 start_interfaces "$C"
527 start_interface "$2" "$C"