2
0

generate.sh 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. #!/bin/sh
  2. [ -e /etc/functions.sh ] && . /etc/functions.sh || . ./functions.sh
  3. [ -x /sbin/modprobe ] && insmod="modprobe" || insmod="insmod"
  4. add_insmod() {
  5. eval "export isset=\${insmod_$1}"
  6. case "$isset" in
  7. 1) ;;
  8. *) append INSMOD "$insmod $* >&- 2>&-" "$N"; export insmod_$1=1;;
  9. esac
  10. }
  11. [ -e /etc/config/network ] && {
  12. # only try to parse network config on openwrt
  13. find_ifname() {(
  14. reset_cb
  15. include /lib/network
  16. scan_interfaces
  17. config_get "$1" ifname
  18. )}
  19. } || {
  20. find_ifname() {
  21. echo "Interface not found."
  22. exit 1
  23. }
  24. }
  25. parse_matching_rule() {
  26. local var="$1"
  27. local section="$2"
  28. local options="$3"
  29. local prefix="$4"
  30. local suffix="$5"
  31. local proto="$6"
  32. local mport=""
  33. local ports=""
  34. append "$var" "$prefix" "$N"
  35. for option in $options; do
  36. case "$option" in
  37. proto) config_get value "$section" proto; proto="${proto:-$value}";;
  38. esac
  39. done
  40. config_get type "$section" TYPE
  41. case "$type" in
  42. classify) unset pkt; append "$var" "-m mark --mark 0";;
  43. default) pkt=1; append "$var" "-m mark --mark 0";;
  44. reclassify) pkt=1;;
  45. esac
  46. append "$var" "${proto:+-p $proto}"
  47. for option in $options; do
  48. config_get value "$section" "$option"
  49. case "$pkt:$option" in
  50. *:srchost)
  51. append "$var" "-s $value"
  52. ;;
  53. *:dsthost)
  54. append "$var" "-d $value"
  55. ;;
  56. *:ipp2p)
  57. add_insmod ipt_ipp2p
  58. append "$var" "-m ipp2p"
  59. case "$value" in
  60. all) append "$var" "--edk --dc --kazaa --gnu --bit";;
  61. *) append "$var" "--$value";;
  62. esac
  63. ;;
  64. *:layer7)
  65. add_insmod ipt_layer7
  66. append "$var" "-m layer7 --l7proto $value${pkt:+ --l7pkt}"
  67. ;;
  68. *:ports|*:srcports|*:dstports)
  69. value="$(echo "$value" | sed -e 's,-,:,g')"
  70. lproto=${lproto:-tcp}
  71. case "$proto" in
  72. ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} -m multiport";;
  73. *) unset "$var"; return 0;;
  74. esac
  75. case "$option" in
  76. ports)
  77. config_set "$section" srcports ""
  78. config_set "$section" dstports ""
  79. config_set "$section" portrange ""
  80. append "$var" "--ports $value"
  81. ;;
  82. srcports)
  83. config_set "$section" ports ""
  84. config_set "$section" dstports ""
  85. config_set "$section" portrange ""
  86. append "$var" "--sports $value"
  87. ;;
  88. dstports)
  89. config_set "$section" ports ""
  90. config_set "$section" srcports ""
  91. config_set "$section" portrange ""
  92. append "$var" "--dports $value"
  93. ;;
  94. esac
  95. ports=1
  96. ;;
  97. *:portrange)
  98. config_set "$section" ports ""
  99. config_set "$section" srcports ""
  100. config_set "$section" dstports ""
  101. value="$(echo "$value" | sed -e 's,-,:,g')"
  102. case "$proto" in
  103. ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";;
  104. *) unset "$var"; return 0;;
  105. esac
  106. ports=1
  107. ;;
  108. *:connbytes)
  109. value="$(echo "$value" | sed -e 's,-,:,g')"
  110. add_insmod ipt_connbytes
  111. append "$var" "-m connbytes --connbytes $value --connbytes-dir both --connbytes-mode bytes"
  112. ;;
  113. 1:pktsize)
  114. value="$(echo "$value" | sed -e 's,-,:,g')"
  115. add_insmod ipt_length
  116. append "$var" "-m length --length $value"
  117. ;;
  118. 1:limit)
  119. add_insmod ipt_limit
  120. append "$var" "-m limit --limit $value"
  121. ;;
  122. 1:tcpflags)
  123. case "$proto" in
  124. tcp) append "$var" "-m tcp --tcp-flags ALL $value";;
  125. *) unset $var; return 0;;
  126. esac
  127. ;;
  128. 1:mark)
  129. config_get class "${value##!}" classnr
  130. [ -z "$class" ] && continue;
  131. case "$value" in
  132. !*) append "$var" "-m mark ! --mark $class";;
  133. *) append "$var" "-m mark --mark $class";;
  134. esac
  135. esac
  136. done
  137. append "$var" "$suffix"
  138. case "$ports:$proto" in
  139. 1:) parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";;
  140. esac
  141. }
  142. config_cb() {
  143. option_cb() {
  144. return 0
  145. }
  146. # Section start
  147. case "$1" in
  148. interface)
  149. config_set "$2" "classgroup" "Default"
  150. config_set "$2" "upload" "128"
  151. ;;
  152. classify|default|reclassify)
  153. option_cb() {
  154. append options "$1"
  155. }
  156. ;;
  157. esac
  158. # Section end
  159. config_get TYPE "$CONFIG_SECTION" TYPE
  160. case "$TYPE" in
  161. interface)
  162. config_get_bool enabled "$CONFIG_SECTION" enabled 1
  163. [ 1 -eq "$enabled" ] || return 0
  164. config_get classgroup "$CONFIG_SECTION" classgroup
  165. config_set "$CONFIG_SECTION" imqdev "$C"
  166. C=$(($C+1))
  167. append INTERFACES "$CONFIG_SECTION"
  168. config_set "$classgroup" enabled 1
  169. config_get device "$CONFIG_SECTION" device
  170. [ -z "$device" ] && {
  171. device="$(find_ifname ${CONFIG_SECTION})"
  172. config_set "$CONFIG_SECTION" device "${device:-eth0}"
  173. }
  174. ;;
  175. classgroup) append CG "$CONFIG_SECTION";;
  176. classify|default|reclassify)
  177. case "$TYPE" in
  178. classify) var="ctrules";;
  179. *) var="rules";;
  180. esac
  181. config_get target "$CONFIG_SECTION" target
  182. config_set "$CONFIG_SECTION" options "$options"
  183. append "$var" "$CONFIG_SECTION"
  184. unset options
  185. ;;
  186. esac
  187. }
  188. enum_classes() {
  189. local c="0"
  190. config_get classes "$1" classes
  191. config_get default "$1" default
  192. for class in $classes; do
  193. c="$(($c + 1))"
  194. config_set "${class}" classnr $c
  195. case "$class" in
  196. $default) class_default=$c;;
  197. esac
  198. done
  199. class_default="${class_default:-$c}"
  200. }
  201. cls_var() {
  202. local varname="$1"
  203. local class="$2"
  204. local name="$3"
  205. local type="$4"
  206. local default="$5"
  207. local tmp tmp1 tmp2
  208. config_get tmp1 "$class" "$name"
  209. config_get tmp2 "${class}_${type}" "$name"
  210. tmp="${tmp2:-$tmp1}"
  211. tmp="${tmp:-$tmp2}"
  212. export ${varname}="${tmp:-$default}"
  213. }
  214. tcrules() {
  215. dir=/usr/lib/qos
  216. [ -e $dir/tcrules.awk ] || dir=.
  217. echo "$cstr" | awk \
  218. -v device="$dev" \
  219. -v linespeed="$rate" \
  220. -f $dir/tcrules.awk
  221. }
  222. start_interface() {
  223. local iface="$1"
  224. local num_imq="$2"
  225. config_get device "$iface" device
  226. config_get_bool enabled "$iface" enabled 1
  227. [ -z "$device" -o 1 -ne "$enabled" ] && {
  228. echo "Interface '$iface' not found or disabled." >&2
  229. return 1
  230. }
  231. config_get upload "$iface" upload
  232. config_get halfduplex "$iface" halfduplex
  233. config_get download "$iface" download
  234. config_get classgroup "$iface" classgroup
  235. config_get_bool overhead "$iface" overhead 0
  236. download="${download:-${halfduplex:+$upload}}"
  237. enum_classes "$classgroup"
  238. for dir in up${halfduplex} ${download:+down}; do
  239. case "$dir" in
  240. up)
  241. [ "$overhead" = 1 ] && upload=$(($upload * 98 / 100 - (32 * 128 / $upload)))
  242. dev="$device"
  243. rate="$upload"
  244. dl_mode=""
  245. prefix="cls"
  246. ;;
  247. down)
  248. add_insmod imq numdevs="$num_imq"
  249. config_get imqdev "$iface" imqdev
  250. [ "$overhead" = 1 ] && download=$(($download * 98 / 100 - (80 * 1024 / $download)))
  251. dev="imq$imqdev"
  252. rate="$download"
  253. dl_mode=1
  254. prefix="d_cls"
  255. ;;
  256. *) continue;;
  257. esac
  258. cstr=
  259. for class in $classes; do
  260. cls_var pktsize "$class" packetsize $dir 1500
  261. cls_var pktdelay "$class" packetdelay $dir 0
  262. cls_var maxrate "$class" limitrate $dir 100
  263. cls_var prio "$class" priority $dir 1
  264. cls_var avgrate "$class" avgrate $dir 0
  265. config_get classnr "$class" classnr
  266. append cstr "$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate" "$N"
  267. done
  268. append ${prefix}q "$(tcrules)" "$N"
  269. export dev_${dir}="ifconfig $dev up txqueuelen 5 >&- 2>&-
  270. tc qdisc del dev $dev root >&- 2>&-
  271. tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0
  272. tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit"
  273. done
  274. add_insmod cls_fw
  275. add_insmod sch_hfsc
  276. add_insmod sch_sfq
  277. add_insmod sch_red
  278. cat <<EOF
  279. ${INSMOD:+$INSMOD$N}${dev_up:+$dev_up
  280. $clsq
  281. }${imqdev:+$dev_down
  282. $d_clsq
  283. $d_clsl
  284. $d_clsf
  285. }
  286. EOF
  287. unset INSMOD clsq clsf clsl d_clsq d_clsl d_clsf dev_up dev_down
  288. }
  289. start_interfaces() {
  290. local C="$1"
  291. for iface in $INTERFACES; do
  292. start_interface "$iface" "$C"
  293. done
  294. }
  295. add_rules() {
  296. local var="$1"
  297. local rules="$2"
  298. local prefix="$3"
  299. for rule in $rules; do
  300. unset iptrule
  301. config_get target "$rule" target
  302. config_get target "$target" classnr
  303. config_get options "$rule" options
  304. parse_matching_rule iptrule "$rule" "$options" "$prefix" "-j MARK --set-mark $target"
  305. append "$var" "$iptrule" "$N"
  306. done
  307. }
  308. start_cg() {
  309. local cg="$1"
  310. local iptrules
  311. local pktrules
  312. local sizerules
  313. local download
  314. enum_classes "$cg"
  315. add_rules iptrules "$ctrules" "iptables -t mangle -A ${cg}_ct"
  316. config_get classes "$cg" classes
  317. for class in $classes; do
  318. config_get mark "$class" classnr
  319. config_get maxsize "$class" maxsize
  320. [ -z "$maxsize" -o -z "$mark" ] || {
  321. add_insmod ipt_length
  322. append pktrules "iptables -t mangle -A ${cg} -m mark --mark $mark -m length --length $maxsize: -j MARK --set-mark 0" "$N"
  323. }
  324. done
  325. add_rules pktrules "$rules" "iptables -t mangle -A ${cg}"
  326. for iface in $INTERFACES; do
  327. config_get classgroup "$iface" classgroup
  328. config_get device "$iface" device
  329. config_get imqdev "$iface" imqdev
  330. config_get dl "$iface" download
  331. config_get halfduplex "$iface" halfduplex
  332. add_insmod ipt_IMQ
  333. append up "iptables -t mangle -A OUTPUT -o $device -j ${cg}" "$N"
  334. append up "iptables -t mangle -A FORWARD -o $device -j ${cg}" "$N"
  335. [ -z "$dl" ] || {
  336. [ -z "$halfduplex" ] || {
  337. append down "iptables -t mangle -A POSTROUTING -o $device -j IMQ --todev $imqdev" "$N"
  338. }
  339. append down "iptables -t mangle -A PREROUTING -i $device -j ${cg}" "$N"
  340. append down "iptables -t mangle -A PREROUTING -i $device -j IMQ --todev $imqdev" "$N"
  341. }
  342. done
  343. cat <<EOF
  344. $INSMOD
  345. iptables -t mangle -N ${cg} >&- 2>&-
  346. iptables -t mangle -N ${cg}_ct >&- 2>&-
  347. ${iptrules:+${iptrules}${N}iptables -t mangle -A ${cg}_ct -j CONNMARK --save-mark}
  348. iptables -t mangle -A ${cg} -j CONNMARK --restore-mark
  349. iptables -t mangle -A ${cg} -m mark --mark 0 -j ${cg}_ct
  350. $pktrules
  351. $up$N${down:+${down}$N}
  352. EOF
  353. unset INSMOD
  354. }
  355. start_firewall() {
  356. add_insmod ipt_multiport
  357. add_insmod ipt_CONNMARK
  358. cat <<EOF
  359. iptables -t mangle -F
  360. iptables -t mangle -X
  361. EOF
  362. for group in $CG; do
  363. start_cg $group
  364. done
  365. }
  366. C="0"
  367. INTERFACES=""
  368. [ -e ./qos.conf ] && {
  369. . ./qos.conf
  370. config_cb
  371. } || config_load qos
  372. C="0"
  373. for iface in $INTERFACES; do
  374. export C="$(($C + 1))"
  375. done
  376. case "$1" in
  377. all)
  378. start_interfaces "$C"
  379. start_firewall
  380. ;;
  381. interface)
  382. start_interface "$2" "$C"
  383. ;;
  384. interfaces)
  385. start_interfaces
  386. ;;
  387. firewall)
  388. start_firewall
  389. ;;
  390. esac