Limitando largura de banda com o CBQ

Publicado por Romulo 23/09/2003

[ Hits: 45.324 ]

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 "$@"; return; }
      echo -e "\nip $@\n" >> $LOG_FILE
      /sbin/ip "$@" 2>&1 | tee -a $LOG_FILE
   } # ip

   ### Logging equivalent of "tc" command
   tc () {
      [ -z "$LOG_FILE" ] && { /sbin/tc "$@"; return; }
      echo -e "\ntc $@\n" >> $LOG_FILE
      /sbin/tc "$@" 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

lock com xscreensaver

Jftp Script - Script para automação de um processo FTP

Inserção de máquinas no banco de dados para controle interno

Ver último twitter pelo terminal ou na barra de notificação

Script para correção de arquivos Makefile usando comando patch


  

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




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts