aboutsummaryrefslogtreecommitdiffstats
path: root/tools/pkt_gen/trex/trex.py
diff options
context:
space:
mode:
authoropensource-tnbt <sridhar.rao@spirent.com>2020-11-23 12:32:36 +0530
committeropensource-tnbt <sridhar.rao@spirent.com>2020-11-23 15:27:44 +0530
commit33918409da9a5d4b60d57cd05f3277c6ff1918cd (patch)
tree610200ba871caf7ed6e97f863fc904752db27150 /tools/pkt_gen/trex/trex.py
parent605102bb6a8a3b48f0c66d817614eec0ef42e017 (diff)
Tools: User Latest Version of T-Rex.
This patch upgrades the version of T-Rex to the latest one. V2.86. This patch is tested on Node-4 and Node-5, Intel Pod12. Scapy all.py modification is not required for new version. Signed-off-by: Sridhar K. N. Rao <sridhar.rao@spirent.com> Change-Id: I928cd3a92e59a90797ae8510a57f96487811f618
Diffstat (limited to 'tools/pkt_gen/trex/trex.py')
-rw-r--r--tools/pkt_gen/trex/trex.py778
1 files changed, 0 insertions, 778 deletions
diff --git a/tools/pkt_gen/trex/trex.py b/tools/pkt_gen/trex/trex.py
deleted file mode 100644
index e2bc1e9a..00000000
--- a/tools/pkt_gen/trex/trex.py
+++ /dev/null
@@ -1,778 +0,0 @@
-# Copyright 2017 Martin Goldammer, OPNFV, Red Hat Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""
-Trex Traffic Generator Model
-"""
-
-# pylint: disable=undefined-variable
-import logging
-import subprocess
-import sys
-import time
-import os
-import re
-from collections import OrderedDict
-# pylint: disable=unused-import
-import netaddr
-import zmq
-from conf import settings
-from conf import merge_spec
-from core.results.results_constants import ResultsConstants
-from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
-try:
- # pylint: disable=wrong-import-position, import-error
- sys.path.append(settings.getValue('PATHS')['trafficgen']['Trex']['src']['path'])
- from trex_stl_lib.api import *
- from trex_stl_lib import trex_stl_exceptions
-except ImportError:
- # VSPERF performs detection of T-Rex api during testcase initialization. So if
- # T-Rex is requsted and API is not available it will fail before this code
- # is reached.
- # This code can be reached in case that --list-trafficgens is called, but T-Rex
- # api is not installed. In this case we can ignore an exception, becuase T-Rex
- # import won't be used.
- pass
-
-_EMPTY_STATS = {
- 'global': {'bw_per_core': 0.0,
- 'cpu_util': 0.0,
- 'queue_full': 0.0,
- 'rx_bps': 0.0,
- 'rx_cpu_util': 0.0,
- 'rx_drop_bps': 0.0,
- 'rx_pps': 0.0,
- 'tx_bps': 0.0,
- 'tx_pps': 0.0,},
- 'latency': {},
- 'total': {'ibytes': 0.0,
- 'ierrors': 0.0,
- 'ipackets': 0.0,
- 'obytes': 0.0,
- 'oerrors': 0.0,
- 'opackets': 0.0,
- 'rx_bps': 0.0,
- 'rx_bps_L1': 0.0,
- 'rx_pps': 0.0,
- 'rx_util': 0.0,
- 'tx_bps': 0.0,
- 'tx_bps_L1': 0.0,
- 'tx_pps': 0.0,
- 'tx_util': 0.0,}}
-
-# Default frame definition, which can be overridden by TRAFFIC['scapy'].
-# The content of the frame and its network layers are driven by TRAFFIC
-# dictionary, i.e. 'l2', 'l3, 'l4' and 'vlan' parts.
-_SCAPY_FRAME = {
- '0' : 'Ether(src={Ether_src}, dst={Ether_dst})/'
- 'Dot1Q(prio={Dot1Q_prio}, id={Dot1Q_id}, vlan={Dot1Q_vlan})/'
- 'IP(proto={IP_proto}, src={IP_src}, dst={IP_dst})/'
- '{IP_PROTO}(sport={IP_PROTO_sport}, dport={IP_PROTO_dport})',
- '1' : 'Ether(src={Ether_dst}, dst={Ether_src})/'
- 'Dot1Q(prio={Dot1Q_prio}, id={Dot1Q_id}, vlan={Dot1Q_vlan})/'
- 'IP(proto={IP_proto}, src={IP_dst}, dst={IP_src})/'
- '{IP_PROTO}(sport={IP_PROTO_dport}, dport={IP_PROTO_sport})',
-}
-
-
-class Trex(ITrafficGenerator):
- """Trex Traffic generator wrapper."""
- _logger = logging.getLogger(__name__)
-
- def __init__(self):
- """Trex class constructor."""
- super().__init__()
- self._logger.info("In trex __init__ method")
- self._params = {}
- self._trex_host_ip_addr = (
- settings.getValue('TRAFFICGEN_TREX_HOST_IP_ADDR'))
- self._trex_base_dir = (
- settings.getValue('TRAFFICGEN_TREX_BASE_DIR'))
- self._trex_user = settings.getValue('TRAFFICGEN_TREX_USER')
- self._stlclient = None
- self._verification_params = None
- self._show_packet_data = False
-
- def show_packet_info(self, packet_a, packet_b):
- """
- Log packet layers to screen
- :param packet_a: Scapy.layers packet
- :param packet_b: Scapy.layers packet
- :return: None
- """
- # we only want to show packet data once per test
- if self._show_packet_data:
- self._show_packet_data = False
- self._logger.info(packet_a.show())
- self._logger.info(packet_b.show())
-
- def connect(self):
- '''Connect to Trex traffic generator
-
- Verify that Trex is on the system indicated by
- the configuration file
- '''
- self._stlclient = STLClient()
- self._logger.info("T-Rex: In Trex connect method...")
- if self._trex_host_ip_addr:
- cmd_ping = "ping -c1 " + self._trex_host_ip_addr
- else:
- raise RuntimeError('T-Rex: Trex host not defined')
-
- ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE)
- output, error = ping.communicate()
-
- if ping.returncode:
- self._logger.error(error)
- self._logger.error(output)
- raise RuntimeError('T-Rex: Cannot ping Trex host at ' + \
- self._trex_host_ip_addr)
-
- connect_trex = "ssh " + self._trex_user + \
- "@" + self._trex_host_ip_addr
-
- cmd_find_trex = connect_trex + " ls " + \
- self._trex_base_dir + "t-rex-64"
-
-
- find_trex = subprocess.Popen(cmd_find_trex,
- shell=True,
- stderr=subprocess.PIPE)
- output, error = find_trex.communicate()
-
- if find_trex.returncode:
- self._logger.error(error)
- self._logger.error(output)
- raise RuntimeError(
- 'T-Rex: Cannot locate Trex program at %s within %s' \
- % (self._trex_host_ip_addr, self._trex_base_dir))
-
- try:
- self._stlclient = STLClient(username=self._trex_user, server=self._trex_host_ip_addr,
- verbose_level=0)
- self._stlclient.connect()
- except STLError:
- raise RuntimeError('T-Rex: Cannot connect to T-Rex server. Please check if it is '
- 'running and that firewall allows connection to TCP port 4501.')
-
- self._logger.info("T-Rex: Trex host successfully found...")
-
- def disconnect(self):
- """Disconnect from the traffic generator.
-
- As with :func:`connect`, this function is optional.
-
- Where implemented, this function should raise an exception on
- failure.
-
- :returns: None
- """
- self._logger.info("T-Rex: In trex disconnect method")
- self._stlclient.disconnect(stop_traffic=True, release_ports=True)
-
- def create_packets(self, traffic, ports_info):
- """Create base packet according to traffic specification.
- If traffic haven't specified srcmac and dstmac fields
- packet will be created with mac address of trex server.
- """
- if not traffic or traffic['l2']['framesize'] <= 0:
- return (None, None)
-
- if traffic['l2']['dstmac'] == '00:00:00:00:00:00' and \
- traffic['l2']['srcmac'] == '00:00:00:00:00:00':
-
- mac_add = [li['hw_mac'] for li in ports_info]
- src_mac = mac_add[0]
- dst_mac = mac_add[1]
- else:
- src_mac = traffic['l2']['srcmac']
- dst_mac = traffic['l2']['dstmac']
-
- if traffic['scapy']['enabled']:
- base_pkt_a = traffic['scapy']['0']
- base_pkt_b = traffic['scapy']['1']
- else:
- base_pkt_a = _SCAPY_FRAME['0']
- base_pkt_b = _SCAPY_FRAME['1']
-
- # check and remove network layers disabled by TRAFFIC dictionary
- # Note: In general, it is possible to remove layers from scapy object by
- # e.g. del base_pkt_a['IP']. However it doesn't work for all layers
- # (e.g. Dot1Q). Thus it is safer to modify string with scapy frame definition
- # directly, before it is converted to the real scapy object.
- if not traffic['vlan']['enabled']:
- self._logger.info('VLAN headers are disabled by TRAFFIC')
- base_pkt_a = re.sub(r'(^|\/)Dot1Q?\([^\)]*\)', '', base_pkt_a)
- base_pkt_b = re.sub(r'(^|\/)Dot1Q?\([^\)]*\)', '', base_pkt_b)
- if not traffic['l3']['enabled']:
- self._logger.info('IP headers are disabled by TRAFFIC')
- base_pkt_a = re.sub(r'(^|\/)IP(v6)?\([^\)]*\)', '', base_pkt_a)
- base_pkt_b = re.sub(r'(^|\/)IP(v6)?\([^\)]*\)', '', base_pkt_b)
- if not traffic['l4']['enabled']:
- self._logger.info('%s headers are disabled by TRAFFIC',
- traffic['l3']['proto'].upper())
- base_pkt_a = re.sub(r'(^|\/)(UDP|TCP|SCTP|{{IP_PROTO}}|{})\([^\)]*\)'.format(
- traffic['l3']['proto'].upper()), '', base_pkt_a)
- base_pkt_b = re.sub(r'(^|\/)(UDP|TCP|SCTP|{{IP_PROTO}}|{})\([^\)]*\)'.format(
- traffic['l3']['proto'].upper()), '', base_pkt_b)
-
- # pylint: disable=eval-used
- base_pkt_a = eval(base_pkt_a.format(
- Ether_src=repr(src_mac),
- Ether_dst=repr(dst_mac),
- Dot1Q_prio=traffic['vlan']['priority'],
- Dot1Q_id=traffic['vlan']['cfi'],
- Dot1Q_vlan=traffic['vlan']['id'],
- IP_proto=repr(traffic['l3']['proto']),
- IP_PROTO=traffic['l3']['proto'].upper(),
- IP_src=repr(traffic['l3']['srcip']),
- IP_dst=repr(traffic['l3']['dstip']),
- IP_PROTO_sport=traffic['l4']['srcport'],
- IP_PROTO_dport=traffic['l4']['dstport']))
- base_pkt_b = eval(base_pkt_b.format(
- Ether_src=repr(src_mac),
- Ether_dst=repr(dst_mac),
- Dot1Q_prio=traffic['vlan']['priority'],
- Dot1Q_id=traffic['vlan']['cfi'],
- Dot1Q_vlan=traffic['vlan']['id'],
- IP_proto=repr(traffic['l3']['proto']),
- IP_PROTO=traffic['l3']['proto'].upper(),
- IP_src=repr(traffic['l3']['srcip']),
- IP_dst=repr(traffic['l3']['dstip']),
- IP_PROTO_sport=traffic['l4']['srcport'],
- IP_PROTO_dport=traffic['l4']['dstport']))
-
- return (base_pkt_a, base_pkt_b)
-
- @staticmethod
- def create_streams(base_pkt_a, base_pkt_b, traffic):
- """Add the base packet to the streams. Erase FCS and add payload
- according to traffic specification
- """
- stream_1_lat = None
- stream_2_lat = None
- frame_size = int(traffic['l2']['framesize'])
- fsize_no_fcs = frame_size - 4
- payload_a = max(0, fsize_no_fcs - len(base_pkt_a)) * 'x'
- payload_b = max(0, fsize_no_fcs - len(base_pkt_b)) * 'x'
-
- # Multistream configuration, increments source values only
- ms_mod = list() # mod list for incrementing values to be populated based on layer
- if traffic['multistream'] > 1:
- if traffic['stream_type'].upper() == 'L2':
- for _ in [base_pkt_a, base_pkt_b]:
- ms_mod += [STLVmFlowVar(name="mac_start", min_value=0,
- max_value=traffic['multistream'] - 1, size=4, op="inc"),
- STLVmWrFlowVar(fv_name="mac_start", pkt_offset=7)]
- elif traffic['stream_type'].upper() == 'L3':
- ip_src = {"start": int(netaddr.IPAddress(traffic['l3']['srcip'])),
- "end": int(netaddr.IPAddress(traffic['l3']['srcip'])) + traffic['multistream'] - 1}
- ip_dst = {"start": int(netaddr.IPAddress(traffic['l3']['dstip'])),
- "end": int(netaddr.IPAddress(traffic['l3']['dstip'])) + traffic['multistream'] - 1}
- for ip_address in [ip_src, ip_dst]:
- ms_mod += [STLVmFlowVar(name="ip_src", min_value=ip_address['start'],
- max_value=ip_address['end'], size=4, op="inc"),
- STLVmWrFlowVar(fv_name="ip_src", pkt_offset="IP.src")]
- elif traffic['stream_type'].upper() == 'L4':
- for udpport in [traffic['l4']['srcport'], traffic['l4']['dstport']]:
- if udpport + (traffic['multistream'] - 1) > 65535:
- start_port = udpport
- # find the max/min port number based on the loop around of 65535 to 0 if needed
- minimum_value = 65535 - (traffic['multistream'] -1)
- maximum_value = 65535
- else:
- start_port, minimum_value = udpport, udpport
- maximum_value = start_port + (traffic['multistream'] - 1)
- ms_mod += [STLVmFlowVar(name="port_src", init_value=start_port,
- min_value=minimum_value, max_value=maximum_value,
- size=2, op="inc"),
- STLVmWrFlowVar(fv_name="port_src", pkt_offset="UDP.sport"),]
-
- if ms_mod: # multistream detected
- pkt_a = STLPktBuilder(pkt=base_pkt_a/payload_a, vm=[ms_mod[0], ms_mod[1]])
- pkt_b = STLPktBuilder(pkt=base_pkt_b/payload_b, vm=[ms_mod[2], ms_mod[3]])
- else:
- pkt_a = STLPktBuilder(pkt=base_pkt_a / payload_a)
- pkt_b = STLPktBuilder(pkt=base_pkt_b / payload_b)
-
- lat_pps = settings.getValue('TRAFFICGEN_TREX_LATENCY_PPS')
- if traffic['traffic_type'] == 'burst':
- if lat_pps > 0:
- # latency statistics are requested; in case of frame burst we can enable
- # statistics for all frames
- stream_1 = STLStream(packet=pkt_a,
- flow_stats=STLFlowLatencyStats(pg_id=0),
- name='stream_1',
- mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
- total_pkts=traffic['burst_size']))
- stream_2 = STLStream(packet=pkt_b,
- flow_stats=STLFlowLatencyStats(pg_id=1),
- name='stream_2',
- mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
- total_pkts=traffic['burst_size']))
- else:
- stream_1 = STLStream(packet=pkt_a,
- name='stream_1',
- mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
- total_pkts=traffic['burst_size']))
- stream_2 = STLStream(packet=pkt_b,
- name='stream_2',
- mode=STLTXSingleBurst(percentage=traffic['frame_rate'],
- total_pkts=traffic['burst_size']))
- else:
- stream_1 = STLStream(packet=pkt_a,
- name='stream_1',
- mode=STLTXCont(percentage=traffic['frame_rate']))
- stream_2 = STLStream(packet=pkt_b,
- name='stream_2',
- mode=STLTXCont(percentage=traffic['frame_rate']))
- # workaround for latency statistics, which can't be enabled for streams
- # with high framerate due to the huge performance impact
- if lat_pps > 0:
- stream_1_lat = STLStream(packet=pkt_a,
- flow_stats=STLFlowLatencyStats(pg_id=0),
- name='stream_1_lat',
- mode=STLTXCont(pps=lat_pps))
- stream_2_lat = STLStream(packet=pkt_b,
- flow_stats=STLFlowLatencyStats(pg_id=1),
- name='stream_2_lat',
- mode=STLTXCont(pps=lat_pps))
-
- return (stream_1, stream_2, stream_1_lat, stream_2_lat)
-
-
- # pylint: disable=too-many-locals, too-many-statements
- def generate_traffic(self, traffic, duration, disable_capture=False):
- """The method that generate a stream
- """
- my_ports = [0, 1]
-
- # initialize ports
- self._stlclient.reset(my_ports)
- self._stlclient.remove_all_captures()
- self._stlclient.set_service_mode(ports=my_ports, enabled=False)
-
- ports_info = self._stlclient.get_port_info(my_ports)
-
- # get max support speed
- max_speed = 0
- if settings.getValue('TRAFFICGEN_TREX_FORCE_PORT_SPEED'):
- max_speed = settings.getValue('TRAFFICGEN_TREX_PORT_SPEED')
- elif ports_info[0]['supp_speeds']:
- max_speed_1 = max(ports_info[0]['supp_speeds'])
- max_speed_2 = max(ports_info[1]['supp_speeds'])
- else:
- # if max supported speed not in port info or set manually, just assume 10G
- max_speed = 10000
- if not max_speed:
- # since we can only control both ports at once take the lower of the two
- max_speed = min(max_speed_1, max_speed_2)
- gbps_speed = (max_speed / 1000) * (float(traffic['frame_rate']) / 100.0)
- self._logger.debug('Starting traffic at %s Gbps speed', gbps_speed)
-
- # for SR-IOV
- if settings.getValue('TRAFFICGEN_TREX_PROMISCUOUS'):
- self._stlclient.set_port_attr(my_ports, promiscuous=True)
-
- packet_1, packet_2 = self.create_packets(traffic, ports_info)
- self.show_packet_info(packet_1, packet_2)
- stream_1, stream_2, stream_1_lat, stream_2_lat = Trex.create_streams(packet_1, packet_2, traffic)
- self._stlclient.add_streams(stream_1, ports=[0])
- self._stlclient.add_streams(stream_2, ports=[1])
-
- if stream_1_lat is not None:
- self._stlclient.add_streams(stream_1_lat, ports=[0])
- self._stlclient.add_streams(stream_2_lat, ports=[1])
-
- # enable traffic capture if requested
- pcap_id = {}
- if traffic['capture']['enabled'] and not disable_capture:
- for ports in ['tx_ports', 'rx_ports']:
- if traffic['capture'][ports]:
- pcap_dir = ports[:2]
- self._logger.info("T-Rex starting %s traffic capture", pcap_dir.upper())
- capture = {ports : traffic['capture'][ports],
- 'limit' : traffic['capture']['count'],
- 'bpf_filter' : traffic['capture']['filter']}
- self._stlclient.set_service_mode(ports=traffic['capture'][ports], enabled=True)
- pcap_id[pcap_dir] = self._stlclient.start_capture(**capture)
-
- self._stlclient.clear_stats()
- # if the user did not start up T-Rex server with more than default cores, use default mask.
- # Otherwise use mask to take advantage of multiple cores.
- try:
- self._stlclient.start(ports=my_ports, force=True, duration=duration, mult="{}gbps".format(gbps_speed),
- core_mask=self._stlclient.CORE_MASK_PIN)
- except STLError:
- self._stlclient.start(ports=my_ports, force=True, duration=duration, mult="{}gbps".format(gbps_speed))
-
- if settings.getValue('TRAFFICGEN_TREX_LIVE_RESULTS'):
- filec = os.path.join(settings.getValue('RESULTS_PATH'),
- settings.getValue('TRAFFICGEN_TREX_LC_FILE'))
- filee = os.path.join(settings.getValue('RESULTS_PATH'),
- settings.getValue('TRAFFICGEN_TREX_LE_FILE'))
- pgids = self._stlclient.get_active_pgids()
- rx_port_0 = 1
- tx_port_0 = 0
- rx_port_1 = 0
- tx_port_1 = 1
- with open(filec, 'a') as fcp, open(filee, 'a') as fep:
- fcp.write("ts,rx_port,tx_port,rx_pkts,tx_pkts,rx_pps,tx_pps,"+
- "rx_bps_num,rx_bps_den,tx_bps_num,tx_bps_den\n")
- fep.write('ts,dropped,ooo,dup,seq_too_high,seq_too_low\n')
- while True:
- tr_status = self._stlclient.is_traffic_active(ports=my_ports)
- if not tr_status:
- break
- time.sleep(1)
- stats = self._stlclient.get_pgid_stats(pgids['flow_stats'])
- lat_stats = stats['latency'].get(0)
- flow_stats_0 = stats['flow_stats'].get(0)
- flow_stats_1 = stats['flow_stats'].get(1)
- if flow_stats_0:
- rx_pkts = flow_stats_0['rx_pkts'][rx_port_0]
- tx_pkts = flow_stats_0['tx_pkts'][tx_port_0]
- rx_pps = flow_stats_0['rx_pps'][rx_port_0]
- tx_pps = flow_stats_0['tx_pps'][tx_port_0]
- rx_bps = flow_stats_0['rx_bps'][rx_port_0]
- tx_bps = flow_stats_0['tx_bps'][tx_port_0]
- rx_bps_l1 = flow_stats_0['rx_bps_l1'][rx_port_0]
- tx_bps_l1 = flow_stats_0['tx_bps_l1'][tx_port_0]
- # https://github.com/cisco-system-traffic-generator/\
- # trex-core/blob/master/scripts/automation/\
- # trex_control_plane/interactive/trex/examples/\
- # stl/stl_flow_latency_stats.py
- fcp.write("{10},{8},{9},{0},{1},{2},{3},{4},{5},{6},{7}\n"
- .format(rx_pkts, tx_pkts, rx_pps, tx_pps,
- rx_bps, rx_bps_l1, tx_bps, tx_bps_l1,
- rx_port_0, tx_port_0, time.time()))
- if flow_stats_1:
- rx_pkts = flow_stats_1['rx_pkts'][rx_port_1]
- tx_pkts = flow_stats_1['tx_pkts'][tx_port_1]
- rx_pps = flow_stats_1['rx_pps'][rx_port_1]
- tx_pps = flow_stats_1['tx_pps'][tx_port_1]
- rx_bps = flow_stats_1['rx_bps'][rx_port_1]
- tx_bps = flow_stats_1['tx_bps'][tx_port_1]
- rx_bps_l1 = flow_stats_1['rx_bps_l1'][rx_port_1]
- tx_bps_l1 = flow_stats_1['tx_bps_l1'][tx_port_1]
- fcp.write("{10},{8},{9},{0},{1},{2},{3},{4},{5},{6},{7}\n"
- .format(rx_pkts, tx_pkts, rx_pps, tx_pps,
- rx_bps, rx_bps_l1, tx_bps, tx_bps_l1,
- rx_port_1, tx_port_1, time.time()))
- if lat_stats:
- drops = lat_stats['err_cntrs']['dropped']
- ooo = lat_stats['err_cntrs']['out_of_order']
- dup = lat_stats['err_cntrs']['dup']
- sth = lat_stats['err_cntrs']['seq_too_high']
- stl = lat_stats['err_cntrs']['seq_too_low']
- fep.write('{5},{0},{1},{2},{3},{4}\n'
- .format(drops, ooo, dup, sth, stl, time.time()))
- else:
- self._stlclient.wait_on_traffic(ports=my_ports)
- stats = self._stlclient.get_stats(sync_now=True)
-
- # export captured data into pcap file if possible
- if pcap_id:
- for pcap_dir in pcap_id:
- pcap_file = 'capture_{}.pcap'.format(pcap_dir)
- self._stlclient.stop_capture(pcap_id[pcap_dir]['id'],
- os.path.join(settings.getValue('RESULTS_PATH'), pcap_file))
- stats['capture_{}'.format(pcap_dir)] = pcap_file
- self._logger.info("T-Rex writing %s traffic capture into %s", pcap_dir.upper(), pcap_file)
- # disable service mode for all ports used by Trex
- self._stlclient.set_service_mode(ports=my_ports, enabled=False)
-
- return stats
-
- @staticmethod
- def calculate_results(stats):
- """Calculate results from Trex statistic
- """
- result = OrderedDict()
- result[ResultsConstants.TX_FRAMES] = (
- stats["total"]["opackets"])
- result[ResultsConstants.RX_FRAMES] = (
- stats["total"]["ipackets"])
- result[ResultsConstants.TX_RATE_FPS] = (
- '{:.3f}'.format(
- float(stats["total"]["tx_pps"])))
-
- result[ResultsConstants.THROUGHPUT_RX_FPS] = (
- '{:.3f}'.format(
- float(stats["total"]["rx_pps"])))
-
- result[ResultsConstants.TX_RATE_MBPS] = (
- '{:.3f}'.format(
- float(stats["total"]["tx_bps"] / 1000000)))
- result[ResultsConstants.THROUGHPUT_RX_MBPS] = (
- '{:.3f}'.format(
- float(stats["total"]["rx_bps"] / 1000000)))
-
- result[ResultsConstants.TX_RATE_PERCENT] = 'Unknown'
-
- result[ResultsConstants.THROUGHPUT_RX_PERCENT] = 'Unknown'
- if stats["total"]["opackets"]:
- result[ResultsConstants.FRAME_LOSS_PERCENT] = (
- '{:.3f}'.format(
- float((stats["total"]["opackets"] - stats["total"]["ipackets"]) * 100 /
- stats["total"]["opackets"])))
- else:
- result[ResultsConstants.FRAME_LOSS_PERCENT] = 100
-
- if settings.getValue('TRAFFICGEN_TREX_LATENCY_PPS') > 0 and stats['latency']:
- try:
- result[ResultsConstants.MIN_LATENCY_NS] = (
- '{:.3f}'.format(
- (float(min(stats["latency"][0]["latency"]["total_min"],
- stats["latency"][1]["latency"]["total_min"])))))
- except TypeError:
- result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown'
-
- try:
- result[ResultsConstants.MAX_LATENCY_NS] = (
- '{:.3f}'.format(
- (float(max(stats["latency"][0]["latency"]["total_max"],
- stats["latency"][1]["latency"]["total_max"])))))
- except TypeError:
- result[ResultsConstants.MAX_LATENCY_NS] = 'Unknown'
-
- try:
- result[ResultsConstants.AVG_LATENCY_NS] = (
- '{:.3f}'.format(
- float((stats["latency"][0]["latency"]["average"]+
- stats["latency"][1]["latency"]["average"])/2)))
- except TypeError:
- result[ResultsConstants.AVG_LATENCY_NS] = 'Unknown'
-
- else:
- result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown'
- result[ResultsConstants.MAX_LATENCY_NS] = 'Unknown'
- result[ResultsConstants.AVG_LATENCY_NS] = 'Unknown'
-
- if 'capture_tx' in stats:
- result[ResultsConstants.CAPTURE_TX] = stats['capture_tx']
- if 'capture_rx' in stats:
- result[ResultsConstants.CAPTURE_RX] = stats['capture_rx']
- return result
-
- def learning_packets(self, traffic):
- """
- Send learning packets before testing
- :param traffic: traffic structure as per send_cont_traffic guidelines
- :return: None
- """
- self._logger.info("T-Rex sending learning packets")
- learning_thresh_traffic = copy.deepcopy(traffic)
- learning_thresh_traffic["frame_rate"] = 1
- self.generate_traffic(learning_thresh_traffic,
- settings.getValue("TRAFFICGEN_TREX_LEARNING_DURATION"),
- disable_capture=True)
- self._logger.info("T-Rex finished learning packets")
- time.sleep(3) # allow packets to complete before starting test traffic
-
- def run_trials(self, traffic, boundaries, duration, lossrate):
- """
- Run rfc2544 trial loop
- :param traffic: traffic profile dictionary
- :param boundaries: A dictionary of three keys left, right, center to dictate
- the highest, lowest, and starting point of the binary search.
- Values are percentages of line rates for each key.
- :param duration: length in seconds for trials
- :param lossrate: loweset loss rate percentage calculated from
- comparision between received and sent packets
- :return: passing stats as dictionary
- """
- threshold = settings.getValue('TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
- max_repeat = settings.getValue('TRAFFICGEN_TREX_RFC2544_MAX_REPEAT')
- loss_verification = settings.getValue('TRAFFICGEN_TREX_RFC2544_BINARY_SEARCH_LOSS_VERIFICATION')
- if loss_verification:
- self._logger.info("Running Binary Search with Loss Verification")
- stats_ok = _EMPTY_STATS
- new_params = copy.deepcopy(traffic)
- iteration = 1
- repeat = 0
- left = boundaries['left']
- right = boundaries['right']
- center = boundaries['center']
- self._logger.info('Starting RFC2544 trials')
- while (right - left) > threshold:
- stats = self.generate_traffic(new_params, duration)
- test_lossrate = ((stats["total"]["opackets"] - stats[
- "total"]["ipackets"]) * 100) / stats["total"]["opackets"]
- if stats["total"]["ipackets"] == 0:
- self._logger.error('No packets recieved. Test failed')
- return _EMPTY_STATS
- if settings.getValue('TRAFFICGEN_TREX_VERIFICATION_MODE'):
- if test_lossrate <= lossrate:
- # save the last passing trial for verification
- self._verification_params = copy.deepcopy(new_params)
- packets_lost = stats['total']['opackets'] - stats['total']['ipackets']
- self._logger.debug("Iteration: %s, frame rate: %s, throughput_rx_fps: %s," +
- " frames lost %s, frame_loss_percent: %s", iteration,
- "{:.3f}".format(new_params['frame_rate']), stats['total']['rx_pps'],
- packets_lost, "{:.3f}".format(test_lossrate))
- if test_lossrate == 0.0 and new_params['frame_rate'] == traffic['frame_rate']:
- return copy.deepcopy(stats)
- elif test_lossrate > lossrate:
- if loss_verification:
- if repeat < max_repeat:
- repeat += 1
- iteration += 1
- continue
- else:
- repeat = 0
- right = center
- center = (left + right) / 2
- new_params = copy.deepcopy(traffic)
- new_params['frame_rate'] = center
- else:
- if loss_verification:
- repeat = 0
- stats_ok = copy.deepcopy(stats)
- left = center
- center = (left + right) / 2
- new_params = copy.deepcopy(traffic)
- new_params['frame_rate'] = center
- iteration += 1
- return stats_ok
-
- def send_cont_traffic(self, traffic=None, duration=30):
- """See ITrafficGenerator for description
- """
- self._logger.info("In Trex send_cont_traffic method")
- self._params.clear()
-
- self._show_packet_data = True
-
- self._params['traffic'] = self.traffic_defaults.copy()
- if traffic:
- self._params['traffic'] = merge_spec(
- self._params['traffic'], traffic)
-
- if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'):
- self.learning_packets(traffic)
- self._logger.info("T-Rex sending traffic")
- stats = self.generate_traffic(traffic, duration)
-
- return self.calculate_results(stats)
-
- def start_cont_traffic(self, traffic=None, duration=30):
- raise NotImplementedError(
- 'Trex start cont traffic not implemented')
-
- def stop_cont_traffic(self):
- """See ITrafficGenerator for description
- """
- raise NotImplementedError(
- 'Trex stop_cont_traffic method not implemented')
-
- def send_rfc2544_throughput(self, traffic=None, tests=1, duration=60,
- lossrate=0.0):
- """See ITrafficGenerator for description
- """
- self._logger.info("In Trex send_rfc2544_throughput method")
- self._params.clear()
- self._show_packet_data = True
- self._params['traffic'] = self.traffic_defaults.copy()
- if traffic:
- self._params['traffic'] = merge_spec(
- self._params['traffic'], traffic)
- if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'):
- self.learning_packets(traffic)
- self._verification_params = copy.deepcopy(traffic)
-
- binary_bounds = {'right' : traffic['frame_rate'],
- 'left' : 0,
- 'center': traffic['frame_rate'],}
-
- # Loops until the preconfigured differencde between frame rate
- # of successful and unsuccessful iterations is reached
- stats_ok = self.run_trials(boundaries=binary_bounds, duration=duration,
- lossrate=lossrate, traffic=traffic)
- if settings.getValue('TRAFFICGEN_TREX_VERIFICATION_MODE'):
- verification_iterations = 1
- while verification_iterations <= settings.getValue('TRAFFICGEN_TREX_MAXIMUM_VERIFICATION_TRIALS'):
- self._logger.info('Starting Trex Verification trial for %s seconds at frame rate %s',
- settings.getValue('TRAFFICGEN_TREX_VERIFICATION_DURATION'),
- self._verification_params['frame_rate'])
- stats = self.generate_traffic(self._verification_params,
- settings.getValue('TRAFFICGEN_TREX_VERIFICATION_DURATION'))
- verification_lossrate = ((stats["total"]["opackets"] - stats[
- "total"]["ipackets"]) * 100) / stats["total"]["opackets"]
- if verification_lossrate <= lossrate:
- self._logger.info('Trex Verification passed, %s packets were lost',
- stats["total"]["opackets"] - stats["total"]["ipackets"])
- stats_ok = copy.deepcopy(stats)
- break
- else:
- self._logger.info('Trex Verification failed, %s packets were lost',
- stats["total"]["opackets"] - stats["total"]["ipackets"])
- new_right = self._verification_params['frame_rate'] - settings.getValue(
- 'TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
- self._verification_params['frame_rate'] = new_right
- binary_bounds = {'right': new_right,
- 'left': 0,
- 'center': new_right,}
- stats_ok = self.run_trials(boundaries=binary_bounds, duration=duration,
- lossrate=lossrate, traffic=self._verification_params)
- verification_iterations += 1
- else:
- self._logger.error('Could not pass Trex Verification. Test failed')
- return self.calculate_results(stats_ok)
-
- def start_rfc2544_throughput(self, traffic=None, tests=1, duration=60,
- lossrate=0.0):
- raise NotImplementedError(
- 'Trex start rfc2544 throughput not implemented')
-
- def wait_rfc2544_throughput(self):
- raise NotImplementedError(
- 'Trex wait rfc2544 throughput not implemented')
-
- def send_burst_traffic(self, traffic=None, duration=20):
- """See ITrafficGenerator for description
- """
- self._logger.info("In Trex send_burst_traffic method")
- self._params.clear()
-
- self._params['traffic'] = self.traffic_defaults.copy()
- if traffic:
- self._params['traffic'] = merge_spec(
- self._params['traffic'], traffic)
-
- if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'):
- self.learning_packets(traffic)
- self._logger.info("T-Rex sending traffic")
- stats = self.generate_traffic(traffic, duration)
-
- time.sleep(3) # allow packets to complete before reading stats
-
- return self.calculate_results(stats)
-
- def send_rfc2544_back2back(self, traffic=None, tests=1, duration=30,
- lossrate=0.0):
- raise NotImplementedError(
- 'Trex send rfc2544 back2back not implemented')
-
- def start_rfc2544_back2back(self, traffic=None, tests=1, duration=30,
- lossrate=0.0):
- raise NotImplementedError(
- 'Trex start rfc2544 back2back not implemented')
-
- def wait_rfc2544_back2back(self):
- raise NotImplementedError(
- 'Trex wait rfc2544 back2back not implemented')
-
-if __name__ == "__main__":
- pass