Usando tan sólo software libre y hardware común conseguiremos crear el equipamiento necesario para realizar pruebas de rendimiento sobre dispositivos (D.U.T.) en redes de alta velocidad (a más de 1Gbps).
La motivación principal del artículo tiene su origen en la necesidad de crear un entorno específico para pruebas de rendimiento que sirviera de alternativa de bajo coste, pero suficiente calidad, frente a otras opciones comerciales existente en el mercado pero excesivamente costosas. Dicho entorno se usará para evaluar los productos de software libre que se están desarrollando en mi empresa y que necesariamente deberán cumplir unos requisitos mínimos, exigidos fundamentalmente por los clientes, ya que se tratan de productos de seguridad orientados a redes de gran capacidad y entornos críticos (telco, banca, etc).
Uno de estos proyectos, redBorder IPS, es una solución completa distribuida de gestión y monitorización de amenazas en las redes corporativas basada en snort, aunque con modificaciones importantes que optimizan el uso del hardware y aumenta el rendimiento si se utilizan los dispositivos de red adecuados. Esta solución es la principal responsable de la creación del entorno de pruebas.
Estado del arte
Las redes actuales crecen a un ritmo tal que aumentan en un grado de magnitud cada década o incluso antes, siguiendo una razón aritmética visto en una escala semi-logarítmica.
| Evolución anual de la capacidad de las redes Ethernet (escala semi-logarítmica) y estimación en el año 2020, basado en el cálculo de la curva de regresión exponencial entre 1980 y 2010. |
Aunque las redes ethernet a 1Gbps (1G) sean las más populares, es habitual encontrar redes troncales de mayor capacidad. Siguiendo el modelo de jerarquía cisco (Cisco Hierarchical Network Model , CHM) en redes conmutadas, a nivel de acceso pueden aparecer los populares puertos 1G (tecnología desarrollada a finales de los 90) con enlaces 1G en agregación, (por ejemplo con LACP) o 10G hacia redes de distribución y éstos a su vez conectados a la red 'core' con enlaces de máxima velocidad. La tecnología ethernet a 100G se creó recientemente y marca la tendencia a seguir ya descrita. Se estima que para finales de 2020 ya se haya desarrollado la tecnología para redes a 1000GE, si no ocurre antes.
El hardware común no integra aún interfaces de red a 10G, debido al alto coste de estos dispositivos y a la necesidad de electrónica externa de apoyo que puede aumentar dicho coste aún más, por lo que nos centraremos en tests sobre redes a 1G, aunque serán más de un puerto a la vez, consiguiendo tráficos agregados del orden de 4G. No obstante todo el entorno es perfectamente adaptable a 10G.
El escenario
Antes de abordar directamente el generador de tráfico, razón fundamental del artículo, se debe tener primero una visión global del escenario que es necesario montar. Para ello es interesante, aunque no obligatorio, mencionar el RFC-2544 como referencia excelente para este tipo de tests. En dicho 'draft' se describen de manera concreta y sencilla cómo deben montarse el equipo generador (Tester) y el DUT (Device Under Test), de manera que las pruebas puedan ser equivalentes y, por tanto sus resultados comparables entre diferentes fabricantes.Por un lado tenemos un equipo o equipos denominados tester y por otro el DUT (Device Under Test). Aunque se puede montar el escenario con dos equipos tester, es importante que se monte sólo con uno, mismo emisor y receptor, de manera que la contabilidad de paquetes sea exacta y no haya desviaciones en medidas tan sensible a errores de sincronización de tiempo como latencias y jitters.
En nuestro caso particular, contamos con dos equipos idénticos Intel Xeon E3 quad-core con HT (8 cores virtuales) a 3,3 GHz con 2 interfaces de red a 1Gb dedicados exclusivamente a gestión (formando un bonding) vía ssh, y 8 interfaces de red a 1Gb, Intel 82580 correspondiente al módulo igb, formando lo que llamamos 4 segmentos (1 segmento lo forman 2 interfaces de red debido a que el DUT necesita de las 2 interfaces para interponerse en medio del tráfico). El gráfico anterior hace referencia a un DUT con un sólo segmento, mientras que en nuestro caso particular se hará sobre 4 segmentos a la vez, para analizar tráfico unidireccional y bidireccional.
Para las pruebas sobre 10G sólo usaríamos un segmento. En nuestro caso particular se ha usado un chipset Intel 82599EB (10G), correspondiente al módulo ixgbe.
En las pruebas estandarizadas se propone la generación de paquetes de tamaño 64, 128, 256, 512, 1024, 1280, 1518 para los tests. Asímismo se proponen los siguiente benchmarks a medir:
- Throughput
- Latency
- Frame loss rate
- Back-to-back frames
- System recovery
- Reset
Los scripts creados para las pruebas se han diseñado para medir de forma bastante exacta los 3 primeros benchmarks propuestos en el draft. El resto se podrían tambien realizar mediante una extensión del código ya escrito.
Asímismo, al tratarse el DUT de un dispositivo IDS/IPS, para cada tamaño de paquete también se establecen los modos de operación:
- Bypass (sin DUT, para generar valores de referencia)
- IDS Forwarding sin reglas
- IDS Forwarding con reglas (varias cantidades, hasta las 12k)
- IPS sin reglas
- IPS con reglas (varias cantidades, hasta las 12k)
Evidentemente, el lector no necesita generar tal cantidad de pruebas. Le bastará con adaptar el escenario y los scripts a su necesidad particular, que pudiera ser bien distinta.
El kernel como generador
Para generar paquetes a la suficiente velocidad (wirespeed con paquetes pequeños), es necesario bajar del nivel de aplicación hasta el nivel del kernel, pero lo más cerca posible de los drivers de la tarjeta de red. En 2001 y para poder evaluar el nuevo API de red (NAPI), Robert Olsson, Alexei Kutnetsov y otros crearon ‘pktgen’, el generador de paquetes a alta velocidad del kernel de linux, en la universidad de Uppsala (Suecia). Más tarde, en 2010 Daniel Turull, ingeniero por la UPC de Barcelona (España), realizó una tesis doctoral en la universidad de Estocolmo (Suecia) en la que desarrolló una extensión en pktgen que permite contabilizar la recepción de los paquetes generados en la misma máquina creando estadísticas de todo tipo.
Para usar pktgen en el sistema tester, deberá compilar el soporte en el kernel. Además, para poder crear las estadísticas de recepción, deberá aplicar el conjunto de parches desarrollados por Daniel Turull. Desde las fuentes del kernel, si usa ‘menuconfig’ como sistema de configuración, lo encontrará en ‘Networking support’->’Networking options’->’Network testing’.
Por supuesto, puede compilarlo como módulo:
Para el usuario que desee saltarse estos pasos, es posible utilizar la distribución Bifrost (arcoiris o puente hacia varhalla en la mitología escandinava), como es nuestro caso, que ya contiene todos los últimos parches de pktgen aplicados en la última versión del kernel Linux v3. Puede obtener la distribución e información sobre la misma en su página web:
http://bifrost.slu.se/
Una vez descargada la distribución, para su instalación en un dispositivo de almacenamiento flash por USB se requiere de 3 archivos básicos: el script de instalación ‘make_bifrost’, la imagen del bootstrap (boot_image.gz) y la imagen comprimida (tarball) que contiene el firmware (el raíz de la minidistribución en sí, bifrost-rc-7.0-2.tar.gz en nuestro caso). Existen paquetes opcionales de Bifrost que pueden ser incluidos en la instalación pero que no son necesarios para el funcionamiento como tester.
Para instalar la minidistribución sin soporte de swap (no necesario en el tester) en un dispositivo USB mapeado como /dev/sdb, se ejecutaría lo siguiente desde un equipo de escritorio en Linux:
# sudo ./make_bifrost sdb 0 boot_image.gz bifrost-rc-7.0-2.tar.gz
Una vez iniciado el sistema bifrost, mediante un sencillo menú podemos configurar la red de gestión en la interfaz que necesitemos. Si deseamos hacerlo manualmente, suponiendo que la interfaz de gestión es la eth0, ejecutaríamos lo siguiente:
# ip link set up dev eth0
# ip addr add 192.168.1.100/24 dev eth0
# ip route add default via 192.168.1.1
Pero, ¿cómo funciona pktgen?.
El primer paso para empezar a trabajar con pktgen es cargar el módulo:
# modprobe pktgen
La forma de comunicarse con el módulo y obtener datos es a través del sistema de ficheros /proc:
# ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 kpktgend_2 kpktgend_3 kpktgend_4 kpktgend_5 kpktgend_6 kpktgend_7 pgctrl
# cat /proc/net/pktgen/pgctrl
Packet Generator for packet performance testing. Version: 2.75
El módulo crea un hilo en el kernel por cada procesador que tenga el sistema, 8 en nuestro caso (kpktgend_0 al kpktgend_7), de manera que se puedan programar diferentes tareas a cada CPU independientes unas de otras.
Para que el procesamiento de paquetes sea lo más eficiente posible y evitemos el paso de información a través de la memoria general del sistema, es necesario configurar correctamente la afinidad IRQ de manera que las interrupciones que se generen en una interfaz sean atendidas por la CPU correcta. Si no fuera así, una CPU virtual (también llamada hilo) atendería la interrupción y recepcionaría en su caché la información, pero si el proceso que va a usarla se encuentra corriendo en otro hilo, hay que realizar un volcado y posterior lectura a través de la memoria general, muchísimo más lenta que la caché del core, provocando una caída apreciable del rendimiento. Esto no es tan dramático si los cores involucrados se encuentran dentro del mismo socket (como por ejemplo es nuestro caso, 1 socket quad-core: 4 cores, 8 hilos, compartiendo memoria caché externa entre ellos e interna entre los hilos del mismo core).
Para forzar el comportamiento deseado, independientemente del tipo de cores involucrados, se configurará la afinidad de cada una de las colas de entrada y salida de las interfaces del sistema. Revisando el estado de las colas y sus IRQ correspondientes:
# cat /proc/interrupts
CPU0 ... CPU7
0: 161 ... 0 IO-APIC-edge timer
1: 8 ... 0 IO-APIC-edge i8042
4: 9 ... 0 IO-APIC-edge serial
...
32: 25434 ... 0 PCI-MSI-edge ahci
33: 5 ... 0 PCI-MSI-edge eth2
34: 152767 ... 0 PCI-MSI-edge eth2-TxRx-0
35: 410 ... 0 PCI-MSI-edge eth2-TxRx-1
36: 410 ... 0 PCI-MSI-edge eth2-TxRx-2
37: 410 ... 0 PCI-MSI-edge eth2-TxRx-3
38: 410 ... 0 PCI-MSI-edge eth2-TxRx-4
39: 410 ... 0 PCI-MSI-edge eth2-TxRx-5
40: 410 ... 0 PCI-MSI-edge eth2-TxRx-6
41: 410 ... 146041 PCI-MSI-edge eth2-TxRx-7
...
100: 5 ... 0 PCI-MSI-edge eth9
101: 152740 ... 0 PCI-MSI-edge eth9-TxRx-0
102: 410 ... 0 PCI-MSI-edge eth9-TxRx-1
103: 410 ... 0 PCI-MSI-edge eth9-TxRx-2
104: 410 ... 0 PCI-MSI-edge eth9-TxRx-3
105: 410 ... 0 PCI-MSI-edge eth9-TxRx-4
106: 410 ... 0 PCI-MSI-edge eth9-TxRx-5
107: 410 ... 0 PCI-MSI-edge eth9-TxRx-6
108: 410 ... 0 PCI-MSI-edge eth9-TxRx-7
...
Podemos ver que el driver de red crea tantas colas TxRx por interfaz como cores tiene el sistema, aplicándole además la afinidad por defecto que suele ser ‘ff’, es decir, todos los cores.
La afinidad se configura aplicando un valor numérico que hace de máscara sobre una entrada específica a la IRQ en el sistema de ficheros /proc.
Ejemplos de máscara a aplicar:
=============================
Todas los cores:
CPU# 0 1 2 3 4 5 6 7
1 1 1 1 1 1 1 1 = 0xff
-----------------------------
Cores del 4 al 7:
CPU# 0 1 2 3 4 5 6 7
0 0 0 0 1 1 1 1 = 0x0f
-----------------------------
Sólo el core 2:
CPU# 0 1 2 3 4 5 6 7
0 0 1 0 0 0 0 0 = 0x20
Por ejemplo, para que la IRQ 34 sea atendida por todas las CPUs del sistema (se hace un reparto balanceado por cada CPU cada vez que se genera una interrupción para el dispositivo asignado a la 17), se ejecutaría:
# echo “ff” > /proc/irq/34/smp_affinity
Si lo que pretendemos, por ejemplo, es que la cola 0 de la interfaz eth9 (eth9-TxRx-0) sea gestionada por el core 0 (CPU0), y así sucesivamente, deberíamos entonces ejecutar las siguientes acciones:
# echo “80” > /proc/irq/101/smp_affinity
# echo “40” > /proc/irq/102/smp_affinity
# echo “20” > /proc/irq/103/smp_affinity
# echo “10” > /proc/irq/104/smp_affinity
# echo “08” > /proc/irq/105/smp_affinity
# echo “04” > /proc/irq/106/smp_affinity
# echo “02” > /proc/irq/107/smp_affinity
# echo “01” > /proc/irq/108/smp_affinity
Evidentemente esta actuación es perfectamente programable, de manera que se configure de manera automática la afinidad IRQ de todas la colas de las interfaces involucradas en la generación de paquetes mediante un script, como así se hace en el script del artículo.
Como hemos dicho, la forma de comunicarse con pktgen es a través del sistema de ficheros /proc. Existen una serie de comandos que sirven para controlar o configurar el comportamiento del generador:
| pgcontrol commands | /proc/net/pktgen/pgctrl |
| start | Starts sending on all threads |
| stop | Stop sending on all threads |
| PgRXcontrol commands (NEW) | /proc/net/pktgen/pgrx |
| rx [device] (NEW) | Enable the receiver part for an specific device. If it is wrong, all the devices are used. |
| rx_reset (NEW) | Reset the counters |
| rx_disable (NEW) | Disable the receiver |
| display [human|script] (NEW) | Display mode |
| statistics [counter|basic|time] (NEW) | Statistics mode |
| Threads commands | /proc/net/pktgen/kpktgend_# |
| add_device | Add a device to thread i.e eth0 |
| rem_device_all | Removes all devices from this thread |
| max_before_softirq | do_softirq() after sending a number of packets |
| Device commands | /proc/net/pktgen/ethX@# |
| debug | Debug mode |
| clone_skb | Number of identical copies of the same packet 0 means alloc for each skb. For DoS etc we must alloc new skb’s. |
| clear_counters | normally handled automatically |
| pkt_size | Link packet size minus CRC (4) |
| min_pkt_size | Range pkt_size setting If < max_pkt_size, then cycle through the port range |
| max_pkt_size | |
| frags | Number of fragments for a packet |
| count | Number of packets to send. Use zero for continious sending |
| rate (NEW) | Rate in Mbps |
| ratep (NEW) | Rate in pps |
| config [0|1] (NEW) | Enables or disables the configuration packet, which reset the statistics and allows to calculate the losses |
| delay | Artificial gap inserted between packets in nanoseconds |
| dst | IP destination address i.e 10.0.0.1 |
| dst_min | Same as dst If < dst_max, then cycle through the port range. |
| dst_max | Maximum destination IP. i.e 10.0.0..1 |
| src_min | Minimum (or only) source IP. i.e. 10.0.0.254 If < src_max, then cycle through the port range. |
| src_max | Maximum source IP. |
| dst6 | IPV6 destination address i.e fec0::1 |
| src6 | IPV6 source address i.e fec0::2 |
| dstmac | MAC destination adress 00:00:00:00:00:00 |
| srcmac | MAC source adress. If omitted it’s automatically taken from source device |
| src_mac_count | Number of MACs we’ll range through. Minimum’ MAC is what you set with srcmac. |
| dst_mac_count | Number of MACs we’ll range through. Minimum’ MAC is what you set with dstmac. |
| queue_map_min | Sets the min value of tx queue interval |
| queue_map_max | Sets the max value of tx queue interval, for multiqueue devices |
| Flags | |
| IPSRC_RND, IPDST_RND TXSIZE_RND, UDPSRC_RND MPLS_RND, VID_RND, SVID_RND QUEUE_MAP_RND QUEUE_MAP_CPU |
IP Source/Dest is random (between min/max), etc ... |
En líneas generales, el modo de configurar pktgen para los test siempre tiene la misma estructura:
- Configurar la afinidad IRQ
- Limpiar posibles estadísticas anteriores
- Configurar las estadísticas de recepción
- Eliminar posibles configuraciones de transmisión de dispositivos anteriores
- Añadir dispositivos de transmisión a los hilos pertinentes de pktgen
- Configurar cada uno de esos dispositivos añadidos para transmitir determinado número de paquetes con características deseadas (tamaño, rate, rango de IP origen y/o destino, direcciones MAC, etc).
- Lanzar el test
Se pueden encontrar muchos ejemplos en la documentación oficial del proyecto:
Lo siguiente es uno de los ejemplos típicos de pktgen, ideal para entender su funcionamiento. Se aprecia una función llamada pgset que simplemente escribe en el archivo contenido en la variable global $PGDEV lo que se le pase como primer argumento. Luego viene la parte de inicialización del hilo kpktgend_0 donde además se le asocia la interfaz eth1. A continuación viene la configuración propia de la interfaz eth1 y finalmente el comando de lanzamiento del test.
#! /bin/sh
# modprobe pktgen
function pgset() {
local result
echo $1 > $PGDEV
result=`cat $PGDEV | fgrep "Result: OK:"`
if [ "$result" = "" ]; then
cat $PGDEV | fgrep Result:
fi
}
function pg() {
echo inject > $PGDEV
cat $PGDEV
}
# Config Start Here -----------------------------------------------------------
# thread config
# Each CPU has own thread. One CPU example. We add eth1.
PGDEV=/proc/net/pktgen/kpktgend_0
echo "Removing all devices"
pgset "rem_device_all"
echo "Adding eth1"
pgset "add_device eth1"
echo "Setting max_before_softirq 10000"
pgset "max_before_softirq 10000"
# device config
# delay 0 means maximum speed.
CLONE_SKB="clone_skb 1000000"
# NIC adds 4 bytes CRC
PKT_SIZE="pkt_size 60"
# COUNT 0 means forever
#COUNT="count 0"
COUNT="count 10000000"
DELAY="delay 0"
PGDEV=/proc/net/pktgen/eth1
echo "Configuring $PGDEV"
pgset "$COUNT"
pgset "$CLONE_SKB"
pgset "$PKT_SIZE"
pgset "$DELAY"
pgset "dst 10.10.11.2"
pgset "dst_mac 00:04:23:08:91:dc"
# Time to run
PGDEV=/proc/net/pktgen/pgctrl
echo "Running... ctrl^C to stop"
pgset "start"
echo "Done"
# Result can be vieved in /proc/net/pktgen/eth1
El script y el tester
Con el escenario ya planteado y preparado, y sabiendo como funciona la generación de paquetes en el kernel (pktgen), podemos abordar definitivamente el script que genera el test de rendimiento para paquetes UDP de diversos tamaños a la máxima velocidad posible para DUT.El software se puede descargar de:
http://www.eneotecnologia.com/dist/pktgen.tgz
El paquete contiene dos scripts, find_break_point.sh y battery.sh. El primero es el responsable del trabajo duro, y el segundo permite automatizar los diferentes test mediante la reconfiguración del DUT usando comandos ssh y ejecutando el primer script con los parámetros adecuados al test. Si se ha usado Bifrost como distribución para el tester, deberá copiar preferiblemente en el directorio /tmp (el resto seguramente sea de sólo lectura) el script find_break_point.sh y, si fuera necesario, el battery.sh.
# ./find_break_point.sh
usage: find_break_point [ -r rate ] [ -w Mbps ] [ -s size ] [ -h ] [ -v ] -d ethX:ethY,... -b
-r rate Initial value for rate (pps)
-w Mbps If -r is not present it will take this value for pps calculate. (Mpbs per segment)
-s size Size of the packets (in bytes)
-d ethX:ethY,... List of pairs (ethOUT:ethIN,...) of interfaces for send and receive packets
-b Bidireccional test
-1 One shot
-v Verbose mode
-h This help
¿Cómo funciona el script find_break_point.sh?, básicamente se le indican unos valores iniciales de tamaño de paquete y velocidad de generación de paquetes (de arranque) y los segmentos de red (pares de interfaces) sobre los que va a actuar, así como si el test va a ser unidireccional o bidireccional. Una vez establecidos estos valores, se generan los paquetes de ese tamaño a la velocidad establecida durante 5 segundos, y se aplica un tiempo de espera de algunos segundos extras para que se estabilicen los contadores y buffers. y para finalmente leer las estadísticas y realizar algunos cálculos cuyos resultados se presentan en dos colores:
- Verde: Los valores obtenidos están dentro de los umbrales adecuados.
- Rojo: Algún valor ha superado su umbral marcado.
Si el resultado es verde, el script no acaba sino que aumenta en un determinado porcentaje la velocidad de generación de paquetes manteniendo el resto de parámetros. Así continua hasta que se alcanza alguno de lo límites marcados (pérdida de un 0.5% de paquetes al atravesar el DUT, latencias superiores a 200ms, etc). En este último caso, el test se repite para verificar que es reproducible la situación (pudiera deberse a algún evento puntual como una subida momentánea de carga por ejemplo), y si se volviese a repetir un resultado rojo entonces se aplica el algoritmo de la media para recalcular la nueva velocidad de generación de paquetes (pps). Se continúa así hasta que se alcanza un resultado rojo del cual ya no se sale, dándose por válidos los últimos resultados conformes (verdes).
Analizando más detenidamente el script, se puede ver que está dividido en dos bloques principales: un primer conjunto de funciones definidas y un segundo bloque formado por el cuerpo principal del script.
En el primer bloque, la mayoría son pequeñas funciones de apoyo, pero la principal es la denominada ‘multi_tx()’, responsable de lanzar la generación de paquetes mediante la configuración del pktgen y ejecución del comando ‘start’ en pgctrl.
#!/bin/bash
## vim:ts=4:sw=4:expandtab:ai:nowrap:formatoptions=croqln:
PRINTED=0
trap 'rmmod pktgen &>/dev/null; last_result; exit' 0 2 5 15 sigtstp
function eexit() {
rmmod pktgen &>/dev/null
exit $1
}
function last_result() {
if [ $PRINTED -eq 0 ]; then
PRINTED=1
f_set_color orange
echo "---------------------------"
echo "FINAL RESULT: ${last_krxrate}"
echo "---------------------------"
f_set_color norm
fi
}
function log() {
[ "x$DEBUG" != "x" ] && logger -t test_search_max_pps "$1"
}
function pgset() {
echo $1 > $PGDEV
}
f_set_color() {
green="echo -en \\033[32m"
...
norm="echo -en \\033[1;0m"
eval \$$1
}
function multi_tx() {
...
}
A la función multi_tx() se le pasan 4 parámetros: la velocidad o rate total (luego se calcula la que debe tener cada CPU), el tamaño de paquete, la lista de segmentos o pares de interfaces (en formato eth2:eth3,eth4:eth5,... por ejemplo, donde en tráfico unidireccional la primera interfaz es la de transmisión y la segunda la de recepción y en bidireccional ambas son de transmisión y recepción), y por último un flag que indica si el test va a ser uni o bidireccional.
La función asimismo desactiva varios parámetros ethernet de las interfaces que pueden afectar a pktgen mediante el API ethtool, configura la afinidad IRQ de las colas, inicializa estadísticas y los hilos de pktgen, asigna las interfaces a todos los cores disponibles (si sólo se usa un segmento tendríamos en nuestro caso 8 cores generando paquetes en un segmento, de manera que garanticemos el máximo rendimiento), configura los parámetros de generación de cada interfaz asociada (total de paquetes a enviar, rate, tamaño de paquete, IP/MAC destino real y rango de de direcciones IP de destino (spoofed) en los paquetes lanzados.
El segundo bloque de código se encarga de parsear los argumentos pasados por línea de comandos, inicializar variables, levantar interfaces y comenzar el bucle principal mediante el cual, usando el algoritmo de la media, se busca el punto de ruptura de los valores conformes del DUT.
--- snip ---
flag_bidir=0
flag_one_shot=0
last_krxrate=0
while getopts “r:s:d:bvh1w:” OPTION; do
case $OPTION in
--- snip ---
esac
done
--- snip ---
while : ; do
fails=0
for try in 1 2; do
flag_pc_dtxrate=0
if [ $counter -gt 70 ]; then
f_set_color red
echo "Max number of TOTAL iterations has reached"
f_set_color norm
exit 1
fi
counter=$(($counter + 1 ))
echo "Making test at $trate pps and $psize bytes"
for ret in $(multi_tx ${trate_partial} $psize ${eth_list} ${flag_bidir}); do
key=$(echo $ret | sed 's/\(.*\):.*/\1/')
value=$(echo $ret | sed 's/.*:\(.*\)/\1/')
v_ret[$key]=$value
done
--- snip ---
done
--- snip ---
Se observa en el fragmento de código anterior cómo se llama a la función muti_tx() desde el bucle principal pasándole los cuatro parámetros necesarios y cuyo valor de retorno se introduce en una matriz hash denominada v_ret cuyas claves son:
- txrate: Rate de transmisión (pps).
- rxrate: Rate de receción (pps).
- lat_avg_max: Valor máximo de las latencias medias calculadas.
- lat_max: Valor máximo de las latencias calculadas.
- total_tx: Total de paquetes transmitidos.
- total_rx: Total de paquete detectado en la recepción.
- flag_pc_lost: Booleano que determina si ha habido pérdida de paquetes.
- flag_lat_max: Booleano que determina si se han superado los 200ms de latencia máxima establecida como umbral.
- bwtx: Rate de transmisión (Mbps).
- bwrx: Rate de recepción (Mbps).
Por supuesto, es posible calcular más valores, tan sólo hace falta ampliar la función muti_tx() y encapsular nuevos pares clave/valor en su salida.
Como se puede apreciar, los scripts combinados pueden ser una herramienta muy potente para generar una amplia variedad de pruebas de rendimiento más o menos automatizadas. En el caso de nuestro producto IPS, la combinación de diferentes tamaños de paquetes y configuraciones diversas junto con el número de pruebas a realizar y el tiempo necesario para cada una, hace que el tiempo total dedicado a las pruebas sea realmente largo, siendo necesario que la intervención manual sea mínima o casi nula. De esta tarea se encarga precisamente el script battery.sh.
Conclusiones
El mundo del software libre se ha ido construyendo a golpe de necesidad. Como consecuencia de la inclusión del NAPI en el sistema de red del kernel, se creó pktgen para poder evaluar las nuevas bondades. Al aparecer nuevas tecnologías ethernet más rápidas y nuevas tecnologías de red sensibles a perturbaciones (como la voz sobre IP o las video conferencias, muy sensibles a los jitters), surgió la necesidad de crear estadísticas que midieran estos fenómenos, motivo de la aparición del proyecto de Daniel Turull. En nuestro caso, surge la necesidad de crear un tester de bajo presupuesto pero suficiente potencia para evaluar el rendimiento en escenarios de mucha carga, creándose los scripts mencionados que se apoyan en las tecnologías descritas, que además están en continua evolución ya que para próximas versiones del IPS (nuestro DUT) se espera usar las incipientes tecnología basadas en DNA y PF_RING.
Referencias
1- Tesis doctoral de Daniel Turull sobre las mejoras en pktgen:
2- White Paper sobre pktgen (versiones previas)
3- Evolución del estándar IEEE 802.3
4- RFC 2544: Benchmarking Methodology for Network Interconnect Devices
5- RFC 1242: Benchmarking Terminology for Network Interconnection Devices
6- SMP IRQ affinity
7- Proyecto Bifrost