generate.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. *:direction)
  114. value="$(echo "$value" | sed -e 's,-,:,g')"
  115. if [ "$value" = "out" ]; then
  116. append "$var" "-o $device"
  117. elif [ "$value" = "in" ]; then
  118. append "$var" "-i $device"
  119. fi
  120. ;;
  121. 1:pktsize)
  122. value="$(echo "$value" | sed -e 's,-,:,g')"
  123. add_insmod ipt_length
  124. append "$var" "-m length --length $value"
  125. ;;
  126. 1:limit)
  127. add_insmod ipt_limit
  128. append "$var" "-m limit --limit $value"
  129. ;;
  130. 1:tcpflags)
  131. case "$proto" in
  132. tcp) append "$var" "-m tcp --tcp-flags ALL $value";;
  133. *) unset $var; return 0;;
  134. esac
  135. ;;
  136. 1:mark)
  137. config_get class "${value##!}" classnr
  138. [ -z "$class" ] && continue;
  139. case "$value" in
  140. !*) append "$var" "-m mark ! --mark $class";;
  141. *) append "$var" "-m mark --mark $class";;
  142. esac
  143. esac
  144. done
  145. append "$var" "$suffix"
  146. case "$ports:$proto" in
  147. 1:) parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";;
  148. esac
  149. }
  150. config_cb() {
  151. option_cb() {
  152. return 0
  153. }
  154. # Section start
  155. case "$1" in
  156. interface)
  157. config_set "$2" "classgroup" "Default"
  158. config_set "$2" "upload" "128"
  159. ;;
  160. classify|default|reclassify)
  161. option_cb() {
  162. append options "$1"
  163. }
  164. ;;
  165. esac
  166. # Section end
  167. config_get TYPE "$CONFIG_SECTION" TYPE
  168. case "$TYPE" in
  169. interface)
  170. config_get_bool enabled "$CONFIG_SECTION" enabled 1
  171. [ 1 -eq "$enabled" ] || return 0
  172. config_get classgroup "$CONFIG_SECTION" classgroup
  173. config_set "$CONFIG_SECTION" imqdev "$C"
  174. C=$(($C+1))
  175. append INTERFACES "$CONFIG_SECTION"
  176. config_set "$classgroup" enabled 1
  177. config_get device "$CONFIG_SECTION" device
  178. [ -z "$device" ] && {
  179. device="$(find_ifname ${CONFIG_SECTION})"
  180. config_set "$CONFIG_SECTION" device "${device:-eth0}"
  181. }
  182. ;;
  183. classgroup) append CG "$CONFIG_SECTION";;
  184. classify|default|reclassify)
  185. case "$TYPE" in
  186. classify) var="ctrules";;
  187. *) var="rules";;
  188. esac
  189. config_get target "$CONFIG_SECTION" target
  190. config_set "$CONFIG_SECTION" options "$options"
  191. append "$var" "$CONFIG_SECTION"
  192. unset options
  193. ;;
  194. esac
  195. }
  196. enum_classes() {
  197. local c="0"
  198. config_get classes "$1" classes
  199. config_get default "$1" default
  200. for class in $classes; do
  201. c="$(($c + 1))"
  202. config_set "${class}" classnr $c
  203. case "$class" in
  204. $default) class_default=$c;;
  205. esac
  206. done
  207. class_default="${class_default:-$c}"
  208. }
  209. cls_var() {
  210. local varname="$1"
  211. local class="$2"
  212. local name="$3"
  213. local type="$4"
  214. local default="$5"
  215. local tmp tmp1 tmp2
  216. config_get tmp1 "$class" "$name"
  217. config_get tmp2 "${class}_${type}" "$name"
  218. tmp="${tmp2:-$tmp1}"
  219. tmp="${tmp:-$tmp2}"
  220. export ${varname}="${tmp:-$default}"
  221. }
  222. tcrules() {
  223. dir=/usr/lib/qos
  224. [ -e $dir/tcrules.awk ] || dir=.
  225. echo "$cstr" | awk \
  226. -v device="$dev" \
  227. -v linespeed="$rate" \
  228. -f $dir/tcrules.awk
  229. }
  230. start_interface() {
  231. local iface="$1"
  232. local num_imq="$2"
  233. config_get device "$iface" device
  234. config_get_bool enabled "$iface" enabled 1
  235. [ -z "$device" -o 1 -ne "$enabled" ] && {
  236. echo "Interface '$iface' not found or disabled." >&2
  237. return 1
  238. }
  239. config_get upload "$iface" upload
  240. config_get halfduplex "$iface" halfduplex
  241. config_get download "$iface" download
  242. config_get classgroup "$iface" classgroup
  243. config_get_bool overhead "$iface" overhead 0
  244. download="${download:-${halfduplex:+$upload}}"
  245. enum_classes "$classgroup"
  246. for dir in up${halfduplex} ${download:+down}; do
  247. case "$dir" in
  248. up)
  249. [ "$overhead" = 1 ] && upload=$(($upload * 98 / 100 - (32 * 128 / $upload)))
  250. dev="$device"
  251. rate="$upload"
  252. dl_mode=""
  253. prefix="cls"
  254. ;;
  255. down)
  256. add_insmod imq numdevs="$num_imq"
  257. config_get imqdev "$iface" imqdev
  258. [ "$overhead" = 1 ] && download=$(($download * 98 / 100 - (80 * 1024 / $download)))
  259. dev="imq$imqdev"
  260. rate="$download"
  261. dl_mode=1
  262. prefix="d_cls"
  263. ;;
  264. *) continue;;
  265. esac
  266. cstr=
  267. for class in $classes; do
  268. cls_var pktsize "$class" packetsize $dir 1500
  269. cls_var pktdelay "$class" packetdelay $dir 0
  270. cls_var maxrate "$class" limitrate $dir 100
  271. cls_var prio "$class" priority $dir 1
  272. cls_var avgrate "$class" avgrate $dir 0
  273. config_get classnr "$class" classnr
  274. append cstr "$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate" "$N"
  275. done
  276. append ${prefix}q "$(tcrules)" "$N"
  277. export dev_${dir}="ifconfig $dev up txqueuelen 5 >&- 2>&-
  278. tc qdisc del dev $dev root >&- 2>&-
  279. tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0
  280. tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit"
  281. done
  282. add_insmod cls_fw
  283. add_insmod sch_hfsc
  284. add_insmod sch_sfq
  285. add_insmod sch_red
  286. cat <<EOF
  287. ${INSMOD:+$INSMOD$N}${dev_up:+$dev_up
  288. $clsq
  289. }${imqdev:+$dev_down
  290. $d_clsq
  291. $d_clsl
  292. $d_clsf
  293. }
  294. EOF
  295. unset INSMOD clsq clsf clsl d_clsq d_clsl d_clsf dev_up dev_down
  296. }
  297. start_interfaces() {
  298. local C="$1"
  299. for iface in $INTERFACES; do
  300. start_interface "$iface" "$C"
  301. done
  302. }
  303. add_rules() {
  304. local var="$1"
  305. local rules="$2"
  306. local prefix="$3"
  307. for rule in $rules; do
  308. unset iptrule
  309. config_get target "$rule" target
  310. config_get target "$target" classnr
  311. config_get options "$rule" options
  312. parse_matching_rule iptrule "$rule" "$options" "$prefix" "-j MARK --set-mark $target"
  313. append "$var" "$iptrule" "$N"
  314. done
  315. }
  316. start_cg() {
  317. local cg="$1"
  318. local iptrules
  319. local pktrules
  320. local sizerules
  321. local download
  322. enum_classes "$cg"
  323. add_rules iptrules "$ctrules" "iptables -t mangle -A ${cg}_ct"
  324. config_get classes "$cg" classes
  325. for class in $classes; do
  326. config_get mark "$class" classnr
  327. config_get maxsize "$class" maxsize
  328. [ -z "$maxsize" -o -z "$mark" ] || {
  329. add_insmod ipt_length
  330. append pktrules "iptables -t mangle -A ${cg} -m mark --mark $mark -m length --length $maxsize: -j MARK --set-mark 0" "$N"
  331. }
  332. done
  333. add_rules pktrules "$rules" "iptables -t mangle -A ${cg}"
  334. for iface in $INTERFACES; do
  335. config_get classgroup "$iface" classgroup
  336. config_get device "$iface" device
  337. config_get imqdev "$iface" imqdev
  338. config_get dl "$iface" download
  339. config_get halfduplex "$iface" halfduplex
  340. add_insmod ipt_IMQ
  341. append up "iptables -t mangle -A OUTPUT -o $device -j ${cg}" "$N"
  342. append up "iptables -t mangle -A FORWARD -o $device -j ${cg}" "$N"
  343. [ -z "$dl" ] || {
  344. [ -z "$halfduplex" ] || {
  345. append down "iptables -t mangle -A POSTROUTING -o $device -j IMQ --todev $imqdev" "$N"
  346. }
  347. append down "iptables -t mangle -A PREROUTING -i $device -j ${cg}" "$N"
  348. append down "iptables -t mangle -A POSTROUTING -o $device -j ${cg}" "$N"
  349. append down "iptables -t mangle -A PREROUTING -i $device -j IMQ --todev $imqdev" "$N"
  350. }
  351. done
  352. cat <<EOF
  353. $INSMOD
  354. iptables -t mangle -N ${cg} >&- 2>&-
  355. iptables -t mangle -N ${cg}_ct >&- 2>&-
  356. ${iptrules:+${iptrules}${N}iptables -t mangle -A ${cg}_ct -j CONNMARK --save-mark}
  357. iptables -t mangle -A ${cg} -j CONNMARK --restore-mark
  358. iptables -t mangle -A ${cg} -m mark --mark 0 -j ${cg}_ct
  359. $pktrules
  360. $up$N${down:+${down}$N}
  361. EOF
  362. unset INSMOD
  363. }
  364. start_firewall() {
  365. add_insmod ipt_multiport
  366. add_insmod ipt_CONNMARK
  367. cat <<EOF
  368. iptables -t mangle -F
  369. iptables -t mangle -X
  370. EOF
  371. for group in $CG; do
  372. start_cg $group
  373. done
  374. }
  375. C="0"
  376. INTERFACES=""
  377. [ -e ./qos.conf ] && {
  378. . ./qos.conf
  379. config_cb
  380. } || config_load qos
  381. C="0"
  382. for iface in $INTERFACES; do
  383. export C="$(($C + 1))"
  384. done
  385. case "$1" in
  386. all)
  387. start_interfaces "$C"
  388. start_firewall
  389. ;;
  390. interface)
  391. start_interface "$2" "$C"
  392. ;;
  393. interfaces)
  394. start_interfaces
  395. ;;
  396. firewall)
  397. start_firewall
  398. ;;
  399. esac