Cisco TRex Traffic Generator: lanzamiento de pruebas de carga de dispositivos de red





Al desarrollar otro enrutador, probamos el rendimiento de la red utilizando una pieza útil de código abierto: el generador de tráfico Cisco TRex. ¿Qué es esta herramienta? ¿Cómo usarlo? ¿Y cómo puede ser útil para los ingenieros de desarrollo? A continuación se encuentran las respuestas a estas preguntas.



1. ¿Qué es Cisco TRex?



Es un generador de tráfico de software de código abierto que se ejecuta en procesadores estándar basados ​​en Intel DPDK y admite modos con estado / sin estado. Comparativamente simple y totalmente escalable.



La documentación en inglés para esta herramienta está disponible en el sitio web .



Trex le permite generar diferentes tipos de tráfico y analizar los datos cuando se reciben. Se admite el trabajo a nivel MAC e IP. Puede establecer el tamaño de los paquetes y su número, controlar la velocidad de transferencia de datos.



Trabajar con el generador está organizado en un entorno Linux.



Una de las diferencias importantes entre el generador de Trex es el uso de la tecnología DPDK, que le permite evitar los cuellos de botella de rendimiento en la pila de red de Linux. DPDK o Data Plane Development Kit es un conjunto de bibliotecas y controladores para el procesamiento rápido de paquetes que le permite excluir la pila de red de Linux del procesamiento de paquetes e interactuar directamente con un dispositivo de red.



DPDK convierte un procesador de uso general en un servidor de reenvío de paquetes. Esta transformación elimina la necesidad de costosos conmutadores y enrutadores. Sin embargo, DPDK impone restricciones en el uso de adaptadores de red específicos, la lista de hardware compatible se indica en el enlace : esta es la plataforma más popular de Inteles decir Se proporciona soporte de hardware que funciona con los controladores de Linux e1000, ixgbe, i40e, ice, fm10k, ipn3ke, ifc, igc.



También es importante comprender que para que un servidor TRex funcione a 10 Gbps, se requiere un procesador multinúcleo, de 4 núcleos y superior, preferiblemente una CPU Intel con soporte para subprocesamiento múltiple (hiperprocesamiento) simultáneo.



2. Cómo obtener y probar TRex



1) Descargue el archivo del servidor trex-tgn.cisco.com: trex-tgn.cisco.com/trex/release/



Desempaquete el archivo en el directorio de inicio del usuario "/ home / user", donde user es el nombre de usuario.



[bash]>wget --no-cache https://trex-tgn.cisco.com/trex/release/latest
[bash]>tar -xzvf latest


2) Configuración de las interfaces para enviar y recibir datos



Realicemos la configuración utilizando la utilidad "dpdk_setup_ports.py", que viene en el archivo con TRex. Puede configurar las interfaces de red que TRex usa a nivel MAC o IP. Para comenzar, debe ejecutar esta utilidad con la tecla de configuración interactiva "sudo ./dpdk_setup_ports.py –i".



El primer paso es abandonar la configuración en el nivel MAC (¿Desea utilizar la configuración basada en MAC? (S / N) n).



El segundo paso es seleccionar un par de interfaces de red con las que trabajaremos, en nuestro caso la tarjeta de red Intel X710 funciona con 4 interfaces de red, usaremos el primer y cuarto socket de la tarjeta de red.







En el tercer paso, el sistema ofrecerá crear automáticamente una configuración cerrada, cuando los datos salgan del puerto 1 y lleguen al puerto 2 (y viceversa), todo en una PC. Tuvimos que abandonar este esquema y configurar el esquema de enrutamiento para 2 PC.



En los pasos cuarto y quinto, aceptamos guardar la configuración en el archivo /etc/trex_cfg.yaml.



Por ejemplo, considere la configuración a nivel de IP para el siguiente esquema de conexión:







El archivo de configuración se encuentra aquí: "/etc/trex_cfg.yaml". A continuación se muestra un archivo de configuración simple para una NIC de 2 puertos con una CPU que admite 8 subprocesos:



### Config file generated by dpdk_setup_ports.py ###
- version: 2
  interfaces: ['01:00.0', '01:00.3']
  port_info:
      - ip: 192.168.253.106
        default_gw: 192.168.253.107
      - ip: 192.168.254.106
        default_gw: 192.168.254.107
 
  platform:
      master_thread_id: 0
      latency_thread_id: 1
      dual_if:
    	- socket: 0
      	threads: [2,3,4,5,6,7]


En configuración:



  • '01: 00.0 ', '01: 00.3': el nombre de las interfaces Eth en el sistema Linux utilizado.
  • ip: 192.168.253.106: la dirección del puerto de la PC Server TRex desde la que se genera el tráfico.
  • default_gw: 192.168.253.107 - dirección de 1 puerto del PC DUT (Dispositivo bajo prueba).
  • ip: 192.168.254.106: la dirección del puerto de PC Server TRex, desde donde se devuelve el tráfico después de pasar por las reglas de QOS.
  • default_gw: 192.168.253.107 - dirección de 2 puertos de PC DUT.


¡Atención! El sistema TRex prohíbe el uso de la misma subred al generar secuencias que utiliza el sistema; para esto, al generar paquetes, se utilizan las subredes 16.0.0.0 y 48.0.0.0.



3) Configuración de interfaces en la máquina remota



Es necesario configurar el reenvío y las rutas para que el sistema (DUT) a través del cual pasaremos el tráfico sepa dónde recibir y dónde enviar paquetes.



Configure las reglas de enrutamiento de flujo en la PC DUT:



sudo echo 1 > /proc/sys/net/ipv4/ip_forward
sudo route add -net 16.0.0.0 netmask 255.0.0.0 gw 192.168.253.106
sudo route add -net 48.0.0.0 netmask 255.0.0.0 gw 192.168.254.106


4) Inicie el servidor TRex en modo astf:



cd v2.XX
sudo ./t-rex-64 -i --astf


Si el servidor TRex se inicia con éxito, veremos información sobre los puertos Ethernet utilizados para las pruebas:



The ports are bound/configured.
port : 0 
------------
link         :  link : Link Up - speed 10000 Mbps - full-duplex
promiscuous  : 0 
port : 1 
------------
link         :  link : Link Up - speed 10000 Mbps - full-duplex
promiscuous  : 0 
number of ports         : 2 
max cores for 2 ports   : 1 
tx queues per port      : 3


5) Inicie la consola TRex



Usando la consola, en una ventana separada, inicie la generación de flujo a partir de ejemplos listos (la carpeta con ejemplos astf está en el archivo de TRex):



cd v2.XX
./trex-console
start -f astf/http_simple.py -m 1
 
start (options):
-a (all ports)
-port 1 2 3 (ports 1 2 3)
-d duration (-d 100 -d 10m -d 1h)
-m stream strength (-m 1 -m 1gb -m 40%)
-f load from disk the streams file


Si el lanzamiento es exitoso, veremos las estadísticas de flujo de tráfico en la consola del servidor TRex:



Global stats enabled
Cpu Utilization : 0.3  %  0.6 Gb/core 
Platform_factor : 1.0  
Total-Tx        :     759.81 Kbps  
Total-Rx        :     759.81 Kbps  
Total-PPS       :      82.81  pps  
Total-CPS       :       2.69  cps  
 
Expected-PPS    :       0.00  pps  
Expected-CPS    :       0.00  cps  
Expected-L7-BPS :       0.00  bps  
 
Active-flows    :        2  Clients :        0   Socket-util : 0.0000 %    
Open-flows      :      641


3. Automatización de desarrollo y pruebas con TRex



En el proceso de desarrollo de un enrutador de red, escribimos muchas pruebas para TRex, por lo que surgió la cuestión de ejecutarlas en modo automático usando python. Cómo lo organizamos:



Iniciamos el servidor TRex en modo stl:



cd v2.XX
sudo ./t-rex-64 -i --stl


Establezca la variable de entorno para python, ya que TRex funciona en conjunto con python.



export PYTHONPATH = / home / !!! user !!! / v2.XX / automation / trex_control_plane / interactive, donde "!!! user !!!" - nombre de usuario y directorio de inicio, v2.XX - versión del software TRex descargada y desempaquetada en esta carpeta.



Comenzamos el generador de tráfico usando python, la lista de la configuración de ejemplo se da a continuación.



python example_test_2bidirectstream.py



Salida esperada:



Transmit: 10000.24576MByte/s Receive: 10000.272384MByte/s
Stream 1 TX: 4487179200 Bit/s RX: 4487179200 Bit/s
Stream 2 TX: 2492873600 Bit/s RX: 2492873600 Bit/s
Stream 3 TX: 1994294400 Bit/s RX: 1994294400 Bit/s
Stream 4 TX: 997147200 Bit/s RX: 997147200 Bit/s


Veamos este ejemplo:



c = STLClient (server = '127.0.0.1')



Cree una conexión al servidor TRex, en este caso, la conexión se crea en la misma máquina que el servidor.



  • "Base_pkt_dir_a, base_pkt_dir_b, base_pkt_dir_c, base_pkt_dir_d" - plantillas de paquetes, que contienen direcciones de origen y destino, puertos de origen y destino. En este ejemplo, se crean 4 flujos, 2 en una dirección y 2 en la dirección opuesta.
  • "S1, s2, s3, s4": solicite los parámetros del flujo generado de la clase STLStream, como ID de flujo y bitrate, en nuestro caso ID1 = 4.5 Gbps, ID2 = 2.5 Gbps, ID3 = 2 Gbps, ID4 = 1 Gbps.


Listado del archivo de configuración de flujo example_test_2bidirectstream.py



# get TRex APIs
from trex_stl_lib.api import *
 
c = STLClient(server = '127.0.0.1')
c.connect()
 
try:
    # create a base packet with scapy
    base_pkt_dir_a = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=5001,sport=50001)
    base_pkt_dir_b = Ether()/IP(src="48.0.0.1",dst="16.0.0.1")/UDP(dport=50001,sport=5001)
 
    base_pkt_dir_c = Ether()/IP(src="16.0.0.2",dst="48.0.0.2")/UDP(dport=5002,sport=50002)
    base_pkt_dir_d = Ether()/IP(src="48.0.0.2",dst="16.0.0.2")/UDP(dport=50002,sport=5002)
 
    # pps : float
    # Packets per second
    #
    # bps_L1 : float
    # Bits per second L1 (with IPG)
    #
    # bps_L2 : float
    # Bits per second L2 (Ethernet-FCS)
    packet_size = 1400
 
    def pad(base_pkt):
        pad = (packet_size - len(base_pkt)) * 'x'
        return pad
 
    s1 = STLStream(packet=STLPktBuilder(base_pkt_dir_a/pad(base_pkt_dir_a)), mode=STLTXCont(bps_L2=4500000000), flow_stats=STLFlowStats(pg_id=1))
    s2 = STLStream(packet=STLPktBuilder(base_pkt_dir_b/pad(base_pkt_dir_b)), mode=STLTXCont(bps_L2=2500000000), flow_stats=STLFlowStats(pg_id=2))
    s3 = STLStream(packet=STLPktBuilder(base_pkt_dir_c/pad(base_pkt_dir_c)), mode=STLTXCont(bps_L2=2000000000), flow_stats=STLFlowStats(pg_id=3))
    s4 = STLStream(packet=STLPktBuilder(base_pkt_dir_d/pad(base_pkt_dir_d)), mode=STLTXCont(bps_L2=1000000000), flow_stats=STLFlowStats(pg_id=4))
 
    my_ports = [0, 1]
 
    c.reset(ports = [my_ports[0], my_ports[1]])
 
    # add the streams
    c.add_streams(s1, ports = my_ports[0])
    c.add_streams(s2, ports = my_ports[1])
    c.add_streams(s3, ports = my_ports[0])
    c.add_streams(s4, ports = my_ports[1])
 
    # start traffic with limit of 10 seconds (otherwise it will continue forever)
    # bi direction
    testduration = 10
    c.start(ports=[my_ports[0], my_ports[1]], duration=testduration)
    # hold until traffic ends
    c.wait_on_traffic()
 
    # check out the stats
    stats = c.get_stats()
 
    # get global stats
    totalstats = stats['global']
    totaltx = round(totalstats.get('tx_bps'))
    totalrx = round(totalstats.get('rx_bps'))
    print('Transmit: {}MByte/s Receive: {}MByte/s'.format((totaltx / 1000000), (totalrx / 1000000)))
    c.clear_stats(ports = [my_ports[0], my_ports[1]])
 
    # get flow stats
    totalstats = stats['flow_stats']
    stream1 = totalstats[1]
 
    stream2 = totalstats[2]
    stream3 = totalstats[3]
    stream4 = totalstats[4]
    totaltx_1 = stream1.get('tx_pkts')
    totalrx_1 = stream1.get('rx_pkts')
    print('Stream 1 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_1['total'] / testduration * packet_size * 8),
                                                               (totalrx_1['total'] / testduration * packet_size * 8)))
    totaltx_2 = stream2.get('tx_pkts')
    totalrx_2 = stream2.get('rx_pkts')
    print('Stream 2 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_2['total'] / testduration * packet_size * 8),
                                                               (totalrx_2['total'] / testduration * packet_size * 8)))
    totaltx_3 = stream3.get('tx_pkts')
    totalrx_3 = stream3.get('rx_pkts')
    print('Stream 3 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_3['total'] / testduration * packet_size * 8),
                                                               (totalrx_3['total'] / testduration * packet_size * 8)))
    totaltx_4 = stream4.get('tx_pkts')
    totalrx_4 = stream4.get('rx_pkts')
    print('Stream 4 TX: {} Bit/s RX: {} Bit/s'.format((totaltx_4['total'] / testduration * packet_size * 8),
                                                               (totalrx_4['total'] / testduration * packet_size * 8)))
except STLError as e:
    print(e)
 
finally:
    c.disconnect()


Conclusión



Al preparar esta guía para Habr, lanzamos y probamos el funcionamiento del sistema DUT con 4 subprocesos, recopilamos información sobre subprocesos y estadísticas globales.



La operación descrita anteriormente se inicia con Python, lo que significa que con TRex, puede automatizar las pruebas y la depuración de dispositivos de red y productos de software, en un bucle o cuando se ejecutan pruebas secuenciales en Python.



Entonces, ¿por qué el TRex de Cisco es mejor o peor que otros generadores de tráfico similares? Por ejemplo, el popular programa cliente-servidor iperf? En el escenario de uso de TRex, vemos una descripción de cómo configurar y trabajar con secuencias. Tanto las herramientas de prueba como de depuración son buenas: iperf: para una prueba rápida de la funcionalidad sobre la marcha, y TRex hace un excelente trabajo de automatización de pruebas y desarrollo de dispositivos y sistemas de red complejos, donde la capacidad de configurar flujos de subprocesos múltiples es importante para configurar cada flujo para una tarea específica y analizar los resultados de salida ...



TRex le permite crear plantillas para casi cualquier tipo de tráfico y amplificarlas para generar ataques DDoS a gran escala, incluidos los flujos TCP-SYN, UDP e ICMP. La capacidad de generar flujos de tráfico masivos le permite simular ataques de múltiples clientes en múltiples servidores de destino.



Entonces, si aún no ha probado esta herramienta, puede tomar una nota. Y si lo intentó, comparta sus ejemplos y comentarios en los comentarios. Es interesante saber en qué TRex está siendo pensado y utilizado por otros ingenieros.



All Articles