Controle de banda para VoIP no Linux
Dica publicada em Linux / Internet
Controle de banda para VoIP no Linux
1. Introdução
Um produto comum para fazer chamadas telefônicas via Internet é o ATA.Muitas empresas compram esses adaptadores VoIP e ligam em suas redes locais, mas percebem um problema frequente com as ligações: elas ficam entrecortadas, principalmente para o lado remoto da conversa.
Minha solução é usar um script no roteador Linux que faz a interface com a Internet. Esse script implementa um controle de banda simples usando a política HTB, reservando uma parte da banda para o adaptador VoIP. O script é o seguinte:
#!/bin/sh
IPTABLES="/sbin/iptables"
TC="/sbin/tc"
# parâmetros
IF_INET=eth0
IF_LOCAL=eth1
DOWN_MAX=1000kbit
UP_MAX=1000kbit
IP_ATA=192.168.1.50
BW_ATA=120kbit
ID_ATA=1000
start_tc() {
# download
$TC qdisc add dev $IF_LOCAL root handle 1: htb default 5
$TC class add dev $IF_LOCAL parent 1: classid 1:1 htb rate $DOWN_MAX ceil $DOWN_MAX prio 1
$TC class add dev $IF_LOCAL parent 1: classid 1:5 htb rate 100000kbit ceil 100000kbit prio 5
$TC qdisc add dev $IF_LOCAL parent 1:5 handle 20: sfq perturb 10
# sip (internet -> empresa)
$IPTABLES -t mangle -A POSTROUTING -o $IF_LOCAL -d $IP_ATA -j MARK --set-mark $ID_ATA
$TC class add dev $IF_LOCAL parent 1:1 classid 1:$ID_ATA htb rate $BW_ATA ceil $BW_ATA prio 1
$TC filter add dev $IF_LOCAL parent 1: protocol ip prio 1 handle $ID_ATA fw flowid 1:$ID_ATA
# upload
$TC qdisc add dev $IF_INET root handle 1: htb default 5
$TC class add dev $IF_INET parent 1: classid 1:1 htb rate $UP_MAX ceil $UP_MAX prio 1
$TC class add dev $IF_INET parent 1: classid 1:5 htb rate $UP_MAX ceil $UP_MAX prio 5
$TC qdisc add dev $IF_INET parent 1:5 handle 20: sfq perturb 10
# sip (empresa -> internet)
$IPTABLES -t mangle -A PREROUTING -i $IF_LOCAL -s $IP_ATA -j MARK --set-mark $ID_ATA
$TC class add dev $IF_INET parent 1:1 classid 1:$ID_ATA htb rate $BW_ATA ceil $BW_ATA prio 1
$TC filter add dev $IF_INET parent 1: protocol ip prio 1 handle $ID_ATA fw flowid 1:$ID_ATA
}
stop_tc() {
$TC qdisc del dev $IF_INET root
$TC qdisc del dev $IF_LOCAL root
$IPTABLES -t mangle -F
}
case "$1" in
start)
echo -n "Iniciando controle de banda..."
start_tc
echo " ok"
;;
stop)
echo -n "Desligando controle de banda..."
stop_tc
echo " ok"
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
IPTABLES="/sbin/iptables"
TC="/sbin/tc"
# parâmetros
IF_INET=eth0
IF_LOCAL=eth1
DOWN_MAX=1000kbit
UP_MAX=1000kbit
IP_ATA=192.168.1.50
BW_ATA=120kbit
ID_ATA=1000
start_tc() {
# download
$TC qdisc add dev $IF_LOCAL root handle 1: htb default 5
$TC class add dev $IF_LOCAL parent 1: classid 1:1 htb rate $DOWN_MAX ceil $DOWN_MAX prio 1
$TC class add dev $IF_LOCAL parent 1: classid 1:5 htb rate 100000kbit ceil 100000kbit prio 5
$TC qdisc add dev $IF_LOCAL parent 1:5 handle 20: sfq perturb 10
# sip (internet -> empresa)
$IPTABLES -t mangle -A POSTROUTING -o $IF_LOCAL -d $IP_ATA -j MARK --set-mark $ID_ATA
$TC class add dev $IF_LOCAL parent 1:1 classid 1:$ID_ATA htb rate $BW_ATA ceil $BW_ATA prio 1
$TC filter add dev $IF_LOCAL parent 1: protocol ip prio 1 handle $ID_ATA fw flowid 1:$ID_ATA
# upload
$TC qdisc add dev $IF_INET root handle 1: htb default 5
$TC class add dev $IF_INET parent 1: classid 1:1 htb rate $UP_MAX ceil $UP_MAX prio 1
$TC class add dev $IF_INET parent 1: classid 1:5 htb rate $UP_MAX ceil $UP_MAX prio 5
$TC qdisc add dev $IF_INET parent 1:5 handle 20: sfq perturb 10
# sip (empresa -> internet)
$IPTABLES -t mangle -A PREROUTING -i $IF_LOCAL -s $IP_ATA -j MARK --set-mark $ID_ATA
$TC class add dev $IF_INET parent 1:1 classid 1:$ID_ATA htb rate $BW_ATA ceil $BW_ATA prio 1
$TC filter add dev $IF_INET parent 1: protocol ip prio 1 handle $ID_ATA fw flowid 1:$ID_ATA
}
stop_tc() {
$TC qdisc del dev $IF_INET root
$TC qdisc del dev $IF_LOCAL root
$IPTABLES -t mangle -F
}
case "$1" in
start)
echo -n "Iniciando controle de banda..."
start_tc
echo " ok"
;;
stop)
echo -n "Desligando controle de banda..."
stop_tc
echo " ok"
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
2. Parâmetros
Os parâmetros no início do script devem ser ajustados para cada caso. IF_INET é o nome da interface ligada à Internet, IF_LOCAL é o nome da interface ligada à rede local.DOWN_MAX é a velocidade nominal da conexão Internet no sentido da Internet para a empresa (download). UP_MAX é a velocidade no sentido da empresa para a Internet (upload). Note que a sintaxe do comando tc é 'kbit' e não 'kbps'.
IP_ATA é o endereço IP do adaptador VoIP. BW_ATA é a banda reservada para o adaptador. Cada ligação VoIP usa aproximadamente 30 kbps, então o script acima está configurado com 120 kbps para priorizar 4 ligações VoIP.
O parâmetro ID_ATA é um número qualquer, e serve para permitir o acréscimo de mais adaptadores VoIP ao script. Se quiser controlar 2 adaptadores, basta trocar ID_ATA por ID_ATA1 e ID_ATA2 e copiar os blocos de linhas marcados com "sip (internet -> empresa)" e "sip (empresa -> internet)".
3. Dependências
O script depende dos comandos tc e iptables, que em distribuições Debian estão nos pacotes iproute e iptables, respectivamente. O roteador Linux deve rodar pelo menos o kernel 2.6.18, que tem suporte ao protocolo SIP.4. Instalação e uso
O script pode ser instalado em /etc/init.d/htb-voip ou em /usr/local/bin/htb-voip. Para ativar, basta fazer:# /etc/init.d/htb-voip start
E para desativar, o comando é similar:
# /etc/init.d/htb-voip stop
Eu coloquei meus ATA numa classe diferente daquela usada na minha rede.
O IP setado na variável IP_ATA poderia ser 192.168.0.1/24? (Estou pensando em implementar seu script para marcar os pacotes que chegam na minha rede também).