aboutsummaryrefslogtreecommitdiffstats
path: root/nfvbench/traffic_gen/trex.py
diff options
context:
space:
mode:
Diffstat (limited to 'nfvbench/traffic_gen/trex.py')
-rw-r--r--nfvbench/traffic_gen/trex.py93
1 files changed, 61 insertions, 32 deletions
diff --git a/nfvbench/traffic_gen/trex.py b/nfvbench/traffic_gen/trex.py
index 23faebc..cabf1cb 100644
--- a/nfvbench/traffic_gen/trex.py
+++ b/nfvbench/traffic_gen/trex.py
@@ -48,6 +48,8 @@ from trex_stl_lib.api import STLVmFlowVarRepetableRandom
from trex_stl_lib.api import STLVmWrFlowVar
from trex_stl_lib.api import UDP
from trex_stl_lib.services.trex_stl_service_arp import STLServiceARP
+
+
# pylint: enable=import-error
@@ -64,31 +66,42 @@ class TRex(AbstractTrafficGenerator):
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()
def extract_stats(self, in_stats):
+ """Extract stats from dict returned by Trex API.
+
+ :param in_stats: dict as returned by TRex api
+ """
utils.nan_replace(in_stats)
LOG.debug(in_stats)
result = {}
+ # port_handles should have only 2 elements: [0, 1]
+ # so (1 - ph) will be the index for the far end port
for ph in self.port_handle:
- stats = self.__combine_stats(in_stats, ph)
+ stats = in_stats[ph]
+ far_end_stats = in_stats[1 - ph]
result[ph] = {
'tx': {
- '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'])
+ 'total_pkts': cast_integer(stats['opackets']),
+ 'total_pkt_bytes': cast_integer(stats['obytes']),
+ 'pkt_rate': cast_integer(stats['tx_pps']),
+ 'pkt_bit_rate': cast_integer(stats['tx_bps'])
},
'rx': {
- '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']),
+ 'total_pkts': cast_integer(stats['ipackets']),
+ 'total_pkt_bytes': cast_integer(stats['ibytes']),
+ 'pkt_rate': cast_integer(stats['rx_pps']),
+ 'pkt_bit_rate': cast_integer(stats['rx_bps']),
+ # how many pkts were dropped in RX direction
+ # need to take the tx counter on the far end port
'dropped_pkts': cast_integer(
- stats['tx_pkts']['total'] - stats['rx_pkts']['total'])
+ far_end_stats['opackets'] - stats['ipackets'])
}
}
@@ -103,20 +116,6 @@ class TRex(AbstractTrafficGenerator):
result["total_tx_rate"] = cast_integer(total_tx_pkts / self.config.duration_sec)
return result
- def __combine_stats(self, in_stats, port_handle):
- """Traverses TRex result dictionary and combines stream stats. Used for combining latency
- and regular streams together.
- """
- result = defaultdict(lambda: defaultdict(float))
-
- for pg_id in [self.stream_ids[port_handle]] + self.latencies[port_handle]:
- record = in_stats['flow_stats'][pg_id]
- for stat_type, stat_type_values in record.iteritems():
- for ph, value in stat_type_values.iteritems():
- result[stat_type][ph] += value
-
- return result
-
def __combine_latencies(self, in_stats, port_handle):
"""Traverses TRex result dictionary and combines chosen latency stats."""
if not self.latencies[port_handle]:
@@ -136,14 +135,16 @@ class TRex(AbstractTrafficGenerator):
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'])
-
+ 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'])
@@ -198,6 +199,8 @@ class TRex(AbstractTrafficGenerator):
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,
@@ -208,6 +211,7 @@ class TRex(AbstractTrafficGenerator):
if latency:
idx_lat = self.id.next()
+ pkt = self.create_pkt(stream_cfg, self.imix_avg_l2_size)
sl = STLStream(packet=pkt,
isg=isg,
flow_stats=STLFlowLatencyStats(pg_id=idx_lat),
@@ -247,7 +251,7 @@ class TRex(AbstractTrafficGenerator):
break
except Exception as ex:
if it == (self.config.generic_retry_count - 1):
- raise ex
+ raise
LOG.info("Retrying connection to TRex (%s)...", ex.message)
def connect(self):
@@ -318,7 +322,7 @@ class TRex(AbstractTrafficGenerator):
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)
@@ -354,7 +358,7 @@ class TRex(AbstractTrafficGenerator):
else:
failed = [arp.get_record().dst_ip for arp in arps
if arp.get_record().dst_mac is None]
- LOG.info('Retrying ARP for: %d (%d / %d)',
+ LOG.info('Retrying ARP for: %s (%d / %d)',
failed, attempt, self.config.generic_retry_count)
time.sleep(self.config.generic_poll_sec)
@@ -433,7 +437,7 @@ class TRex(AbstractTrafficGenerator):
LOG.info('Cleared all existing streams.')
def get_stats(self):
- stats = self.client.get_pgid_stats()
+ stats = self.client.get_stats()
return self.extract_stats(stats)
def get_macs(self):
@@ -450,6 +454,31 @@ class TRex(AbstractTrafficGenerator):
def stop_traffic(self):
self.client.stop(ports=self.port_handle)
+ def start_capture(self):
+ """Capture all packets on both ports that are unicast to us."""
+ if self.capture_id:
+ self.stop_capture()
+ # Need to filter out unwanted packets so we do not end up counting
+ # src MACs of frames that are not unicast to us
+ src_mac_list = self.get_macs()
+ bpf_filter = "ether dst %s or ether dst %s" % (src_mac_list[0], src_mac_list[1])
+ # ports must be set in service in order to enable capture
+ self.client.set_service_mode(ports=self.port_handle)
+ self.capture_id = self.client.start_capture(rx_ports=self.port_handle,
+ bpf_filter=bpf_filter)
+
+ 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: