En este articulo veremos como limitar el ancho de banda de los DomUs en XEN 4.1 instalado en una debian squeeze.
Aclaración debe estar configurado el DomU de modo que vif debe tener seteados vifname y mac, el parámetro name del VPS y vifname sean iguales, también debemos agregar una linea de configuración con la variable bandwith_limit, XEN no reconoce este parámetro y lo ignorara pero sera usado por nuestro script. Además debemos asegurarnos que estén instalados los paquetes mawk, ethtool e iproute.
Podemos ver un archivo de configuración de ejemplo.
root@x49:/# cat /etc/xen/x50.cfg # # Configuration file for the Xen instance x50, created # by xen-tools 4.3.1 on Thu Jan 17 01:33:06 2013. # # # Kernel + memory size # kernel = '/boot/vmlinuz-3.2.0-0.bpo.4-amd64' ramdisk = '/boot/initrd.img-3.2.0-0.bpo.4-amd64' vcpus = '1' memory = '1024' # # Disk device(s). # root = '/dev/xvda2 ro' disk = [ 'file:/var/lib/xen/DomUs/domains/x50/root.img,xvda2,w', 'file:/var/lib/xen/DomUs/domains/x50/swap.img,xvda1,w', ] # # Physical volumes # # # Hostname # name = 'x50' # # Networking # vif = [ 'ip=192.168.252.50 ,mac=00:16:C0:A8:FC:32,vifname=x50' ] # # Behaviour # on_poweroff = 'destroy' on_reboot = 'restart' on_crash = 'restart' extra = 'elevator=deadline console=hvc0 noht loglevel=0' bandwith_limit = '4MBit' root@x49:/#
Podemos ver resaltadas las lineas donde estan las variables name, vifname, mac y bandwith_limit
Luego creamos el archivo /usr/local/xen/bandwith-limit.sh con el siguiente contenido
root@x49:/# cat /usr/local/xen/bandwith-limit.sh #!/bin/bash TC=/sbin/tc IPTABLES=/sbin/iptables ECHO=/bin/echo CAT=/bin/cat CUT=/usr/bin/cut SED=/bin/sed TR=/usr/bin/tr WC=/usr/bin/wc GREP=/bin/grep IFCONFIG=/sbin/ifconfig MAWK=/usr/bin/mawk SORT=/usr/bin/sort XEN=/usr/sbin/xen ETHTOOL=/sbin/ethtool XENSTORE_READ=/usr/sbin/xenstore-read ############################################################################################################################################################################################################# function set_bridge_limit_up { local ETHS=`${IFCONFIG} | ${GREP} encap:Ethernet | ${MAWK} '{print $1;}' | ${GREP} eth` for eth_data in ${ETHS} do if [ ${eth_data} = ${ETH_BR} ] then local NUM_TC_RULES=`${TC} class show dev ${eth_data} | ${WC} -l` if [ "${NUM_TC_RULES}" = "0" ] then limit_device ${eth_data} fi else local NUM_TC_RULES=`${TC} qdisc show dev ${eth_data} | ${GREP} rate | ${GREP} burst | ${GREP} peakrate | ${WC} -l` if [ "${NUM_TC_RULES}" = "0" ] then limit_device ${eth_data} fi fi done } function limit_device() { local DEV_IN=$1 local ETH_SUB3=`${ECHO} ${DEV_IN} | ${CUT} -b 1-3` if [ "${ETH_SUB3}" = "eth" ] then local CEIL_LIMIT_VALUE=`${ETHTOOL} ${DEV_IN} | ${GREP} -i speed: | ${MAWK} -F ":" '{print $2;}' | ${MAWK} -F "/" '{print $1;}' | ${TR} -d " " | ${TR} -d "a-zA-Z" ` local RATE_LIMIT_VALUE=$[ ${CEIL_LIMIT_VALUE} * 95 / 100 ] local RATE_LIMIT_UNIT=`${ETHTOOL} ${DEV_IN} | ${GREP} -i speed: | ${MAWK} -F ":" '{print $2;}' | ${MAWK} -F "/" '{print $1;}' | ${TR} -d " " | ${TR} -d "0-9" | ${TR} '[A-Z]' '[a-z]' ` if [ ${RATE_LIMIT_UNIT} = "mb" ] then RATE_LIMIT_UNIT=mbit elif [ ${RATE_LIMIT_UNIT} = "kb" ] then RATE_LIMIT_UNIT=kbit fi local RATE_IN=${RATE_LIMIT_VALUE}${RATE_LIMIT_UNIT} local CEIL_IN=${CEIL_LIMIT_VALUE}${RATE_LIMIT_UNIT} if [ -z "${RATE_IN}" ] then RATE_IN=95mbit CEIL_IN=100mbit fi if [ "${DEV_IN}" = "${ETH_BR}" ] then ${TC} qdisc add dev ${DEV_IN} root handle 1: htb 1>/dev/null 2>>${FILE_LOG_ERROR} ${TC} class add dev ${DEV_IN} parent 1: classid 1:1 htb rate ${RATE_IN} ceil ${CEIL_IN} 1>/dev/null 2>>${FILE_LOG_ERROR} else ${TC} qdisc add dev ${DEV_IN} root tbf rate ${RATE_IN} burst 64kb latency 25ms mpu 64 peakrate ${CEIL_IN} mtu 64kb 1>/dev/null 2>>${FILE_LOG_ERROR} fi else local DOMID=`${XEN} domid ${DEV_IN}` local MAC_IN=`${XENSTORE_READ} /local/domain/${DOMID}/device/vif/0/mac` local CLASS_TR=$[ (${DOMID} + 1007) % 10000 ] local RATE_LIMIT_VALUE=`${CAT} ${DIR_CONFIG}/${DEV_IN}.cfg | ${GREP} bandwith_limit | ${MAWK} -F "=" '{print $2;}' | ${TR} -d " '\"" | ${TR} -d "a-zA-Z" ` local RATE_LIMIT_UNIT=`${CAT} ${DIR_CONFIG}/${DEV_IN}.cfg | ${GREP} bandwith_limit | ${MAWK} -F "=" '{print $2;}' | ${TR} -d " '\"" | ${TR} -d "0-9" ` if [ ${RATE_LIMIT_UNIT} = "mb" ] then RATE_LIMIT_UNIT=mbit elif [ ${RATE_LIMIT_UNIT} = "kb" ] then RATE_LIMIT_UNIT=kbit fi local CEIL_LIMIT_VALUE=$[ ${RATE_LIMIT_VALUE} * 110 / 100 ] if [ "${CEIL_LIMIT_VALUE} = ${RATE_LIMIT_VALUE}" ] then CEIL_LIMIT_VALUE=$[ ${CEIL_LIMIT_VALUE} + 1 ] fi local RATE_IN=${RATE_LIMIT_VALUE}${RATE_LIMIT_UNIT} local CEIL_IN=${CEIL_LIMIT_VALUE}${RATE_LIMIT_UNIT} if [ -z "${RATE_IN}" ] then RATE_IN=10mbit CEIL_IN=12mbit fi set_bridge_limit_up ${TC} qdisc add dev ${DEV_IN} root tbf rate ${RATE_IN} burst 64kb latency 25ms mpu 64 peakrate ${CEIL_IN} mtu 64kb 1>/dev/null 2>>${FILE_LOG_ERROR} ${TC} class add dev ${ETH_BR} parent 1:1 classid 1:${CLASS_TR} htb rate ${RATE_IN} ceil ${CEIL_IN} prio 4 1>/dev/null 2>>${FILE_LOG_ERROR} ${TC} qdisc add dev ${ETH_BR} parent 1:${CLASS_TR} handle ${CLASS_TR}: sfq perturb 10 1>/dev/null 2>>${FILE_LOG_ERROR} ${IPTABLES} -t mangle -A FORWARD -m mac --mac-source ${MAC_IN} -j CLASSIFY --set-class 1:${CLASS_TR} 1>/dev/null 2>>${FILE_LOG_ERROR} fi } function unlimit_device() { local DEV_IN=$1 local ETH_SUB3=`${ECHO} ${DEV_IN} | ${CUT} -b 1-3` if [ "${ETH_SUB3}" = "eth" ] then if [ "${DEV_IN}" = "${ETH_BR}" ] then ${TC} qdisc del dev ${DEV_IN} root handle 1: htb 1>/dev/null 2>>${FILE_LOG_ERROR} else ${TC} qdisc del dev ${DEV_IN} root 1>/dev/null 2>>${FILE_LOG_ERROR} fi else local DOMID=`${ECHO} ${XENBUS_PATH} | ${MAWK} -F "/" '{print $3;}' 2>>${FILE_LOG_ERROR}` local CLASS_TR=$[ (${DOMID} + 1007) % 10000 ] local RATE_LIMIT_VALUE=`${CAT} ${DIR_CONFIG}/${DEV}.cfg | ${GREP} bandwith_limit | ${MAWK} -F "=" '{print $2;}' | ${TR} -d " '\"" | ${TR} -d "a-zA-Z" ` local RATE_LIMIT_UNIT=`${CAT} ${DIR_CONFIG}/${DEV}.cfg | ${GREP} bandwith_limit | ${MAWK} -F "=" '{print $2;}' | ${TR} -d " '\"" | ${TR} -d "0-9" ` local CEIL_LIMIT_VALUE=$[ ${RATE_LIMIT_VALUE} * 110 / 100 ] if [ ${RATE_LIMIT_UNIT} = "mb" ] then RATE_LIMIT_UNIT=mbit elif [ ${RATE_LIMIT_UNIT} = "kb" ] then RATE_LIMIT_UNIT=kbit fi local RATE_IN=${RATE_LIMIT_VALUE}${RATE_LIMIT_UNIT} local CEIL_IN=${CEIL_LIMIT_VALUE}${RATE_LIMIT_UNIT} if [ -z "${RATE_IN}" ] then RATE_IN=10mbit CEIL_IN=12mbit fi ${TC} qdisc del dev ${ETH_BR} parent 1:${CLASS_TR} handle ${CLASS_TR}: sfq perturb 10 1>/dev/null 2>>${FILE_LOG_ERROR} ${TC} class del dev ${ETH_BR} parent 1:1 classid 1:${CLASS_TR} htb rate ${RATE_IN} ceil ${CEIL_IN} prio 4 1>/dev/null 2>>${FILE_LOG_ERROR} #${TC} qdisc del dev ${DEV_IN} root 1>/dev/null 2>>${FILE_LOG_ERROR} local IPCHAIN=`${IPTABLES} -n -t mangle -L FORWARD --line-numbers | ${GREP} 1:${CLASS_TR} | ${MAWK} '{print $1;}'` if [ -n "${IPCHAIN}" ] then ${IPTABLES} -t mangle -D FORWARD ${IPCHAIN} 1>/dev/null 2>>${FILE_LOG_ERROR} fi fi } ############################################################################################################################################################################################################# DIR_CONFIG=/etc/xen ETH_BR=eth1 THIS_FILE=`basename $0` FILE_LOG_ERROR=/var/log/${THIS_FILE}.log ############################################################################################################################################################################################################# COMMAND=$1 DEV=$2 DIR_CONFIG=/etc/xen ETH_BR=eth1 if [ "${COMMAND}" = "start" ] then limit_device ${DEV} fi if [ "${COMMAND}" = "stop" ] then unlimit_device ${DEV} fi root@x49:/#
Como se puede ver en las lineas resaltadas nuestro script lee el parámetro bandwith_limit del archivo de configuración, también esta resaltada la linea «ETH_BR=eth1» deben reemplazar eth1 por la interfaz física que este en el bridge
Luego debemos editar el archivo /usr/local/xen/vif-bridge-local.sh de modo que luzca así
NOTA: Suponemos que estamos usando una configuración similar a la de nuestros anteriores artículos 1 y 2
Nota 2: La unidad del parámetro bandwith_limit debe ser una unidad aceptada por el comando tc, ver man tc la sección units los valores aceptados para rate (kbps, mbps, kbit, mbit, bps)
root@x49:/# cat /usr/local/xen/vif-bridge-local.sh #!/bin/bash XENSTORE_READ=/usr/sbin/xenstore-read VNSTAT=/usr/bin/vnstat LIMIT_BANDWITH=/usr/local/xen/bandwith-limit.sh THIS_FILE=`basename $0` FILE_LOG_ERRORS=/var/log/${THIS_FILE}.log . /etc/xen/scripts/xen-script-common.sh ACTION_TYPE=$1 TYPEIF=$2 evalVariables "$@" dev=vif case "$type_if" in vif) dev=${vif} ;; tap) dev=$INTERFACE ;; *) exit 1 ;; esac if [ "${ACTION_TYPE}" = "online" ] then if [ "${type_if}" = "vif" ] then /etc/xen/scripts/vif-bridge $@ KEY_VIFNAME=/local/domain/0/${XENBUS_PATH}/vifname vifname=`${XENSTORE_READ} ${KEY_VIFNAME} 2>/dev/null` ${VNSTAT} -u -i ${vifname} 1>/dev/null 2>>${FILE_LOG_ERRORS} ${VNSTAT} --enable -i ${vifname} 1>/dev/null 2>>${FILE_LOG_ERRORS} ${VNSTAT} --sync -i ${vifname} 1>/dev/null 2>>${FILE_LOG_ERRORS} ${VNSTAT} --reset -i ${vifname} 1>/dev/null 2>>${FILE_LOG_ERRORS} ${LIMIT_BANDWITH} start ${vifname} else /etc/xen/scripts/vif-bridge $@ fi fi if [ "${ACTION_TYPE}" = "offline" ] then if [ "${type_if}" = "vif" ] then KEY_VIFNAME=/local/domain/0/${XENBUS_PATH}/vifname vifname=`${XENSTORE_READ} ${KEY_VIFNAME} 2>/dev/null` ${LIMIT_BANDWITH} stop ${vifname} ${VNSTAT} -r --disable -i ${vifname} 1>/dev/null 2>>${FILE_LOG_ERRORS} /etc/xen/scripts/vif-bridge $@ else /etc/xen/scripts/vif-bridge $@ fi fi if [ "${ACTION_TYPE}" = "add" ] then /etc/xen/scripts/vif-bridge $@ fi root@x49:/#
Por ultimo si queremos que a los VPSs que instalemos con xen-tools al archivo de configuración del DomU se le agregue automáticamente la linea bandwith_limit = ’10mbit’ debemos editar el archivo /etc/xen-tools/xm.tmpl y agregarle al final la siguiente linea
bandwith_limit = '10mbit';
De modo que quede así
root@x49:/# cat /etc/xen-tools/xm.tmpl # # Configuration file for the Xen instance {$hostname}, created # by xen-tools {$xen_tools_version} on { scalar localtime }. # # # Kernel + memory size # { if ( ( $kernel ) && ( !defined($pygrub)) ) { $OUT.= "kernel = '$kernel'"; } } { if ( ( $initrd ) && ( !defined($pygrub)) ) { $OUT.= "ramdisk = '$initrd'"; } } { if ( $pygrub ) { my $pygrub_bin = ''; foreach my $pygrub_path (reverse glob('/usr/lib/xen-*/bin/pygrub /usr/lib/xen-default/bin/pygrub /usr/*bin/pygrub')) { if (-x $pygrub_path) { $pygrub_bin = $pygrub_path; last; } } die "pygrub not found" unless $pygrub_bin; $OUT .= "bootloader = '$pygrub_bin'\n"; } } vcpus = '{$vcpus}' memory = '{$memory}' # # Disk device(s). # { if ( !defined($image_vbd ) ) { for ( my $i = $#PARTITIONS; $i >= 0 ; $i-- ) { if ( $PARTITIONS[$i]{'mountpoint'} eq '/' ) { $OUT .= "root = '/dev/$device" . ($i + 1) . " ro'\n"; } } $OUT .= "disk = [\n"; for ( my $i = $#PARTITIONS; $i >= 0 ; $i-- ) { if ( $PARTITIONS[$i]{'mountpoint'} eq '/' ) { $OUT .= " '$PARTITIONS[$i]{'imagetype'}$PARTITIONS[$i]{'image'},$device" . ( $i + 1 ) .",w',\n"; } } for ( my $i = $#PARTITIONS; $i >= 0 ; $i-- ) { if ( $PARTITIONS[$i]{'mountpoint'} ne '/' ) { $OUT .= " '$PARTITIONS[$i]{'imagetype'}$PARTITIONS[$i]{'image'},$device" . ( $i + 1 ) .",w',\n"; } } $OUT .= " ]\n"; } } # # Physical volumes # { if ( $image_vbd ) { $OUT .= "root = '/dev/$device" . "2 ro'\n"; $OUT .= "disk = [\n"; $OUT .= " '$image_vbd," . $device . "2,w',\n"; if ( $swap_vbd ) { $OUT .= " '$swap_vbd," . $device . "1,w',\n"; } $OUT .= " ]\n"; } } # # Hostname # name = '{$hostname}' # # Networking # { if ( $dhcp ) { $OUT .= "dhcp = 'dhcp'\n"; # Setup the mac address, if present. my $m = ''; if ( $mac ) { $m = "mac=$mac" } my $br = ''; if ( $bridge ) { if ( $mac ) { $br = ",bridge=$bridge" } else { $br = "bridge=$bridge" } } $OUT .= "vif = [ '"; $OUT .= "$m"; $OUT .= "$br"; $OUT .= "' ]"; } else { # # Setup the mac address, if present. # my $m = ''; if ( $mac ) { $m = ",mac=$mac" } my $vn = ''; if ( $vifname ) { $vn = ",vifname=$vifname"; } my $br = ''; if ( $bridge ) { $br = ",bridge=$bridge" } $OUT .= "vif = [ 'ip=$ips"; $OUT .= "$m"; $OUT .= "$vn"; $OUT .= "$br"; $OUT .= "' ]"; } } # # Behaviour # on_poweroff = 'destroy' on_reboot = 'restart' on_crash = 'restart' { if ( $admins ) { $OUT .= "xen_shell = '$admins'\n"; } } bandwith_limit = '10mbit' root@x49:/#
Listo, luego chequear que la configuración funcione correctamente, reiniciar los VPSs y testear el bandwith tanto de entrada como de salida de los VPSs.

About Ricardo Marcelo Alvarez
- Web |
- More Posts(58)