Limitando largura de banda com o CBQ

Publicado por Romulo 23/09/2003

[ Hits: 44.636 ]

Download script_cbq.sh




Script usado para limitar largura de banda com o CBQ.

  



Esconder código-fonte

#!/bin/sh
PATH="/bin:/sbin:/usr/bin:/usr/sbin"
CBQ_PATH="/etc/sysconfig/cbq"

### Uncomment for debugging
#LOG_FILE="/var/run/cbq-$1"

if [ -n "$LOG_FILE" ]; then
   ### Initialize log file
   echo "# `date`" > $LOG_FILE

   ### Logging equivalent of "ip" command
   ip () {
      [ -z "$LOG_FILE" ] && { /sbin/ip "[email protected]"; return; }
      echo -e "\nip [email protected]\n" >> $LOG_FILE
      /sbin/ip "[email protected]" 2>&1 | tee -a $LOG_FILE
   } # ip

   ### Logging equivalent of "tc" command
   tc () {
      [ -z "$LOG_FILE" ] && { /sbin/tc "[email protected]"; return; }
      echo -e "\ntc [email protected]\n" >> $LOG_FILE
      /sbin/tc "[email protected]" 2>&1 | tee -a $LOG_FILE
   } # tc
fi # command logging

### Remove CBQ from all devices
cbq_off () {
   for dev in `ip link| sed -n '/^[0-9]/ { s/^[0-9]\+: 
\([a-z0-9]\+\)[:@].*/\1/; p; }'`; do
      cbq_device_off $dev
   done
   return
} # cbq_off

### Remove root class from device $1
cbq_device_off () {
   tc qdisc del dev $1 root &>/dev/null
   return
} # cbq_device_off

### Display CBQ setup
cbq_show () {
   for dev in $DEVICES; do
      echo ---[ $dev: configured classes ]---------------------------
      echo; tc $1 class show dev $dev; echo
      
      echo ---[ $dev: queueing disciplines ]-------------------------
      echo; tc $1 qdisc show dev $dev; echo
   done
} # cbq_show

### Check configuration and load DEVFIELDS/CLASSLIST
cbq_init () {

   ### Check configuration in $CBQ_PATH directory and get CLASSLIST
   CLASSLIST=`find $CBQ_PATH -name 'cbq-*' -maxdepth 1 -printf "%f\n"| sort`
   if [ -z "$CLASSLIST" ]; then
      echo "**CBQ: not configured in $CBQ_PATH!"
      exit
   fi

   ### Collect all DEVICE fields from $CBQ_PATH/cbq-*
   DEVFIELDS=`find $CBQ_PATH -name 'cbq-*' -maxdepth 1 -exec sed -ne\
         's/#.*//; s/ //g; /^DEVICE=.*,.*,.*/ { s/.*=//; p; q; }; \
         /^DEVICE=/ q' {} \;| sort -u`

   ### Check if there are any devices to set up
   if [ -z "$DEVFIELDS" ]; then
      echo "**CBQ: can't find any DEVICE field in $CBQ_PATH/cbq-*!"
      exit
   fi

   ### Extract all device names from DEVICE fields in $CBQ_PATH/cbq-*
   DEVICES=`echo "$DEVFIELDS"| sed 's/,.*//'| sort -u`
       
   ### Check for multiple devices with different DEVICE fields
   if [ `echo "$DEVICES"| wc -l` -ne `echo "$DEVFIELDS"| wc -l` ]; then
      echo "**CBQ: multiple different DEVICE fields for one device found!"
      echo "$DEVFIELDS"
      exit
   fi
} # cbq_init


### Load class configuration from file $1
cbq_load_class () {
   CNAME="$CBQ_PATH/$1"
   CFILE=`sed -e 's/#.*//; s/ //g; /^$/ d' $CNAME`
   
   CLASS=`echo $1| sed 's/^cbq-0*//; s/\..*//'`
   if [ `/usr/bin/printf "%d" 0x$CLASS` -le 1 ]; then
      echo "**CBQ: class ID of $1 must be > 1!"
      cbq_off
      exit
   fi
   
   ### Device parameters   
   DEVICE=`echo "$CFILE"| sed -n '/^DEVICE=/ { s/.*=//; s/,.*//; p; q; }'`
   BANDWIDTH=`echo "$DEVFIELDS"| sed -n "/^$DEVICE,/ { s/.*,\(.*\),.*/\1/; p; q; }"`
   
   ### Class parameters
   CLASSID="1:$CLASS"
   PARENT=`echo "$CFILE"| sed -n '/^PARENT=/ { s/.*=0*//; p; q; }'`
   [ -z "$PARENT" ] && PARENT="1:1" || PARENT="1:$PARENT"
   
   LEAF=`echo "$CFILE"| sed -n '/^LEAF=/ { s/.*=//; p; q; }'`
   [ -z "$LEAF" ] && LEAF="tbf"
   
   BOUNDED=`echo "$CFILE"| sed -n '/^BOUNDED=/ { s/.*=//; p; q; }'`
   [ "$BOUNDED" = "no" ] && BOUNDED="" || BOUNDED="bounded"
   
   ISOLATED=`echo "$CFILE"| sed -n '/^ISOLATED=/ { s/.*=//; p; q; }'`
   [ "$ISOLATED" = "yes" ] && ISOLATED="isolated" || ISOLATED=""
   
   PRIO=`echo "$CFILE"| sed -n '/^PRIO=/ { s/.*=//; p; q; }'`
   RATE=`echo "$CFILE"| sed -n '/^RATE=/ { s/.*=//; p; q; }'`
   WEIGHT=`echo "$CFILE"| sed -n '/^WEIGHT=/ { s/.*=//; p; q; }'`
   if [ -z "$RATE" -o -z "$WEIGHT" -o -z "$PRIO" ]; then
      echo "**CBQ: missing RATE, WEIGHT or PRIO field(s) in $1!"
      cbq_off
      exit
   fi

   ### Leaf qdisc parameters for TBF
   if [ "$LEAF" = "tbf" ]; then
      BUFFER=`echo "$CFILE"| sed -n '/^BUFFER=/ { s/.*=//; p; q; }'`
      [ -z "$BUFFER" ] && BUFFER="10Kb/8"
   
      LIMIT=`echo "$CFILE"| sed -n '/^LIMIT=/ { s/.*=//; p; q; }'`
      [ -z "$LIMIT" ] && LIMIT="15Kb"
      
      PEAK=`echo "$CFILE"| sed -n '/^PEAK=/ { s/.*=//; p; q; }'`
      [ -n "$PEAK" ] && PEAK="peakrate $PEAK"
      
      MTU=`echo "$CFILE"| sed -n '/^MTU=/ { s/.*=//; p; q; }'`
      [ -z "$MTU" ] && MTU="1500"
   elif [ "$LEAF" = "sfq" ]; then
      PERTURB=`echo "$CFILE"| sed -n '/^PERTURB=/ { s/.*=//; p; q; }'`
      [ -n "$PERTURB" ] && PERTURB="perturb $PERTURB"
      
      QUANTUM=`echo "$CFILE"| sed -n '/^QUANTUM=/ { s/.*=//; p; q; }'`
      [ -n "$QUANTUM" ] && QUANTUM="quantum $QUANTUM"
   elif [ "$LEAF" = "cbq" ]; then
      echo "**CBQ: class $1, leaf qdisc CBQ not yet supported!"   
   fi
   
   return 0
} # cbq_load_class


### Check if ip-route is installed
if [ ! -f /sbin/tc -o ! -f /sbin/ip ]; then
   echo "**CBQ: ip-route2 utilities not installed!"
   exit
fi


########################################################################
# See how were we called                                               #
########################################################################  

case "$1" in

   ### START ###
   start)

### If you have cbq, tbf and u32 compiled into kernel, comment it out
for module in sch_cbq sch_tbf sch_sfq sch_prio cls_u32; do
        if ! modprobe $module; then
      echo "**CBQ: could not load module $module"
      exit
        fi
done


########################################################################
# Get all devices from configuration files $CBQ_PATH/cbq-*             #
# and setup CBQ root classes for them (if it is possible).             #
########################################################################  

### Load DEVICES, DEVFIELDS and CLASSLIST
cbq_init

### Try to discover interface bandwidth from DEVICE
### field and if OK - setup root class for this one
 
for dev in $DEVICES; do
   ### Retrieve device bandwidth and weight
   DEVTEMP=`echo "$DEVFIELDS"| sed -n "/^$dev,/ { s/.*,\(.*\),\(.*\)/\1,\2/; p; 
q; }"`
   DEVBWDT=${DEVTEMP%%,*}
   DEVWGHT=${DEVTEMP##*,}
   
   ### If correctly set and the device is up, setup root class
   if [ -n "$DEVBWDT" -a -n "$DEVWGHT" ]; then
      if ! ip link | grep -q "$dev[:@].*UP"; then
         echo "**CBQ: could not find device $dev! CBQ turned off."
         cbq_off
         exit
      fi

      ### Remove old root class from device
      cbq_device_off $dev

      ### Setup root class (queueing discipline) for device
      tc qdisc add dev $dev root handle 1:0 cbq \
      bandwidth $DEVBWDT avpkt 1000 cell 8

      ### Create parent class :1. Every shaper will use it as 
      ### parent unless specified otherwise using PARENT=xxxx
      tc class add dev $dev parent 1:0 classid 1:1 cbq \
      bandwidth $DEVBWDT rate $DEVBWDT weight $DEVWGHT \
      prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000
   else
      echo "**CBQ: could not determine bandwidth or weight for device $dev!"
      echo "**CBQ: setup DEVICE field properly!"
      exit
   fi
done # device


#######################################################################
# Set up all classes described in $CBQ_PATH/cbq-*                     #
#######################################################################

for classfile in $CLASSLIST; do

   cbq_load_class $classfile
   
   ### Create class and setup leaf qdisc
   tc class add dev $DEVICE parent $PARENT classid $CLASSID cbq \
   bandwidth $BANDWIDTH rate $RATE weight $WEIGHT prio $PRIO \
   allot 1514 cell 8 maxburst 20 avpkt 1000 $BOUNDED $ISOLATED
   
   ### Setup leaf queueing discipline
   if [ "$LEAF" = "tbf" ]; then
      tc qdisc add dev $DEVICE parent $CLASSID tbf \
      rate $RATE buffer $BUFFER limit $LIMIT mtu $MTU $PEAK
   elif [ "$LEAF" = "sfq" ]; then
      tc qdisc add dev $DEVICE parent $CLASSID sfq \
      $PERTURB $QUANTUM
   elif [ "$LEAF" = "cbq" ]; then
      :
   fi


   ### Create u32 filter for addresses specified by RULE fields
   RULESET=`echo "$CFILE"| sed -n '/^RULE/ { s/.*=//; p; }'`
   [ -z "$RULESET" ] && continue
   
   ### Rules present, parse them
   for rule in $RULESET; do
      u32_s=""; u32_d=""
      SADDR=""; SPORT=""
   
      ### Split up destination
      DST=${rule##*,}
      DADDR=${DST%%:*}
      
      [ "$DADDR" != "$DST" ] && DPORT=${DST##*:} || DPORT=""
      [ "$DADDR" = "*" ] && DADDR=""
         
      ### Split up source (if specified)
      if [ "$DST" != "$rule" ]; then
         SRC=${rule%%,*}
         SADDR=${SRC%%:*}
         
         [ "$SADDR" != "$SRC" ] && SPORT=${SRC##*:}
         [ "$SADDR" = "*" ] && SADDR=""
      fi
      
      ### Compose the u32 filter rules
      [ -n "$SPORT" ] && u32_s="match ip sport $SPORT 0xffff"
      [ -n "$SADDR" ] && u32_s="match ip src $SADDR $u32_s"
      [ -n "$DPORT" ] && u32_d="match ip dport $DPORT 0xffff"
      [ -n "$DADDR" ] && u32_d="match ip dst $DADDR $u32_d"
                  
      ### Uncomment the following if you want to see parsed rules
      # echo "$rule: $u32_s $u32_d"
      
      ### Attach u32 filter to the appropriate class
      tc filter add dev $DEVICE parent 1:0 protocol ip \
      prio 100 u32 $u32_s $u32_d flowid $CLASSID
   done ### rule
   
done ### class file
   ;;
   
   ### TIMECHECK ###
   timecheck)

### Load DEVICES, DEVFIELDS and CLASSLIST
cbq_init

### Current time in hh:mm format
TIME_NOW=`date +%k:%M`
TIME_ABS=$[${TIME_NOW%%:*}*60 + ${TIME_NOW##*:}]

### Check every config file for TIME parameter
for classfile in $CLASSLIST; do

   TIMERATES=`sed -ne 's/#.*//; s/ //g; /^TIME/ { s/.*=//; p; }' 
$CBQ_PATH/$classfile`
   [ -z "$TIMERATES" ] && continue
   
   MATCH=0; CHANGE=0;
   for timerate in $TIMERATES; do
      
      ### Split up TIME parameter    
          INTERVAL=${timerate%%;*}; PARAMS=${timerate##*;}
      BEG_TIME=${INTERVAL%%-*}; END_TIME=${INTERVAL##*-}
      
      ### Compute interval boundaries
      BEG_ABS=$[${BEG_TIME%%:*}*60 + ${BEG_TIME##*:}]   
      END_ABS=$[${END_TIME%%:*}*60 + ${END_TIME##*:}]
      
      ### Midnight wrap fixup   
      if [ $BEG_ABS -gt $END_ABS ]; then
         [ $TIME_ABS -le $END_ABS ] && TIME_ABS=$[TIME_ABS + 24*60]
         END_ABS=$[END_ABS + 24*60]
      fi
   
      ### If the time matches, remembers params and set flag
      if [ $TIME_ABS -ge $BEG_ABS -a $TIME_ABS -lt $END_ABS ]; then
         TMP_RATE=${PARAMS%%/*}
         TMP_WGHT=${PARAMS#*/}
         TMP_PEAK=${TMP_WGHT#*/}
         
         [ "$TMP_PEAK" = "$TMP_WGHT" ] && TMP_PEAK="" || TMP_WGHT={$TMP_WGHT%%/*}
            
         [ -n "$TMP_PEAK" ] && TMP_PEAK="peakrate $TMP_PEAK"
         MATCH=1
      fi
   done ### timerate

   cbq_load_class $classfile
             
   ### Get current RATE of CBQ class
   RATE_NOW=`tc class show dev $DEVICE| sed -n \
         "/cbq $CLASSID / { s/.*rate //; s/ .*//; p; q; }"`
   [  -z "$RATE_NOW" ] && continue
   
   ### Time interval match is found
   if [ $MATCH -ne 0 ]; then
   
      ### Check if there is any change in class RATE
      if [ "$RATE_NOW" != "$TMP_RATE" ]; then
         NEW_RATE="$TMP_RATE"
         NEW_WGHT="$TMP_WGHT"
         NEW_PEAK="$TMP_PEAK"
         CHANGE=1
      fi
   
   ### Match not found, reset to default RATE if necessary
   elif [ "$RATE_NOW" != "$RATE" ]; then   
      NEW_WGHT="$WEIGHT"
      NEW_RATE="$RATE"
      NEW_PEAK="$PEAK"
      CHANGE=1
   fi
   
   ### If there's a change, replace CBQ class and leaf qdisc
   [ $CHANGE -ne 1 ] && continue
   
   ### Get leaf qdisc handle
   LEAF_HND=`tc class show dev $DEVICE| sed -n \
        "/cbq $CLASSID .* leaf / { s/.*leaf //; s/ .*//; p; q; }"`
   [ -z "$LEAF_HND" ] && continue
          
   ### Replace CBQ class      
   tc class replace dev $DEVICE classid $CLASSID cbq \
   bandwidth $BANDWIDTH rate $NEW_RATE weight $NEW_WGHT prio $PRIO \
   allot 1514 cell 8 maxburst 20 avpkt 1000 $BOUNDED $ISOLATED
   
   ### Replace leaf qdisc
   if [ "$LEAF" = "tbf" ]; then
      tc qdisc replace dev $DEVICE handle $LEAF_HND tbf \
      rate $NEW_RATE buffer $BUFFER limit $LIMIT mtu $MTU $NEW_PEAK
   elif [ "$LEAF" = "sfq" ]; then
      ### SFQ does not support parameter changes
      ### yet so it does not need replacing
      
      #tc qdisc replace dev $DEVICE handle $LEAF_HND sfq \
      #$PERTURB $QUANTUM
      :
   elif [ "$LEAF" = "cbq" ]; then
      :
   fi

   echo "**CBQ: $TIME_NOW: class $CLASS on $DEVICE changed rate ($RATE_NOW -> 
$NEW_RATE)"
done ### class file
5
   ;;
   
   ### STOP ###
   stop)
      cbq_off
   ;;
   
   ### RESTART ###
   restart)
      $0 stop
      $0 start
   ;;
   
   ### LIST ###
   list)
      cbq_init
      cbq_show
   ;;
   
   ### STATS ###
   stats)
      cbq_init
      cbq_show -s
   ;;
      
   ### default ###
   *)
      echo "Usage: " `basename $0` "{start|stop|restart|timecheck|list|stats}"
esac

Scripts recomendados

Testando se a conexão com a Internet está ativa

Script - monitorando servidor

Script de instalação do Qmail

Ativar serviço que está parado

zsh: Sattolo's Random Cyclic Permutation


  

Comentários
[1] Comentário enviado por Estival em 26/11/2003 - 13:48h

Como utilizar isso ??? , não tem nenhum comentario de como utilizar este script ??

[2] Comentário enviado por julioarraes em 11/06/2004 - 14:00h

como eu faço para saber como usar esse seu script... pois não sei como usa-lo?

[3] Comentário enviado por pcnmota em 16/07/2004 - 11:22h

Ola !!!! Gostaria de parabenizar nosso amigo pelo script, solucionou minha dor de cabeca de semanas aqui.... to conseguindo controlar a banda de meus clientes tranquilamente. Obtive sucesso utilizando as distros Red Hat 7.3 e Conectiva 8.
Valeu amigao.....

[4] Comentário enviado por lscorrearj em 20/01/2005 - 20:13h

gostaria de explicações a respeito deste script...-> configurações... obrigado...

[5] Comentário enviado por fabiobarros em 02/04/2005 - 23:52h

Ele dividiu em duas partes... esse script é a segunda, a primeira é um artigo:
http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=367

[6] Comentário enviado por gameover em 05/02/2008 - 22:34h

fala ae cara sera que vc poderia me dar uma dica de como eu posso montar um servidor de controlador de banda com o satux??????
Valeu!!!!!!!

[7] Comentário enviado por andre_mandrake em 27/03/2008 - 13:23h

Este script deve ser salvo onde?

[8] Comentário enviado por FireBird em 20/04/2010 - 20:48h

Fala galera do VOL... Saudações... Muito tempo que não apareço por aqui...rs...Mas, vamo la...

Recentemente recebi o encargo de uma rede corporativa e resolvi implantar o cbq ao invés do controle pelo squid ou htb. Fiz as configurações de sempre e estava tudo OK até eu perceber, de repente, uma coisa: Minha banda, não somente a da Internet, mas, a comunicação da rede Interna estava limitada àquela configurada nos arquivos de configuração do cbq. Procurando na Internet, não encontrei solução. Há alguma forma de eu bloquear somente o tráfego para a Internet? Ou, quem sabe, estou fazendo algo errado(se for o caso, por favor me digam se não possuem o mesmo problema).

Agradeço desde já.

[9] Comentário enviado por importantz em 06/08/2010 - 12:42h

Cara, seguinte.. Eu fiz o controle de banda e funcionou ok.
Até aí, tudo bem... Mas só funciona se o cliente não utilizar nenhum acelerador de downloads, caso o cliente utilize a taxa de transferência consegue passar, e muito, do limite.


Contribuir com comentário