import random
import time
import traceback
+from functools import reduce
from itertools import count
# pylint: disable=import-error
from nfvbench.utils import timeout
from nfvbench.utils import TimeoutError
+from hdrh.histogram import HdrHistogram
+
# pylint: disable=import-error
from trex.common.services.trex_service_arp import ServiceARP
from trex.stl.api import bind_layers
from trex.stl.api import STLStream
from trex.stl.api import STLTXCont
from trex.stl.api import STLVmFixChecksumHw
+from trex.stl.api import STLVmFixIpv4
from trex.stl.api import STLVmFlowVar
from trex.stl.api import STLVmFlowVarRepeatableRandom
from trex.stl.api import STLVmWrFlowVar
self.rates = []
self.capture_id = None
self.packet_list = []
+ self.l2_frame_size = 0
def get_version(self):
"""Get the Trex version."""
pg_id = port * TRex.PORT_PG_ID_MASK | chain_id
return pg_id, pg_id | TRex.LATENCY_PG_ID_MASK
- def extract_stats(self, in_stats):
+ def extract_stats(self, in_stats, ifstats):
"""Extract stats from dict returned by Trex API.
:param in_stats: dict as returned by TRex api
total_tx_pkts = result[0]['tx']['total_pkts'] + result[1]['tx']['total_pkts']
result["total_tx_rate"] = cast_integer(total_tx_pkts / self.config.duration_sec)
+ # actual offered tx rate in bps
+ avg_packet_size = utils.get_average_packet_size(self.l2_frame_size)
+ total_tx_bps = utils.pps_to_bps(result["total_tx_rate"], avg_packet_size)
+ result['offered_tx_rate_bps'] = total_tx_bps
result["flow_stats"] = in_stats["flow_stats"]
result["latency"] = in_stats["latency"]
+
+ # Merge HDRHistogram to have an overall value for all chains and ports
+ try:
+ hdrh_list = []
+ if ifstats:
+ for chain_id, _ in enumerate(ifstats):
+ for ph in self.port_handle:
+ _, lat_pg_id = self.get_pg_id(ph, chain_id)
+ hdrh_list.append(
+ HdrHistogram.decode(in_stats['latency'][lat_pg_id]['latency']['hdrh']))
+ else:
+ for pg_id in in_stats['latency']:
+ if pg_id != 'global':
+ hdrh_list.append(
+ HdrHistogram.decode(in_stats['latency'][pg_id]['latency']['hdrh']))
+
+ def add_hdrh(x, y):
+ x.add(y)
+ return x
+ decoded_hdrh = reduce(add_hdrh, hdrh_list)
+ result["hdrh"] = HdrHistogram.encode(decoded_hdrh).decode('utf-8')
+ except KeyError:
+ pass
+
return result
def get_stream_stats(self, trex_stats, if_stats, latencies, chain_idx):
udp_args = {}
if stream_cfg['udp_src_port']:
udp_args['sport'] = int(stream_cfg['udp_src_port'])
- udp_args['sport_step'] = int(stream_cfg['udp_port_step'])
+ if stream_cfg['udp_port_step'] == 'random':
+ step = 1
+ else:
+ step = stream_cfg['udp_port_step']
+ udp_args['sport_step'] = int(step)
udp_args['sport_max'] = int(stream_cfg['udp_src_port_max'])
if stream_cfg['udp_dst_port']:
udp_args['dport'] = int(stream_cfg['udp_dst_port'])
- udp_args['dport_step'] = int(stream_cfg['udp_port_step'])
+ if stream_cfg['udp_port_step'] == 'random':
+ step = 1
+ else:
+ step = stream_cfg['udp_port_step']
+ udp_args['dport_step'] = int(step)
udp_args['dport_max'] = int(stream_cfg['udp_dst_port_max'])
pkt_base /= IP(src=stream_cfg['ip_src_addr'], dst=stream_cfg['ip_dst_addr']) / \
max_value=udp_args['sport_max'],
size=2,
seed=random.randint(0, 32767),
- limit=udp_args['udp_src_count'])
+ limit=stream_cfg['udp_src_count'])
dst_fv_port = STLVmFlowVarRepeatableRandom(
name="p_dst",
min_value=udp_args['dport'],
dst_fv_port,
STLVmWrFlowVar(fv_name="p_dst", pkt_offset="UDP:{}.dport".format(encap_level)),
]
- for encap in range(int(encap_level), -1, -1):
- vm_param.append(STLVmFixChecksumHw(l3_offset="IP:{}".format(encap),
- l4_offset="UDP:{}".format(encap),
- l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP))
+ # Use HW Offload to calculate the outter IP/UDP packet
+ vm_param.append(STLVmFixChecksumHw(l3_offset="IP:0",
+ l4_offset="UDP:0",
+ l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP))
+ # Use software to fix the inner IP/UDP payload for VxLAN packets
+ if int(encap_level):
+ vm_param.append(STLVmFixIpv4(offset="IP:1"))
pad = max(0, frame_size - len(pkt_base)) * 'x'
return STLPktBuilder(pkt=pkt_base / pad,
if server_ip == '127.0.0.1':
self.__start_local_server()
else:
- raise TrafficGeneratorException(e.message)
+ raise TrafficGeneratorException(e.message) from e
ports = list(self.generator_config.ports)
self.port_handle = ports
message = f.read()
else:
message = e.message
- raise TrafficGeneratorException(message)
+ raise TrafficGeneratorException(message) from e
def __start_server(self):
server = TRexTrafficServer()
.format(pps=r['rate_pps'],
bps=r['rate_bps'],
load=r['rate_percent']))
+ self.l2_frame_size = l2frame_size
# a dict of list of streams indexed by port#
# in case of fixed size, has self.chain_count * 2 * 2 streams
# (1 normal + 1 latency stream per direction per chain)
self.client.reset(self.port_handle)
LOG.info('Cleared all existing streams')
- def get_stats(self):
+ def get_stats(self, if_stats=None):
"""Get stats from Trex."""
stats = self.client.get_stats()
- return self.extract_stats(stats)
+ return self.extract_stats(stats, if_stats)
def get_macs(self):
"""Return the Trex local port MAC addresses.