20ec7c17d93c386d14533b99dd9e01cd9e109545
[rahunas] / tools / rahunas-bandwidth.in
1 #!/bin/sh
2 # File: bandwidth.sh
3 # Description: The bandwidth shaper wrapper script for RahuNAS
4
5 PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
6 prefix=@prefix@
7 exec_prefix=@exec_prefix@
8
9 TC=/sbin/tc
10 IP=/sbin/ip
11 IFCONFIG=/sbin/ifconfig
12
13 INIT=@sysconfdir@/default/rahunas
14 RUN=@localstatedir@/run/rahunas-bandwidth
15
16 # Interface Speed (Kbit), Default: 100 Mbps
17 INTERFACE_SPEED=102400
18
19 INTERFACE_ID=9999
20 BITTORRENT_ID=9998
21
22 MESSAGE=""
23
24 test -f $INIT || exit 0
25 . $INIT
26
27 test "$RUN_DAEMON" = "yes" || exit 0
28 test -f $RAHUNAS_CONFIG || exit 1
29
30 SHAPING_DOWN_INF=""
31 SHAPING_UP_INF=""
32
33 MSG_NOT_COMPLETED="NOT COMPLETED"
34
35 get_config_value () {
36   section=$1
37   key=$2
38   file=$3
39
40   test -n "$file" || return
41   test -e "$file" && cat "$file" | sed -e "0,/$section = {/ ! { /}/,/$section = {/ ! s/^/>>/ }" | grep "^>>" | sed -e "s/^>>//g" | grep -w "$key" | cut -d= -f2 | sed "s/^ *\(.*[^ ]\) *$/\1/" | sed 's/"//g'
42 }
43
44 BANDWIDTH_SHAPE=`get_config_value main bandwidth_shape $RAHUNAS_CONFIG`
45 BITTORRENT_DOWNLOAD_MAX=`get_config_value main bittorrent_download_max $RAHUNAS_CONFIG`
46 BITTORRENT_UPLOAD_MAX=`get_config_value main bittorrent_upload_max $RAHUNAS_CONFIG` 
47
48 test "$BANDWIDTH_SHAPE" = "yes" || exit 0 
49
50 interface_setting () {
51   case "$1" in
52     start)
53       # Interface Downlink
54       $TC qdisc add dev $SHAPING_DOWN_INF root handle 1: htb \
55         default ${INTERFACE_ID} 
56       $TC class add dev $SHAPING_DOWN_INF parent 1: classid 1:${INTERFACE_ID} \
57         htb rate ${INTERFACE_SPEED}Kbit
58
59       # Interface Uplink
60       $IFCONFIG $SHAPING_UP_INF up
61       $TC qdisc add dev $SHAPING_UP_INF root handle 2: htb \
62         default ${INTERFACE_ID} 
63       $TC class add dev $SHAPING_UP_INF parent 2: classid 2:${INTERFACE_ID} \
64         htb rate ${INTERFACE_SPEED}Kbit
65
66       # Redirect incoming traffic to IFB
67       $TC qdisc add dev $SHAPING_DOWN_INF ingress
68       $TC filter add dev $SHAPING_DOWN_INF parent ffff: protocol ip prio 2 u32 \
69         match u32 0 0 flowid 1:${INTERFACE_ID} \
70         action mirred egress redirect dev $SHAPING_UP_INF
71       ;;
72   stop)
73       # Redirect incoming traffic to IFB
74       $TC filter del dev $SHAPING_DOWN_INF parent ffff: protocol ip prio 2 u32 \
75         match u32 0 0 flowid 1:${INTERFACE_ID} \
76         action mirred egress redirect dev $SHAPING_UP_INF
77       $TC qdisc del dev $SHAPING_DOWN_INF ingress
78
79       # Interface Downlink
80       $TC qdisc del dev $SHAPING_DOWN_INF root
81
82       # Interface Uplink
83       $TC qdisc del dev $SHAPING_UP_INF root
84
85       $IFCONFIG $SHAPING_UP_INF down
86       ;;
87   esac
88 }
89
90 bittorrent_setting () {
91   case "$1" in
92     start)
93       # BITTORRENT Download throttling
94       $TC class add dev $SHAPING_DOWN_INF parent 1:${INTERFACE_ID} \
95         classid 1:${BITTORRENT_ID} htb rate ${BITTORRENT_DOWNLOAD_MAX}Kbit
96       $TC qdisc add dev $SHAPING_DOWN_INF parent 1:${BITTORRENT_ID} \
97         handle ${BITTORRENT_ID}: sfq perturb 10
98       $TC filter add dev $SHAPING_DOWN_INF parent 1: protocol ip prio 1 \
99         handle 0x3 fw classid 1:${BITTORRENT_ID}
100
101       # BITTORRENT Upload throttling
102       $TC class add dev $SHAPING_UP_INF parent 2:${INTERFACE_ID} \
103         classid 2:${BITTORRENT_ID} htb rate ${BITTORRENT_UPLOAD_MAX}Kbit
104       $TC qdisc add dev $SHAPING_UP_INF parent 2:${BITTORRENT_ID} \
105         handle ${BITTORRENT_ID}: sfq perturb 10
106       $TC filter add dev $SHAPING_UP_INF parent 2: protocol ip prio 1 \
107         handle 0x3 fw classid 2:${BITTORRENT_ID}
108       ;;
109     stop)
110       ;;
111   esac
112 }
113
114 start () {
115   if [ ! -e $RUN ]; then
116     interface_setting start
117     bittorrent_setting start
118     MESSAGE="Start OK"
119     touch $RUN
120   fi
121 }
122
123 stop () {
124   if [ -e $RUN ]; then
125     interface_setting stop
126     bittorrent_setting stop
127     MESSAGE="Stop OK"
128     rm -f $RUN
129   fi
130 }
131
132 usage_add() {
133   echo "Usage: $1 add ID IP DOWNSPEED UPSPEED DOWN_IF UP_IF"
134   echo "         ID - ID number from 1 to 9900"
135   echo "         IP - IPv4 Address"
136   echo "  DOWNSPEED - Download speed (bits/s)"
137   echo "    UPSPEED - Upload speed (bits/s)"
138   echo "    DOWN_IF - Downstream interface (eth0, eth1, vlan1, ...)"
139   echo "      UP_IF - Upstream interface (ifb0, ifb1, ...)"
140 }
141
142 usage_del() {
143   echo "Usage: $1 del ID DOWN_IF UP_IF"
144   echo "         ID - ID number from 1 to 9900"
145   echo "    DOWN_IF - Downstream interface (eth0, eth1, vlan1, ...)"
146   echo "      UP_IF - Upstream interface (ifb0, ifb1, ...)"
147 }
148
149 usage() {
150   echo "Usage: $1 {start|stop|restart|add|del}"
151   echo "       $1 add --help"
152   echo "       $1 del --help"
153 }
154
155 bw_add() {
156   ID=$1
157   IP=$2
158   DOWNSPEED=$3
159   UPSPEED=$4
160   MESSAGE="Add shaping slot id: $ID for $IP with D/U=$DOWNSPEED/$UPSPEED bits/s"
161
162   # Downlink
163   $TC class add dev $SHAPING_DOWN_INF parent 1:${INTERFACE_ID} \
164     classid 1:${ID} htb rate ${DOWNSPEED}bit ceil ${DOWNSPEED}bit
165   $TC filter add dev $SHAPING_DOWN_INF parent 1: \
166     protocol ip prio 2 u32 match ip dst ${IP}/32 flowid 1:${ID}
167
168   # Uplink
169   $TC class add dev $SHAPING_UP_INF parent 2:${INTERFACE_ID} \
170     classid 2:${ID} htb rate ${UPSPEED}bit ceil ${UPSPEED}bit
171   $TC filter add dev $SHAPING_UP_INF parent 2: \
172     protocol ip prio 2 u32 match ip src ${IP}/32 flowid 2:${ID}
173 }
174
175 bw_del() {
176   ID=$1
177   MESSAGE="Delete shaping slot id: $ID"
178
179   # Filter Removal
180   # Downlink/Uplink
181   DOWN_HANDLE=`$TC filter show dev $SHAPING_DOWN_INF | grep -w "flowid 1:${ID} " | awk '{print $10}'`
182   UP_HANDLE=`$TC filter show dev $SHAPING_UP_INF | grep -w "flowid 2:${ID} " | awk '{print $10}'`
183   $TC filter del dev $SHAPING_DOWN_INF parent 1: \
184     prio 2 handle ${DOWN_HANDLE} u32
185   $TC filter del dev $SHAPING_UP_INF parent 2: \
186     prio 2 handle ${UP_HANDLE} u32
187
188   # Class Removal
189   # Downlink/Uplink
190   $TC class del dev $SHAPING_DOWN_INF parent 1:${INTERFACE_ID} classid 1:${ID}
191   $TC class del dev $SHAPING_UP_INF parent 2:${INTERFACE_ID} classid 2:${ID}
192 }
193
194 chk_interface () {
195   SHAPING_DOWN_INF=$1
196   SHAPING_UP_INF=$2
197
198   iface_list=`$IFCONFIG -a | grep "Link encap" | awk '{print $1}'`
199
200   echo $iface_list | grep -w "$SHAPING_DOWN_INF" > /dev/null 2>&1
201   if [ $? -ne 0 ]; then
202     return 1
203   fi
204
205   echo $iface_list | grep -w "$SHAPING_UP_INF" > /dev/null 2>&1
206   if [ $? -ne 0 ]; then
207     return 1
208   fi
209
210   return 0
211 }
212
213 N=@sysconfdir@/rahunas/bandwidth.sh
214
215 case "$1" in
216   start)
217     if [ -z "$2" ] || [ -z "$3" ]; then
218       MESSAGE="$MSG_NOT_COMPLETED"  
219     else
220       chk_interface $2 $3
221       if [ $? -eq 0 ]; then
222         RUN=${RUN}-${SHAPING_DOWN_INF}-${SHAPING_UP_INF}
223         start 
224       else
225         MESSAGE="$MSG_NOT_COMPLETED"
226       fi
227     fi
228
229     test -n "$MESSAGE" || MESSAGE="$MSG_NOT_COMPLETED"
230     echo $MESSAGE
231     ;;
232   stop)
233     if [ -z "$2" ] || [ -z "$3" ]; then
234       MESSAGE="$MSG_NOT_COMPLETED"  
235     else
236       chk_interface $2 $3
237       if [ $? -eq 0 ]; then
238         RUN=${RUN}-${SHAPING_DOWN_INF}-${SHAPING_UP_INF}
239         stop 
240       else
241         MESSAGE="$MSG_NOT_COMPLETED"
242       fi
243     fi
244
245     test -n "$MESSAGE" || MESSAGE="$MSG_NOT_COMPLETED"
246     echo $MESSAGE
247
248     ;;
249   restart)
250     if [ -z "$2" ] || [ -z "$3" ]; then
251       MESSAGE="$MSG_NOT_COMPLETED"  
252     else
253       chk_interface $2 $3
254       if [ $? -eq 0 ]; then
255         RUN=${RUN}-${SHAPING_DOWN_INF}-${SHAPING_UP_INF}
256         stop 
257         start 
258       else
259         MESSAGE="$MSG_NOT_COMPLETED"
260       fi
261     fi
262
263     test -n "$MESSAGE" || MESSAGE="$MSG_NOT_COMPLETED"
264     echo $MESSAGE
265
266     ;;
267   add)
268     if [ "$2" = "--help" ]; then
269       usage_add $N
270       exit 3
271     fi
272
273     if [ $# != 7 ]; then
274       echo "Error: too few arguments"
275       usage_add $N
276       exit 1
277     fi
278
279     if [ -z "$6" ] || [ -z "$7" ]; then
280       MESSAGE="$MSG_NOT_COMPLETED"  
281     else
282       chk_interface $6 $7
283       if [ $? -eq 0 ]; then
284         RUN=${RUN}-${SHAPING_DOWN_INF}-${SHAPING_UP_INF}
285         bw_add $2 $3 $4 $5 
286       else
287         MESSAGE="$MSG_NOT_COMPLETED"
288       fi
289     fi
290     echo $MESSAGE
291     ;;
292   del)
293     if [ "$2" = "--help" ]; then
294       usage_del $N
295       exit 3
296     fi
297
298     if [ $# != 4 ]; then
299       echo "Error: too few arguments"
300       usage_del $N
301       exit 1
302     fi
303     if [ -z "$3" ] || [ -z "$4" ]; then
304       MESSAGE="$MSG_NOT_COMPLETED"  
305     else
306       chk_interface $3 $4
307       if [ $? -eq 0 ]; then
308         RUN=${RUN}-${SHAPING_DOWN_INF}-${SHAPING_UP_INF}
309         bw_del $2 
310       else
311         MESSAGE="$MSG_NOT_COMPLETED"
312       fi
313     fi
314     echo $MESSAGE
315     ;;
316   *)
317     usage $N
318     exit 3
319     ;;
320 esac 
321
322 exit 0