Newsgroup: it.comp.os.linux.sys
Titolo: qos per voip

Ciao,
sto cercando di realizzare uno script che limiti di molto la navigazione di
tutti gli host, tranne degli apparecchi per il voip, quando viene
individuata una telefonata in corso.
La situazione è questa: router linux che fa il nat per una serie di host e
per 2 apparecchi voip.
Questo è la bozza di script al quale sono arrivato fino adesso.
I -j RETURN probabilmente sono superflui.
Conoscete un altro sistema per individuare una telefonata in corso? Io ho
usato tcpdump in questo modo. Si mette in ascolto e non appena individua un
certo numero di pacchetti ritorna. Se questo numero di pacchetti è
individuato in meno di un tot di secondi, allora c'è una telefonata in
corso (per il momento ho messo 30 pacchetti in 7 secondi). Suggerimenti?
Ho un altro problema, quello di scrivere un filtro con iptables (con -j
MARK) o con tc che individui i pacchetti per il pppoe (devo settare una
regola anche per quelli...).
Grazie.
#!/bin/bash
function init_firewall(){
        iptables -t mangle -N QOS 2>/dev/null
        iptables -t mangle -F QOS
        for i in $VOIP; do
                iptables -t mangle -A QOS -s $i -j MARK --set-mark 1
                iptables -t mangle -A QOS -s $i -j RETURN
                iptables -t mangle -A QOS -d $i -j MARK --set-mark 1
                iptables -t mangle -A QOS -d $i -j RETURN
        done
        iptables -t mangle -A QOS -j MARK --set-mark 2
}
function only_voip(){
        tc qdisc del dev ppp0 root 2>/dev/null
        tc qdisc del dev eth0 root 2>/dev/null
        tc qdisc add dev ppp0 root handle 1: prio 
 
        #voip
        tc qdisc add dev ppp0 parent 1:1 handle 10: sfq
        #altro
        tc qdisc add dev ppp0 parent 1:2 handle 20: tbf rate 40kbit burst 1600 \
 limit 3000
        #nessun pacchetto dovrebbe mai entrare in questa classe, ma metto il tbf
        #per sicurezza
        tc qdisc add dev ppp0 parent 1:3 handle 30: tbf rate 40kbit burst 1600 \
        limit 3000
        #voip
        tc filter add dev ppp0 protocol ip parent 1: prio 1 handle 1 fw flowid 1:1 
        #altro
        tc filter add dev ppp0 protocol ip parent 1: prio 2 handle 2 fw flowid 1:2 
        tc qdisc add dev eth0 root handle 1: prio
        tc qdisc add dev eth0 parent 1:1 handle 10: pfifo
        tc qdisc add dev eth0 parent 1:2 handle 20: sfq
        tc qdisc add dev eth0 parent 1:3 handle 30: tbf rate 40kbit burst 1600 \
 limit 3000
#pppoe
#tc filter add dev eth0 protocol ip parent 1: prio 1 handle 4 fw flowid 1:1 
        #voip
        tc filter add dev eth0 protocol ip parent 1: prio 2 handle 1 fw flowid 1:2
        #altro
        tc filter add dev eth0 protocol ip parent 1: prio 2 handle 2 fw flowid 1:3 
        iptables -t mangle -A PREROUTING -j QOS
}
function stop_voip_only(){
        tc qdisc del dev ppp0 root
        tc qdisc del dev eth0 root
        iptables -t mangle -D PREROUTING -j QOS
}
function check_activity(){
        RULE="host 192.168.1.60 or host 192.168.1.61"
        #for i in $VOIP; do
        #       RULE="$RULE or host $i "
        #done
        tcpdump -c $NUM_PACKETS -p -q $RULE >/dev/null 2>&1
}
VOIP="192.168.1.60 192.168.1.61"
NUM_PACKETS=30
INTER=7
init_firewall
while /bin/true; do
        TIME=`date +%s`
        check_activity
        TIME_N=`date +%s`
        #echo $((TIME_N - TIME))
        if [ $((TIME_N - TIME)) -lt $INTER ]; then
                logger "Telefonata in corso... attivo qos"
                only_voip;
                sleep 4m;       
                logger "Disattivo qos."
                stop_voip_only;
        fi 
done

 individuata una telefonata in corso.
...
Ho fatto delle correzioni, questo sembra funzionare bene:
function init_firewall(){
        iptables -t mangle -N QOS_IN 2>/dev/null
        iptables -t mangle -N QOS_OUT 2>/dev/null
        iptables -t mangle -F QOS_IN
        iptables -t mangle -F QOS_OUT
        for i in $VOIP; do
                iptables -t mangle -A QOS_IN -s $i -j MARK --set-mark 1
                iptables -t mangle -A QOS_IN -s $i -j RETURN
                iptables -t mangle -A QOS_OUT -d $i -j MARK --set-mark 1
                iptables -t mangle -A QOS_OUT -d $i -j RETURN
        done
        iptables -t mangle -A QOS_IN -j MARK --set-mark 2
        #iptables -t mangle -A QOS_OUT -j MARK --set-mark 2
}
function only_voip(){
        tc qdisc del dev ppp0 root 2>/dev/null
        tc qdisc del dev eth0 root 2>/dev/null
        tc qdisc add dev ppp0 root handle 1: prio 
        tc qdisc add dev ppp0 parent 1:1 handle 10: sfq
        tc qdisc add dev ppp0 parent 1:2 handle 20: tbf rate 50kbit burst 1600
limit 3000
        tc qdisc add dev ppp0 parent 1:3 handle 30: tbf rate 50kbit burst 1600
limit 3000
        tc filter add dev ppp0 protocol ip parent 1: prio 1 handle 1 fw flowid 1:1
#voip
        tc filter add dev ppp0 protocol ip parent 1: prio 2 handle 2 fw flowid 1:2
#altro
        tc qdisc add dev eth0 root handle 1: prio
        tc qdisc add dev eth0 parent 1:1 handle 10: pfifo
        tc qdisc add dev eth0 parent 1:2 handle 20: sfq
        tc qdisc add dev eth0 parent 1:3 handle 30: tbf rate 50kbit burst 1600
limit 3000
        tc filter add dev eth0 protocol ip parent 1: prio 1 handle 4 fw flowid 1:1
#pppoe
        tc filter add dev eth0 protocol ip parent 1: prio 2 handle 1 fw flowid 1:2
#voip
        tc filter add dev eth0 protocol ip parent 1: prio 2 handle 2 fw flowid 1:3
#altro
        iptables -t mangle -A PREROUTING -j QOS_IN
        iptables -t mangle -A POSTROUTING -j QOS_OUT
}
function stop_voip_only(){
        tc qdisc del dev ppp0 root
        tc qdisc del dev eth0 root
        iptables -t mangle -D PREROUTING -j QOS_IN
        iptables -t mangle -D POSTROUTING -j QOS_OUT
}
function check_activity(){
        RULE="host 192.168.1.60 or host 192.168.1.61"
        #for i in $VOIP; do
        #       RULE="$RULE or host $i "
        #done
        tcpdump -c $NUM_PACKETS -p -q $RULE >/dev/null 2>&1
}
VOIP="192.168.1.60 192.168.1.61"
NUM_PACKETS=30
INTER=7
init_firewall
while /bin/true; do
        TIME=`date +%s`
        check_activity
        TIME_N=`date +%s`
        #echo $((TIME_N - TIME))
        if [ $((TIME_N - TIME)) -lt $INTER ]; then
        #       echo "Telefonata..."
                logger "Telefonata in corso... attivo qos"
                only_voip;
                sleep 2m;       
        #       echo "Stop..."


Non riesco a capire una cosa con la tabella di netfilter mangle.
Quando una regola è verificata le altre regole delle tabelle mangle sono
verificate? Mi sembra di si, perché uno deve avere la possibilità di fare
più modifiche ad un pacchetto.
Ma se assegno un MARK ad un pacchetto, con --set-mark, le altre regole che
prevedono un --set-mark, sono applicate?
Supponiamo di voler marcare il traffico proveniente da 2 host con il numero
1 e tutto l'altro traffico con il numero 2.
iptables -t mangle -A POSTROUTING  -d host1 -j MARK --set-mark 1
iptables -t mangle -A POSTROUTING  -d host2 -j MARK --set-mark 1
iptables -t mangle -A POSTROUGING  -j MARK --set-mark 2
I pacchetti destinati a host1 e host2 sono marcati con 1 o con 2?
Un'altra domanda relativa a tc.
Come faccio nella qdisc prio a dire che i pacchetti che non verificano alcun
filtro devono andare nella banda 3?
Grazie.

 individuata una telefonata in corso.
Premessa: non ho letto tutto lo script
Esiste una strada molto più semplice IMHO:
Esempio: ADSL con 256KB di upload
Crei tramite htbinit o qualche script preconfezionato due classi, 1 da
32kbit di banda garantita con picco di 256 ed una da 224kbit con picco
da 256
Poi con iptables marchi tutto il traffico proveniente dagli host non
voip per mandarli nella classe 1(--set-mark 0x1) e tutti gli altri
voip nella classe 2 (--set-mark 0x2)
In caso di traffico voip, la classe 2 avrà molta più banda a
disposizione rispetto alla 1 che risulterà limitata a 32kbit.

Alessandro wrote:


Più o meno è quello che ho fatto. Invece di usare HTB ho usato prio,
assegnando ai voip la banda 1 e all'altro traffico la banda 2, limitata con
un tbf. 
Lo script contiene pure una parte che individua quando c'è una chiamata in
corso e attiva il qos solo in quel caso.
Cmq, se potesse servire in futuro a qualcuno:
le regole della tabella mangle sono percorse tutte, anche se vi è stato un
match (quindi si devono inserire prima regola più generali e poi più
particolari).

 corso e attiva il qos solo in quel caso.
Credo sia proprio questo il problema.
HTB ti permette di gestire una banda minima garantita BMG per le classi 
cosa che con tbf non puoi fare (o per lo meno non puoi fare in modo 
semplice IMHO).
Esempio (BTOT=banda totale utilizzabile dalla classe):
classe 1: BMG 32kbit BTOT: 200kbit
classe 2: BMG 200kbit BTOT: 200kbit
Nel caso non ci fosse traffico sulla classe 2 (assenza di telefonate), 
htb ti 'allarga' la classe 1 fino al suo BTOT andando a 'mangiare' banda 
dalla classe 2 se necessario.
In caso di telefonate, HTB assegna la massima priorità alla classe 2 
ovvero la classe 1 non può più prendersi la sua banda in quanto la BMG è 
di 200kbit
In sostanza, non devi più verificare se ci sono o meno telefonate perchè 
fa tutto lui con 5 righe di codice.
Si fa prima a farlo che a spiegare il funzionamento.

Mandi! Giovanni Di Stasi
  In chel d? si favelave...
GDS> I pacchetti destinati a host1 e host2 sono marcati con 1 o con 2?
Con due, devi per forza duplicare la regola e mettere un -j RETURN per
forzare l'uscita dalla catena.
GDS> Come faccio nella qdisc prio a dire che i pacchetti che non verificano alcun
GDS> filtro devono andare nella banda 3?
Metti alla fine un filtro catch-all, o marcando con iptables o usando
un filtro generico da tc.
-- 
  La CIA ha scoperto chi porta il carbonchio... la befanchia!!!

Alessandro wrote:

Il fatto è che non mi fido delle soluzioni buone "sempre e comunque", quindi
per il momento preferisco usare questo approccio, consistente
nell'individuare la telefonata e fare uno shaping di forza solo per il
tempo della telefonata. Puo' pure essere che l'htb funzioni molto bene, può
darsi che lo provero' (forse il problema potrebbe essere la banda molto
variabile del mio provider wireless), per il momento vedo se questa
soluzione va bene.
Grazie per le buone indicazioni, cmq.

 soluzione va bene.
Cioè non ti fidi di HTB che è stato progettato appositamente per fare 
quello che chiedi?
Tu stai cercando di reinventare la ruota. La ruota esiste già, perchè 
non la usi?
Se poi vuoi fare un 'esercizio di programmazione' è un altro discorso ma 
la soluzione migliore per fare quello che chiedi è usare HTB o simili.

 
Non mi fido che possa fare la stessa cosa che voglio fare io. Poi ritengo
che applicare una politica "forte" solo quando serve, sia molto più
efficace.
Al limite applicherei l'HTB al posto del tbf, però lo stesso usando il
meccanismo di scoperta delle telefonate. In caso contrario dovrei
predisporre una politica di qos valida sempre, e quindi molto più
complicata. Asso posso attuare 2 politiche, una per quando ci sono le
telefonate con il tbf, e una nel caso normale con pfifo_fast (che rispetta
il TOS dei pacchetti).
Hai mai provato a garantire la qualità del servizio a dei telefoni VOIP? Se
si sono curioso di sapere in che modo hai fatto e se la qualità delle
telefonate è sempre buona.

 telefonate è sempre buona.
Forse non ci capiamo :)
Due classi
classe1: BMG 32kbit BMAX 200kbit
classe2: BMG 200kbit BMAX 200kbit
Cosa significa.
significa che il traffico nella classe1, in condizioni normali, cioè 
quando può usare tutta la banda disponibile fino al tetto di BMAX, va a 
quella velocità.
In condizioni normali, quindi, la navigazione web che è dentro la 
classe1 andrà a 200kbit perchè si va a mangiare banda dalla classe2
Poi, tu apri una chiamata voip.
Il traffico voip va dentro la classe2
Classe 2 ha una BMG di 200kbit il che significa che sotto 200kbit NON CI 
PUò ANDARE MAI, quindi si va a mangiare tutta la banda non garantita 
della classe 1.
In questo caso avrai una navigazione web limitata a 32kbit (non può 
mangiare traffico dalla classe2 perchè classe2 ha BMG superiore) e 
chiamate voi con traffico garantito a 200kbit.
Terminata la chiamata, la classe2 si svuota, classe1 può quindi mangiare 
nuovamente banda e ritornare a 200kbit.
Uso costantemente HTB per QoS di traffico VoIP o QoS per traffico dei 
server con tanto di BGM garantita e di picco. Mai avuto problemi.
In sostanza, la banda garantita serve a definire un limite che non può 
essere 'mangiato' dalle altre classi. Tutto ciò che non è garantito, 
viene mangiato per andare a 'coprire' la BGM che ha bisogno del traffico.

 Il fatto è che non mi fido delle soluzioni buone "sempre e comunque"
Beh, allora perchè chiedere l'altrui parere?
Alessandro te l'ha già detto, io ribadisco: HTB funziona molto bene e fa
quel che ti servirebbe in maniera efficiente.

 classe2: BMG 200kbit BMAX 200kbit
Ehm, si potrebbe avere la cosa qui' sopra in "formato" HTB ?
Ho bisogno di implementare un qos nel mio router (ovviamente per il voip) ma
sono mooolto newbie di qos.
Grazie, Nicola.
-- 
chi va pian va san e va lontan

NicoKid ha scritto:

Scarica htb-init
crei 2 file (leggi le istruzioni, sono molto semplici)
con dentro qualcosa tipo
CEIL=200kbit
RATE=32kbit
MARK=1
e l'altro
CEIL=200kbit
RATE=200kbit
MARK=2
CEIL = banda massima utilizzabile in caso di poco traffico (occhio a non 
saturarti la banda al 100% altrimenti non ti funziona più nulla)
RATE = banda minima garantita. La classe andrà a quella banda li in caso 
di traffico e altre classi (dello stesso livello) non possono 'mangiare' 
banda facendo finire una classe sotto il suo livello di 'rate'
(Lo so, non sono capace a spiegare)

Alessandro wrote:

No no, sembra chiaro.


> 
Ma htb sembra un progetto defunto !


 Nicola.
CONFIG_NET_SCH_HTB ti dice nulla?
A me dice che HTB è nel kernel tree ufficiale da un bel pezzo.

whiplash wrote:

Non c'e' traccia di htb nei repositi di ubuntu e nemmeno in fc6.
Forse ha un nome diverso ?


 
Ma per usare uno script in bash di 1 (uno) file bisogna usare i repository?
http://sourceforge.net/projects/htbinit/
Comunque: devi abilitare lo scheduler nel kernel poi se vuoi la pappa 
pronta usi htbinit altrimenti ti crei le classi con 'tc'

 pronta usi htbinit altrimenti ti crei le classi con 'tc'
Ah ecco, ora e' chiaro. tc e' il comando, htbinit e' per semplificarne
l'uso.
Scusate, ma sono newbie di qos.
Gazie, Nicola.


 
Vabbe ma google esiste e basterebbe scrivere "htbinit"