diff options
author | opensource-tnbt <sridhar.rao@spirent.com> | 2020-11-23 12:32:36 +0530 |
---|---|---|
committer | opensource-tnbt <sridhar.rao@spirent.com> | 2020-11-23 15:27:44 +0530 |
commit | 33918409da9a5d4b60d57cd05f3277c6ff1918cd (patch) | |
tree | 610200ba871caf7ed6e97f863fc904752db27150 /tools/pkt_gen/trex/trex.py | |
parent | 605102bb6a8a3b48f0c66d817614eec0ef42e017 (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.py | 778 |
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 |