# License for the specific language governing permissions and limitations
# under the License.
+import os
+import random
+import time
+import traceback
+
from collections import defaultdict
from itertools import count
from nfvbench.log import LOG
from nfvbench.specs import ChainType
from nfvbench.traffic_server import TRexTrafficServer
+from nfvbench.utils import cast_integer
from nfvbench.utils import timeout
from nfvbench.utils import TimeoutError
-import os
-import random
-import time
-import traceback
from traffic_base import AbstractTrafficGenerator
from traffic_base import TrafficGeneratorException
import traffic_utils as utils
-
+# pylint: disable=import-error
from trex_stl_lib.api import CTRexVmInsFixHwCs
from trex_stl_lib.api import Dot1Q
from trex_stl_lib.api import Ether
from trex_stl_lib.services.trex_stl_service_arp import STLServiceARP
-class TRex(AbstractTrafficGenerator):
+# pylint: enable=import-error
+
+class TRex(AbstractTrafficGenerator):
LATENCY_PPS = 1000
def __init__(self, runner):
self.streamblock = defaultdict(list)
self.rates = []
self.arps = {}
+ self.capture_id = None
+ self.packet_list = []
def get_version(self):
return self.client.get_server_version()
stats = self.__combine_stats(in_stats, ph)
result[ph] = {
'tx': {
- 'total_pkts': stats['tx_pkts']['total'],
- 'total_pkt_bytes': stats['tx_bytes']['total'],
- 'pkt_rate': stats['tx_pps']['total'],
- 'pkt_bit_rate': stats['tx_bps']['total']
+ 'total_pkts': cast_integer(stats['tx_pkts']['total']),
+ 'total_pkt_bytes': cast_integer(stats['tx_bytes']['total']),
+ 'pkt_rate': cast_integer(stats['tx_pps']['total']),
+ 'pkt_bit_rate': cast_integer(stats['tx_bps']['total'])
},
'rx': {
- 'total_pkts': stats['rx_pkts']['total'],
- 'total_pkt_bytes': stats['rx_bytes']['total'],
- 'pkt_rate': stats['rx_pps']['total'],
- 'pkt_bit_rate': stats['rx_bps']['total'],
- 'dropped_pkts': stats['tx_pkts']['total'] - stats['rx_pkts']['total']
+ 'total_pkts': cast_integer(stats['rx_pkts']['total']),
+ 'total_pkt_bytes': cast_integer(stats['rx_bytes']['total']),
+ 'pkt_rate': cast_integer(stats['rx_pps']['total']),
+ 'pkt_bit_rate': cast_integer(stats['rx_bps']['total']),
+ 'dropped_pkts': cast_integer(
+ stats['tx_pkts']['total'] - stats['rx_pkts']['total'])
}
}
lat = self.__combine_latencies(in_stats, ph)
- result[ph]['rx']['max_delay_usec'] = lat.get('total_max', float('nan'))
- result[ph]['rx']['min_delay_usec'] = lat.get('total_min', float('nan'))
- result[ph]['rx']['avg_delay_usec'] = lat.get('average', float('nan'))
-
+ result[ph]['rx']['max_delay_usec'] = cast_integer(
+ lat['total_max']) if 'total_max' in lat else float('nan')
+ result[ph]['rx']['min_delay_usec'] = cast_integer(
+ lat['total_min']) if 'total_min' in lat else float('nan')
+ result[ph]['rx']['avg_delay_usec'] = cast_integer(
+ lat['average']) if 'average' in lat else float('nan')
total_tx_pkts = result[0]['tx']['total_pkts'] + result[1]['tx']['total_pkts']
- result["total_tx_rate"] = total_tx_pkts / self.config.duration_sec
+ result["total_tx_rate"] = cast_integer(total_tx_pkts / self.config.duration_sec)
return result
def __combine_stats(self, in_stats, port_handle):
def __combine_latencies(self, in_stats, port_handle):
"""Traverses TRex result dictionary and combines chosen latency stats."""
- if not len(self.latencies[port_handle]):
+ if not self.latencies[port_handle]:
return {}
result = defaultdict(float)
return result
def create_pkt(self, stream_cfg, l2frame_size):
- # 46 = 14 (Ethernet II) + 4 (CRC Checksum) + 20 (IPv4) + 8 (UDP)
- payload = 'x' * (max(64, int(l2frame_size)) - 46)
pkt_base = Ether(src=stream_cfg['mac_src'], dst=stream_cfg['mac_dst'])
-
if stream_cfg['vlan_tag'] is not None:
+ # 50 = 14 (Ethernet II) + 4 (Vlan tag) + 4 (CRC Checksum) + 20 (IPv4) + 8 (UDP)
pkt_base /= Dot1Q(vlan=stream_cfg['vlan_tag'])
-
- pkt_base /= IP() / UDP()
+ l2payload_size = int(l2frame_size) - 50
+ else:
+ # 46 = 14 (Ethernet II) + 4 (CRC Checksum) + 20 (IPv4) + 8 (UDP)
+ l2payload_size = int(l2frame_size) - 46
+ payload = 'x' * l2payload_size
+ udp_args = {}
+ if stream_cfg['udp_src_port']:
+ udp_args['sport'] = int(stream_cfg['udp_src_port'])
+ if stream_cfg['udp_dst_port']:
+ udp_args['dport'] = int(stream_cfg['udp_dst_port'])
+ pkt_base /= IP() / UDP(**udp_args)
if stream_cfg['ip_addrs_step'] == 'random':
src_fv = STLVmFlowVarRepetableRandom(
idx_lat = None
streams = []
if l2frame == 'IMIX':
+ min_size = 64 if stream_cfg['vlan_tag'] is None else 68
+ self.adjust_imix_min_size(min_size)
for t, (ratio, l2_frame_size) in enumerate(zip(self.imix_ratios, self.imix_l2_sizes)):
pkt = self.create_pkt(stream_cfg, l2_frame_size)
streams.append(STLStream(packet=pkt,
if os.path.isfile(logpath):
# Wait for TRex to finish writing error message
last_size = 0
- for it in xrange(self.config.generic_retry_count):
+ for _ in xrange(self.config.generic_retry_count):
size = os.path.getsize(logpath)
if size == last_size:
# probably not writing anymore
def __start_server(self):
server = TRexTrafficServer()
- server.run_server(self.config.generator_config)
+ server.run_server(self.config.generator_config, self.config.vlan_tagging)
def resolve_arp(self):
self.client.set_service_mode(ports=self.port_handle)
if len(self.arps[port]) == self.config.service_chain_count:
resolved += 1
- LOG.info('ARP resolved successfully for port {}'.format(port))
+ LOG.info('ARP resolved successfully for port %s', port)
break
else:
failed = [arp.get_record().dst_ip for arp in arps
if arp.get_record().dst_mac is None]
- LOG.info('Retrying ARP for: {} ({} / {})'.format(
- failed, attempt, self.config.generic_retry_count))
+ LOG.info('Retrying ARP for: %s (%d / %d)',
+ failed, attempt, self.config.generic_retry_count)
time.sleep(self.config.generic_poll_sec)
self.client.set_service_mode(ports=self.port_handle, enabled=False)
stream_cfgs = [d.get_stream_configs(self.config.generator_config.service_chain)
for d in self.config.generator_config.devices]
- self.rates = map(lambda rate: utils.to_rate_str(rate), rates)
+ self.rates = [utils.to_rate_str(rate) for rate in rates]
for ph in self.port_handle:
# generate one pg_id for each direction
for ph in self.port_handle:
self.client.add_streams(self.streamblock[ph], ports=ph)
- LOG.info('Created traffic stream for port %s.' % ph)
-
- def modify_rate(self, rate, reverse):
- port_index = int(reverse)
- port = self.port_handle[port_index]
- self.rates[port_index] = utils.to_rate_str(rate)
- LOG.info('Modified traffic stream for %s, new rate=%s.' % (port, utils.to_rate_str(rate)))
+ LOG.info('Created traffic stream for port %s.', ph)
def clear_streamblock(self):
self.streamblock = defaultdict(list)
def stop_traffic(self):
self.client.stop(ports=self.port_handle)
+ def start_capture(self):
+ if self.capture_id:
+ self.stop_capture()
+ self.client.set_service_mode(ports=self.port_handle)
+ self.capture_id = self.client.start_capture(rx_ports=self.port_handle)
+
+ def fetch_capture_packets(self):
+ if self.capture_id:
+ self.packet_list = []
+ self.client.fetch_capture_packets(capture_id=self.capture_id['id'],
+ output=self.packet_list)
+
+ def stop_capture(self):
+ if self.capture_id:
+ self.client.stop_capture(capture_id=self.capture_id['id'])
+ self.capture_id = None
+ self.client.set_service_mode(ports=self.port_handle, enabled=False)
+
def cleanup(self):
if self.client:
try: