Shaping-Script: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Florz (Diskussion | Beiträge) Abgleich mit meiner aktuellen Version |
||
Zeile 5: | Zeile 5: | ||
Die Uhrzeit sollte möglichst automatisch aktualisiert werden. Vorsicht derzeit gibt es einen [http://www.mail-archive.com/uclibc@uclibc.org/msg07261.html Bug] in der uclibc, der dazu führt, dass in Schaltjahren die Sommerzeit zu spät beginnt wird. | Die Uhrzeit sollte möglichst automatisch aktualisiert werden. Vorsicht derzeit gibt es einen [http://www.mail-archive.com/uclibc@uclibc.org/msg07261.html Bug] in der uclibc, der dazu führt, dass in Schaltjahren die Sommerzeit zu spät beginnt wird. | ||
<pre> | <pre> | ||
#! /bin/sh | #! /bin/sh | ||
Zeile 38: | Zeile 27: | ||
DEV_DEPEND=$8 # never go faster than this interface (optional) | DEV_DEPEND=$8 # never go faster than this interface (optional) | ||
DEV_DEPEND_MAX=$9 # use only % of the available speed (optional) | DEV_DEPEND_MAX=$9 # use only % of the available speed (optional) | ||
DEV_SHAPE_UCI=$(uci show network | grep ifname=$( echo $DEV_SHAPE | sed -e "s/br-//") | cut -d. -f2) | |||
# calculate minimum speed | # calculate minimum speed | ||
Zeile 82: | Zeile 71: | ||
EXCLUDE=0 | EXCLUDE=0 | ||
echo "Can't exclude any traffic from shaping. The router needs to be running since before 00:00:00. Do \"touch /tmp/force_tc_cron_exclude\" to force exclusion." | echo "Can't exclude any traffic from shaping. The router needs to be running since before 00:00:00. Do \"touch /tmp/force_tc_cron_exclude\" to force exclusion." | ||
fi | |||
else | |||
if [ $(( $(date +%s)-$(date -d "$(date +%F) 00:00:00" +%s)-$(cat /proc/uptime | cut -d. -f1) )) -lt 0 ]; then | |||
rm /tmp/force_tc_cron_exclude | |||
fi | fi | ||
fi | fi | ||
Zeile 111: | Zeile 104: | ||
#disable interface if over limit | #disable interface if over limit | ||
if [ $COUNTER_NOW -ge $MAX_DAILY ]; then | if [ $COUNTER_NOW -ge $MAX_DAILY ]; then | ||
ifdown $DEV_SHAPE_UCI | |||
touch /tmp/${DEV_SHAPE_UCI}_is_down | |||
else | else | ||
if [ -e /tmp/${DEV_SHAPE_UCI}_is_down ]; then | |||
ifup $DEV_SHAPE_UCI && rm /tmp/${DEV_SHAPE_UCI}_is_down | |||
fi | |||
fi | fi | ||
Version vom 2. Dezember 2013, 12:14 Uhr
Natürlich sind wir für Netzneutralität. Nichts desto trotz können es die äußerlichen Umstände erforderlich machen, einen Internetanschluss drosseln zu wollen. Das Script auf dieser Seite entstand, da die Netzanschlüsse des Chemnitzer Studentennetzes (CSN) tagsüber festen Beschränkungen unterliegen. Bei zweifacher Überschreitung des Tageslimits erfolgt die sofortige Sperrung des Anschlusses. Diese Regel wurde in der Vergangenheit hart umgesetzt. Dies macht beispielsweise den Betrieb eines Freifunkknotens zu einem riskanten Unterfangen.
Das Script erlaubt es daher eine feste tägliche Quota vorzugeben. Die Angabe des nicht beachteten Zeitraumes ist möglich (im CSN von 0-8 Uhr (00:00-07:59)). Der Aufruf erfolgt minütlich per cron. Getestet wurde Das Script unter OpenWRT Backfire (10.03.1, r29592) mit installiertem vnstat (muss als dienst laufen -> /etc/init.d/vnstat enable), kmod-sched und tc. Das logging durch vnstat erfolgt auf einen angesteckten USB-Stick (um den internen Flasch zu schonen).
Die Uhrzeit sollte möglichst automatisch aktualisiert werden. Vorsicht derzeit gibt es einen Bug in der uclibc, der dazu führt, dass in Schaltjahren die Sommerzeit zu spät beginnt wird.
#! /bin/sh PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin for i in $(ls /lib/modules/$(uname -r)/ | grep sch_ | cut -d"." -f1); do insmod $i >> /dev/null 2>&1 done insmod sch_ingress >> /dev/null 2>&1 insmod sch_sfq >> /dev/null 2>&1 insmod sch_htb >> /dev/null 2>&1 insmod cls_u32 >> /dev/null 2>&1 insmod act_police >> /dev/null 2>&1 MAX_DAILY=$3 #MB PCT_INITIAL=$5 #% offset at 00:00:00 SPEEDMAX=$4 #kbit DEV_MEASURE="$1" DEV_SHAPE="$2" TIME_EXCLUDE_START=$6 # first hour to exclude from todays calculation TIME_EXCLUDE_END=$7 # last hour to exclude from todays calculation # Example: 0 8 means 00:00-07:59 DEV_DEPEND=$8 # never go faster than this interface (optional) DEV_DEPEND_MAX=$9 # use only % of the available speed (optional) DEV_SHAPE_UCI=$(uci show network | grep ifname=$( echo $DEV_SHAPE | sed -e "s/br-//") | cut -d. -f2) # calculate minimum speed SPEEDMIN=$(( (($MAX_DAILY*8*1024*1024)/(60*60*24))/(2*2*1000) )) # 50% of bandwith when $MAX_DAILY is used completely # calculate maximum speed if [ -n "$DEV_DEPEND" ]; then DEV_DEPEND_SPEEDMAX=$(( $(($(( $(tc class show dev $DEV_DEPEND | grep -oe "rate [0-9]*[kKmMgG]\{0,1\}bit" | sed "s/rate //" | sed -e "s/[kK]bit//" | sed -e "s/[mM]bit/\*1000/" | sed -e "s/[gG]bit/\*1000000/" | sed -e "s/bit/\/1000/") ))*$DEV_DEPEND_MAX))/100 )) if [ -n "$DEV_DEPEND_SPEEDMAX" ]; then if [ $DEV_DEPEND_SPEEDMAX -lt $SPEEDMAX ]; then SPEEDMAX=$DEV_DEPEND_SPEEDMAX fi if [ $DEV_DEPEND_SPEEDMAX -lt $SPEEDMIN ]; then SPEEDMIN=$DEV_DEPEND_SPEEDMAX fi fi fi # calculate time in percent of today PCT_OF_DAY=$(( ($(date +%s) - $(date -d "$(date +%F) 00:00:00" +%s))*100 / $((60*60*24)) )) # calculate available contingent MAX_NOW=$(( ($MAX_DAILY*$PCT_OF_DAY)/100 + (($MAX_DAILY*$PCT_INITIAL)*( 100-$PCT_OF_DAY ))/(100*100) )) # calculate limit vnstat -i ${DEV_MEASURE} -u HOUR_NOW=$(date +%H) EXCLUDE=0 if [ $HOUR_NOW -lt $TIME_EXCLUDE_END ]; then TIME_EXCLUDE_END_MINUS_ONE=$HOUR_NOW else TIME_EXCLUDE_END_MINUS_ONE=$(($TIME_EXCLUDE_END-1)) fi if [ $HOUR_NOW -ge $TIME_EXCLUDE_START ]; then TMP=$(vnstat -i ${DEV_MEASURE} --dumpdb | grep -e "$(echo $(seq $(($TIME_EXCLUDE_START)) $(($TIME_EXCLUDE_END_MINUS_ONE))) | sed -e "s/ /;\\\|h;/g" | sed -e "s/^/h;/" | sed -e "s/$/;/")" | grep -oe "[0-9]\{1,\};[0-9]\{1,\}$" | sed -e "s/;/ /") for i in $TMP; do EXCLUDE=$(($EXCLUDE+$i)) done fi EXCLUDE=$(($EXCLUDE/1024)) if [ ! -e /tmp/force_tc_cron_exclude ]; then if [ $(( $(date +%s)-$(date -d "$(date +%F) 00:00:00" +%s)-$(cat /proc/uptime | cut -d. -f1) )) -gt 0 ]; then EXCLUDE=0 echo "Can't exclude any traffic from shaping. The router needs to be running since before 00:00:00. Do \"touch /tmp/force_tc_cron_exclude\" to force exclusion." fi else if [ $(( $(date +%s)-$(date -d "$(date +%F) 00:00:00" +%s)-$(cat /proc/uptime | cut -d. -f1) )) -lt 0 ]; then rm /tmp/force_tc_cron_exclude fi fi COUNTER_NOW=0 TMP=$(vnstat -i ${DEV_MEASURE} --dumpdb | grep -e "$(echo $(seq 0 $HOUR_NOW) | sed -e "s/ /;\\\|h;/g" | sed -e "s/^/h;/" | sed -e "s/$/;/")" | grep -oe "[0-9]\{1,\};[0-9]\{1,\}$" | sed -e "s/;/ /") for i in $TMP; do COUNTER_NOW=$(($COUNTER_NOW+$i)) done COUNTER_NOW=$((($COUNTER_NOW/1024)-$EXCLUDE)) if [ $COUNTER_NOW -lt 0 ]; then COUNTER_NOW=0 fi LEFT_NOW=$(( $MAX_NOW-$COUNTER_NOW )) PCT_MAX_NOW=$(( ($COUNTER_NOW*100) / $MAX_NOW )) #% of MAX_NOW SPEED=$(( ((($LEFT_NOW*8*1024*1024)/((60*60*24*5)/1000))/1000)/2 )) # bits left now / 0.5% of day (contingent is increased in 1% steps (+$PCT_INITIAL)) if [ $SPEED -lt $SPEEDMIN ]; then SPEED=$SPEEDMIN fi if [ $SPEED -gt $SPEEDMAX ]; then SPEED=$SPEEDMAX fi if [ $HOUR_NOW -ge $TIME_EXCLUDE_START ]; then if [ $HOUR_NOW -lt $TIME_EXCLUDE_END ]; then SPEED=$SPEEDMAX fi fi #disable interface if over limit if [ $COUNTER_NOW -ge $MAX_DAILY ]; then ifdown $DEV_SHAPE_UCI touch /tmp/${DEV_SHAPE_UCI}_is_down else if [ -e /tmp/${DEV_SHAPE_UCI}_is_down ]; then ifup $DEV_SHAPE_UCI && rm /tmp/${DEV_SHAPE_UCI}_is_down fi fi # debug echo "Counter for today: ${COUNTER_NOW}MB; ${EXCLUDE}MB excluded" echo "${LEFT_NOW}MB may be transfered after $PCT_OF_DAY% of today have passed." echo "Limiting speed to ${SPEED}kbit/s." ########## # uplink # ########## tc qdisc del dev ${DEV_SHAPE} root tc qdisc add dev ${DEV_SHAPE} root handle 1: htb default 10 tc class add dev ${DEV_SHAPE} parent 1:1 classid 1:10 htb rate ${SPEED}kbit ceil ${SPEED}kbit tc filter add dev ${DEV_SHAPE} protocol ip parent 1: prio 1 u32 match ip dst 0.0.0.0/0 flowid 1:10 # DST-IP ############ # downlink # ############ tc qdisc del dev ${DEV_SHAPE} handle ffff: ingress tc qdisc add dev ${DEV_SHAPE} handle ffff: ingress tc filter add dev ${DEV_SHAPE} parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate ${SPEED}kbit burst ${SPEED}kbit drop flowid :1
Mögliche Verbesserungen
- nur die Kernelmodule laden, die für das Script tatsächlich benötigt werden.