思科TRex流量生成器:启动网络设备的负载测试





在开发另一台路由器时,我们使用了一个有用的开源产品Cisco TRex流量生成器测试了网络性能。这是什么工具?如何使用它?对开发工程师有什么用?以下是这些问题的答案。



1.什么是Cisco TRex



它是一个开源软件流量生成器,可以在基于Intel DPDK的标准处理器上运行,并支持有状态/无状态模式。比较简单,完全可扩展。



该工具的英语文档可在网站上找到



Trex允许您生成不同类型的流量,并在收到数据时对其进行分析。支持在MAC和IP级别上工作。您可以设置数据包的大小及其数量,控制数据传输速率。



在Linux环境中组织使用生成器。



Trex生成器之间的重要区别之一是DPDK技术的使用,该技术可让您绕过Linux网络堆栈中的性能瓶颈。 DPDK或数据平面开发套件是用于快速数据包处理的一组库和驱动程序,使您可以从数据包处理中排除Linux网络堆栈,并直接与网络设备进行交互。



DPDK将通用处理器转变为数据包转发服务器。这种转变消除了对昂贵的交换机和路由器的需求。但是,DPDK对特定网络适配器的使用施加了限制,链接上指示了受支持的硬件列表-这是英特尔最受欢迎的平台,即 提供了与Linux驱动程序e1000,ixgbe,i40e,ice,fm10k,ipn3ke,ifc,igc一起使用的硬件支持。



同样重要的是要理解,要使TRex服务器以10 Gbps的速度运行,就需要一个多核处理器-4核或更高,最好是支持同时多线程(超线程)的Intel CPU。



2.如何获得和尝试TRex



1)从trex-tgn.cisco.com服务器下载档案: trex-tgn.cisco.com/trex/release/



在用户的主目录“ / home / user”中解压缩档案,其中user是用户名。



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


2)配置用于发送和接收数据的接口



让我们使用TRex存档中随附的“ dpdk_setup_ports.py”实用程序执行配置。您可以在MAC或IP级别上配置TRex使用的网络接口。首先,您需要使用“ sudo ./dpdk_setup_ports.py –i”交互式设置键运行该实用程序。



第一步是放弃在MAC级别的配置(是否要使用基于MAC的配置?(是/否)n)。



第二步是选择将要使用的一对网络接口,在本例中,Intel X710网卡可用于4个网络接口,我们将使用网卡的第一个和第四个插槽。







在第三步中,系统将提供自动创建封闭配置的功能-当数据离开端口1并到达端口2(然后返回)时,它们全部在一台PC上。我们必须放弃此方案,并为2台PC配置路由方案。



在第四步和第五步中,我们同意将配置保存到/etc/trex_cfg.yaml文件中。



例如,考虑以下连接方案在IP级别







的配置配置文件位于此处:“ / etc / trex_cfg.yaml”。下面显示了一个简单的配置文件,用于2端口NIC,其CPU支持8个线程:



### 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]


在配置中:



  • '01:00.0','01:00.3'-使用的Linux系统中Eth接口的名称。
  • ip:192.168.253.106-从中生成流量的Server TRex PC端口的地址。
  • default_gw:192.168.253.107-PC DUT(被测设备)的1个端口的地址。
  • ip:192.168.254.106-服务器TRex PC端口的地址,通过QOS规则后,将从该端口返回流量。
  • default_gw:192.168.253.107-PC DUT的2个端口的地址。


注意!TRex系统在生成系统使用的流时禁止使用同一子网;为此,在生成数据包时,使用子网16.0.0.0和48.0.0.0。



3)在远程计算机上配置接口



必须配置转发和路由,以便我们将通过其通信的系统(DUT)知道在哪里接收和在哪里发送数据包。



在DUT PC上配置流路由规则:



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)在astf模式下启动TRex服务器:



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


如果TRex服务器成功启动,我们将看到有关用于测试的以太网端口的信息:



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)启动TRex控制台



使用该控制台,在一个单独的窗口中,开始从现成的示例生成流(带有astf示例的文件夹在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


如果启动成功,我们将在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.使用TRex自动化开发和测试



在开发网络路由器的过程中,我们为TRex编写了许多测试,因此出现了使用python在自动模式下运行它们的问题。我们如何组织它:



我们以stl模式启动了TRex服务器:



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


由于TRex与python结合使用,因此请为python设置环境变量。



导出PYTHONPATH = / home / !!!用户!!! / v2.XX /自动化/ trex_control_plane /交互式,其中“ !!!用户!!!” -用户名和主目录,v2.XX-已下载并解压缩到此文件夹中的TRex软件版本。



我们使用python启动了流量生成器,下面给出了示例配置清单。



python example_test_2bidirectstream.py



预期输出:



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


让我们看一下这个示例:



c = STLClient(server ='127.0.0.1')



创建与TRex服务器的连接,在这种情况下,该连接与服务器创建在同一台计算机上。



  • “ Base_pkt_dir_a,base_pkt_dir_b,base_pkt_dir_c,base_pkt_dir_d”-数据包模板,其中包含源和目标地址,源和目标端口。在此示例中,创建了4个流,一个方向为2个,相反方向为2个。
  • “ S1,s2,s3,s4”-从STLStream类请求生成的流的参数,例如流ID和比特率,在我们的情况下,ID1 = 4.5 Gbps,ID2 = 2.5 Gbps,ID3 = 2 Gbps,ID4 = 1 Gbps。


流配置文件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()


结论



在为Habr准备本指南时,我们启动并测试了具有4个线程的DUT系统的运行情况,收集了有关线程的信息和全局统计信息。



上面描述的操作是使用python启动的,这意味着使用TRex,您可以循环或在python中依次运行测试时自动执行网络设备和软件产品的测试和调试。



那么,为什么思科的TRex比其他类似的流量生成器更好或更差?例如,流行的客户端服务器程序iperf?在TRex使用场景中,我们看到有关设置和使用流的描述。测试和调试工具都很好:iperf-用于在旅途中快速测试功能,TRex出色地完成了复杂网络设备和系统的自动化测试和开发,其中配置多线程流的能力对于为特定任务配置每个流并分析输出结果很重要。 ...



TRex允许您为几乎所有流量创建模板,并将其放大以生成大规模DDoS攻击,包括TCP-SYN,UDP和ICMP流。生成大量流量的能力使您可以模拟来自多个目标服务器上多个客户端的攻击。



因此,如果您还没有尝试过此工具,则可以进行记录。如果尝试过-在评论中分享您的示例和反馈。知道其他工程师正在考虑和使用什么是TRex,这很有趣。



All Articles