Belastungstests von Netzwerken mit dem Datenverkehr-Generator Cisco TRex
Bei der Entwicklung eines aktuellen Routers haben wir die Netzwerkleistung mit einem nützlichen Open-Source-Tool getestet - dem Netzwerkdatenverkehr-Generator Cisco TRex. Was für ein Werkzeug ist das? Wie wird es verwendet? Und was kann es für Entwicklungsingenieure leisten? Nachfolgend finden Sie Antworten auf diese Fragen.
1. Was ist Cisco TRex?
Es handelt sich um einen Open-Source-Software-Verkehrsgenerator, der auf standardmäßigen Intel DPDK-basierten Prozessoren läuft und zustandsabhängige/zustandslose Modi unterstützt. Das Produkt ist leicht verständlich und vollständig skalierbar.
Die englischsprachige Dokumentation für dieses Tool ist auf der Website verfügbar.
TRex ermöglicht es, verschiedene Arten von Datenverkehr zu generieren und die empfangenen Daten zu analysieren, wobei MAC- und IP-Schicht unterstützt werden. Es ist möglich, die Paketgröße und die Anzahl der Pakete einzustellen und die Datenrate zu steuern.
Die Arbeit mit dem Generator wurde in einer Linux-Umgebung durchgeführt.
Eines der wichtigsten Merkmale des TRex-Generators ist die Verwendung der DPDK-Technologie, mit der die Leistungsengpässe des Linux-Netzwerkstacks umgangen werden. Das DPDK (Data Plane Development Kit) umfasst eine Reihe von Bibliotheken und Treibern für die schnelle Paketverarbeitung, die es ermöglichen, den Linux-Netzwerkstack bei der Paketverarbeitung zu umgehen und direkt mit dem Netzwerkgerät zu kommunizieren.
Das DPDK verwandelt einen Allzweckprozessor in einen Paketweiterleitungsserver. Diese Transformation macht teure Switches und Router überflüssig. Das DPDK schränkt jedoch die Verwendung auf bestimmte Netzwerkadapter ein, die Liste der unterstützten Hardware finden sie hier - es ist Intels beliebteste Plattform, d.h. es wird Hardware unterstützt, die mit den Linux-Treibern e1000, ixgbe, i40e, ice, fm10k, ipn3ke, ifc, igc funktioniert.
Der Betrieb eines TRex-Servers mit 10 Gbit/s setzt einen Multi-Core-Prozessor mit mindestens 4 Kernen voraussetzt, vorzugsweise eine Intel-CPU mit Unterstützung für gleichzeitiges Multi-Threading (Hyper-Threading).
2. TRex herunterladen und starten
1) Laden Sie das Archiv vom Server trex-tgn.cisco.com herunter: trex-tgn.cisco.com/trex/release/
[bash]>wget --no-cache https://trex-tgn.cisco.com/trex/release/latest
[bash]>tar -xzvf latest
Entpacken Sie das Archiv in das Home-Verzeichnis des Benutzers /home/user, wobei user für den Benutzernamen steht.
2) Konfiguration der Schnittstellen zum Senden und Empfangen von Daten
Für die Konfiguration können Sie das Dienstprogramm dpdk_setup_ports.py verwenden, das im TRex-Paket enthalten ist. Die von TRex verwendeten Netzwerkschnittstellen können auf MAC- oder IP-Ebene konfiguriert werden. Starten Sie das Dienstprogramm im interaktiven Modus: sudo ./dpdk_setup_ports.py -i
Im ersten Schritt verwerfen wir die MAC-basierte Konfiguration (Möchten Sie eine MAC-basierte Konfiguration verwenden? (j/N) n).
Der zweite Schritt besteht darin, ein Paar von Netzwerkschnittstellen auszuwählen, die wir benutzen wollen. In unserem Fall verfügt die Netzwerkkarte Intel X710 über 4 Netzwerkschnittstellen, wir werden Slot 1 und Slot 4 der Netzwerkkarte verwenden.
Im dritten Schritt bietet das System an, automatisch eine geschlossene Konfiguration zu erstellen, bei der die Daten Port 1 verlassen und bei Port 2 ankommen (und zurück), und zwar auf demselben PC. Wir mussten dieses Schema aufgeben und ein Routing-Schema mit 2 PCs einrichten.
Im vierten und fünften Schritt stimmen wir dem Speichern der Konfiguration in der Datei /etc/trex_cfg.yaml zu.
Betrachten wir als Beispiel die Konfiguration auf IP-Ebene für das folgende Verbindungsschema:
Die Konfigurationsdatei ist hier zu finden: /etc/trex_cfg.yaml. Nachfolgend sehen Sie eine einfache Konfigurationsdatei für eine Netzwerkkarte mit 2 Ports und einer CPU, die 8 Threads unterstützt:
### 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]
In der Konfiguration verwendete Adressen:
- '01:00.0', '01:00.3' — Name der verwendeten Eth-Schnittstellen im Linux-System.
- ip: 192.168.253.106 — IP-Adresse des TRex-Servers, von dessen Port der Datenverkehr erzeugt wird.
- default_gw: 192.168.253.107 — IP-Adresse des PC-Prüflings (DUT … Device under test), der an Port 1 getestet wird
- ip: 192.168.254.106 — IP-Adresse des TRex-Servers, an dessen Port der Verkehr nach Durchlaufen der QOS-Regeln zurückgesendet wird
- default_gw: 192.168.253.107 — IP-Adresse des PC-Prüflings mit Port 2
Achtung! Das TRex-System verbietet bei der Generierung des Datenflusses die Verwendung desselben Subnetzes, das auch vom System verwendet wird. Daher werden für die Paketgenerierung die Subnetze 16.0.0.0 und 48.0.0.0 benutzt.
3) Konfiguration der Schnittstellen auf dem Remote-Rechner
Es ist notwendig, die Paketweiterleitung und die Routen so zu konfigurieren, dass das System (DUT), durch das der Verkehr geleitet wird, weiß, wo es Pakete empfangen und wohin es diese senden soll.
Wir konfigurieren die Routing-Regeln auf dem PC-Prüfling (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) Starten des TRex-Servers im ASTF-Modus (Advance Stateful):
cd v2.XX
sudo ./t-rex-64 -i --astf
Wenn der TRex-Server erfolgreich gestartet wurde, werden Informationen über die zum Testen verwendeten Ethernet-Ports angezeigt:
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) Starten der TRex-Konsole
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
Öffnen Sie die Konsole in einem separaten Fenster, um die Generierung des Datenflusses aus den vorgefertigten Beispielen zu starten (der Ordner mit den ASTF-Beispielen befindet sich im TRex-Archiv):
Nach erfolgreichem Start werden in der TRex-Serverkonsole die Statistiken zum Verkehrsfluss angezeigt:
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. Entwicklung und Test mit TRex automatisieren
Während der Entwicklung eines Netzwerk-Routers haben wir viele Tests für TRex geschrieben, so dass die Frage aufkam, wie man diese mit Python automatisch ausführen kann. So haben wir es organisiert:
Wir haben den TRex-Server im STL-Modus (Stateless) gestartet:
cd v2.XX
sudo ./t-rex-64 -i --stl
Es muss eine Umgebungsvariable für Python festgelegt werden, da TRex in Verbindung mit Python arbeitet.
export PYTHONPATH=/home/<user>/v2.XX/automation/trex_control_plane/interactive,
wobei <user> durch den Nutzename und das Homeverzeichnis ersetzt werden muss und v2.XX die heruntergeladene und in dieses Verzeichnis entpackte Version der TRex-Software ist
Wir haben den Traffic-Generator mit Python gestartet. Die Konfigurationsdatei ist unten abgebildet.
python example_test_2bidirectstream.py
Erwartete Ausgabe:
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
Sehen wir uns dieses Beispiel genauer an:
Zuerst wird eine Verbindung zum TRex-Server hergestellt, in diesem Fall zum gleichen Rechner hergestellt, auf dem auch der Server läuft.
- base_pkt_dir_a, base_pkt_dir_b, base_pkt_dir_c, base_pkt_dir_d sind die Paketvorlagen mit Quell- und Zieladressen sowie Quell- und Zielports. In diesem Beispiel werden 4 Datenflüsse erzeugt, 2 in die eine Richtung und 2 in die entgegengesetzte Richtung.
- s1, s2, s3, s4 - von der STLStream-Klasse werden die Parameter des generierten Flusses angefordert, wie Stream-ID und Bitrate, in unserem Fall ID1=4.5 Gbps, ID2=2.5 Gbps, ID3=2 Gbps, ID4=1 Gbps.
Konfigurationsdatei des Datenflusses 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()
Fazit
Bei der Vorbereitung dieses Tutorials für Habr haben wir einen Prüfling (DUT) mit 4 Threads konfiguriert und getestet, Thread-Informationen gesammelt und globale Statistiken erstellt.
Das oben beschriebene Beispiel benutzt zur Ausführung Python, um das Testen und Debuggen von Netzwerkgeräten und Softwareprodukten mit TRex automatisieren können - in einer Schleife oder durch sequentielle Ausführung von Tests in Python.
Ist Cisco TRex also besser oder schlechter als andere ähnliche Traffic-Generatoren? Zum Beispiel das beliebte Client-Server-Programm iperf? Im Anwendungsfall TRex wurde das Einrichten und Arbeiten mit Datenflüssen beschrieben. Beide Test- und Debugging-Tools haben ihre Stärken: iperf eignet sich für schnelle Funktionsprüfungen im laufenden Betrieb, während TRex bei der Automatisierung von Tests und der Entwicklung komplexer Netzwerkgeräte und -systeme hervorragende Dienst leistet. TRex bietet sich für Aufgaben an, bei denen die Konfiguration von Multithreading-Streams wichtig ist, um jeden Datenfluss für eine bestimmte Aufgabe zu konfigurieren und die Ausgabeergebnisse zu analysieren.
TRex ermöglicht die Erstellung von Vorlagen für nahezu jede Art von Datenverkehr und deren Erweiterung zur Generierung groß angelegter DDoS-Angriffe, einschließlich TCP-SYN-, UDP- und ICMP-Streams. Durch die Möglichkeit, massive Verkehrsströme zu erzeugen, können Sie Angriffe von verschiedenen Clients auf mehrere Zielserver simulieren.
Wenn Sie dieses Tool noch nicht ausprobiert haben, sollten Sie es sich unbedingt ansehen.
Unsere Projekte