jueves, 30 de abril de 2009

Simulación con tc/netem en Linux

Esta configuración tiene 3 PC's: los extremos suj-uchile52, suj-uchile53 y el bridge suj-uchile51 (con 2 tarjetas de red eth0 y eth1).
Asegurarse que cada extremo esté conectado al bridge con un cable cruzado.
Cada extremo puede utilizarse con Linux o FreeBSD, el bridge sólo lo tengo habilitado con Ubuntu server 8.10 (netem sólo funciona en Linux). Las IP's son:

suj-uchile51: 192.168.4.51
suj-uchile52: 192.168.4.52
suj-uchile53: 192.168.4.53

Comandos tc


Se utiliza tc para todo. tc es el Traffic Control. Todo se debe ejecutar con sudo o como root. Lo otro que se utiliza mucho son los qdisc's (queuing discipline) que son algo así como un objeto de simulación.

Algo que yo hago mucho es:

suj-uchile51:~$ tc qdisc show
qdisc pfifo_fast 0: dev eth1 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

Esto muestra los qdisc's. La salida que aparece no tengo bien claro qué es, pero aparece cuando no hay qdiscs configurados.

Para crear un qdisc con pérdida 0.1% se hace:

suj-uchile51:~$ sudo tc qdisc add dev eth0 root netem drop 0.1%

Lo que importa de este comando es sólo la última parte netem drop 0.1%. El resto del comando dice que se quiere añadir (add) un qdisc en el dispositivo (dev) eth0 como raíz (root) del sistema de clases. Este sistema de clases es complejo y no es necesario comprenderlo por ahora. En Packet Shaping HOWTO aparece una explicación más extensa.

Si ahora se consulta por los qdisc's existentes:
suj-uchile51:~$ tc qdisc show
qdisc pfifo_fast 0: dev eth1 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc netem 8001: dev eth0 root limit 1000 loss 0.1%

aparece el último qdisc creado.

Para simular delay (200ms) se hace:
suj-uchile51:~$ sudo tc qdisc change dev eth0 root netem delay 200ms

Ojo que ahora pusimos change en vez de add, porque cambiamos el qdisc en vez de crearlo.

Para combinar delay y pérdida:
suj-uchile51:~$ sudo tc qdisc change dev eth0 root netem drop 0.1% delay 200ms
suj-uchile51:~$ tc qdisc show
qdisc pfifo_fast 0: dev eth1 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc netem 8001: dev eth0 root limit 1000 delay 200.0ms loss 0.1%

(con netem "drop" es sinónimo de "loss")

Es importante notar que el qdisc asignado a eth0 afectará sólo el tráfico que salga por eth0 y no el entrante. Por ej. con la siguiente configuración:

El tráfico desde suj-uchile52 a suj-uchile53 no será afectado, pero sí el de suj-uchile53 a suj-uchile52 con los parámetros especificados.

Por eso lo que hemos estado haciendo es simular un canal con P% pérdida y D ms de delay asignando P% pérdida a cada interfaz y D/2 en cada una.

Por ej. para simular un canal con 6.7% pérdida y 268ms delay hacemos:

suj-uchile51:~$ sudo tc qdisc change dev eth0 root netem delay 134ms drop 6.7%
suj-uchile51:~$ sudo tc qdisc add dev eth1 root netem delay 134ms drop 6.7%
suj-uchile51:~$ tc qdisc show
qdisc netem 8002: dev eth1 root limit 1000 delay 134.0ms loss 6.7%
qdisc netem 8001: dev eth0 root limit 1000 delay 134.0ms loss 6.7%

Para borrar qdisc hacemos:
suj-uchile51:~$ sudo tc qdisc delete dev eth0 root
suj-uchile51:~$ sudo tc qdisc delete dev eth1 root

En el SVN uchile está el script netem.sh:

#!/bin/sh

user=`whoami`
if [ $user != "root" ]
then
echo "You have to be root, you are $user"
exit 1
fi

if test $# != 2
then
echo "Use ./netem "
exit 1
fi
delay=`echo "scale=1 ; $1 / 2" | bc`
if `tc qdisc add dev eth0 root netem delay ${delay}ms drop $2`
then
tc qdisc add dev eth1 root netem delay ${delay}ms drop $2
else
tc qdisc change dev eth0 root netem delay ${delay}ms drop $2
tc qdisc change dev eth1 root netem delay ${delay}ms drop $2
fi
tc qdisc show

Si queremos simular lo mismo (268ms delay y 6.7% pérdida) con este script:
suj-uchile51:~$ sudo netem 268 6.7
qdisc netem 8004: dev eth1 root limit 1000 delay 134.0ms loss 6.7%
qdisc netem 8003: dev eth0 root limit 1000 delay 134.0ms loss 6.7%

Token Buffer Filter


Ya cachamos que un porcentaje de pérdida constante independiente del bandwitdh enviado no es realista y deja la escoba al tener congestion control. Así que la siguiente etapa es utilizar este algoritmo Token Buffer Filter (tbf), que simula los routers botando paquetes dado un ancho de banda.
Además del ancho de banda, se debe especificar otros 2 parámetros (no sé todavía qué función cumplen en el algoritmo):
  • latency: favorable para el bandwidth, poner 200ms
  • burst: favorable para el bandwidth, poner 256k
El período del sawtooth del cwnd con TCP reno es creciente con ambos parámetros, pero al parecer este aumento es más lineal con el burst y más cuadrático con la latency.

Después de varias pruebas, lo que caché que funciona más parecido a la conexión entre Tokio y Santiago es poner el rate en 9mbit, latency 200ms, burst 256k

Los qdisc's de tbf son distintos a los con netem. Para emular la conexión con Chile se debe además configurar con netem un delay de 268ms.

Los siguientes comandos están basados en Network Simulation with NetEm. Haciendo copy/paste con mis propios parámetros. Además de los qdisc's se agrega un filter al final para que sólo se afecte el tráfico que se quiere:

suj-uchile51:~$ sudo tc qdisc add dev eth0 root handle 1: prio
suj-uchile51:~$ sudo tc qdisc add dev eth0 parent 1:3 handle 30: netem delay 268ms
suj-uchile51:~$ sudo tc qdisc add dev eth0 parent 30:1 tbf rate 9mbit latency 200ms burst 256k
suj-uchile51:~$ sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dst 192.168.4.52/24 flowid 10:3
suj-uchile51:~$ tc qdisc show
qdisc pfifo_fast 0: dev eth1 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc prio 1: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc netem 30: dev eth0 parent 1:3 limit 1000 delay 268.0ms
qdisc tbf 8005: dev eth0 parent 30:1 rate 9000Kbit burst 256Kb lat 200.0ms

Del filter no estoy muy seguro. Con esto el tráfico desde suj-uchile52 hasta suj-uchile53 tendrá 268ms de delay y se botarán paquetes de acuerdo al tbf configurado. Ojo que por completitud también debería configurarse el sentido inverso (la interfaz eth1).

No hay comentarios:

Publicar un comentario