Primeiramente, vamos criar o script que será utilizado na inicialização do CBQ.
# vi /sbin/script_cbq.sh
#!/bin/sh
PATH="/bin:/sbin:/usr/bin:/usr/sbin"
CBQ_PATH="/etc/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 "
ip
[email protected]
" >> $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 "
tc
[email protected]
" >> $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
for dev in `ifconfig |grep eth1 |awk {'print$1'}`; 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
"| 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