diff options
-rw-r--r-- | docs/development/design/traffic_desc.rst | 3 | ||||
-rw-r--r-- | nfvbench/chain_runner.py | 12 | ||||
-rw-r--r-- | nfvbench/nfvbench.py | 17 | ||||
-rw-r--r-- | nfvbench/stats_manager.py | 4 | ||||
-rw-r--r-- | nfvbench/summarizer.py | 6 | ||||
-rw-r--r-- | nfvbench/traffic_gen/traffic_base.py | 14 | ||||
-rw-r--r-- | nfvbench/traffic_gen/traffic_utils.py | 16 | ||||
-rw-r--r-- | nfvbench/traffic_gen/trex.py | 37 |
8 files changed, 54 insertions, 55 deletions
diff --git a/docs/development/design/traffic_desc.rst b/docs/development/design/traffic_desc.rst index 6442013..cd80a1c 100644 --- a/docs/development/design/traffic_desc.rst +++ b/docs/development/design/traffic_desc.rst @@ -23,8 +23,7 @@ The code to create the UDP packet is located in TRex.create_pkt() (nfvbench/traf NFVbench always generates UDP packets (even when doing L2 forwarding). The final size of the frame containing each UDP packet will be based on the requested L2 frame size. When taking into account the minimum payload size requirements from the traffic generator for -the latency streams, the minimum L2 frame size is 64 byte (no vlan tagging) or -68 bytes (with vlan tagging). +the latency streams, the minimum L2 frame size is 64 byte. Flows Specification ------------------- diff --git a/nfvbench/chain_runner.py b/nfvbench/chain_runner.py index c120501..876fec2 100644 --- a/nfvbench/chain_runner.py +++ b/nfvbench/chain_runner.py @@ -90,13 +90,13 @@ class ChainRunner(object): self.traffic_client.ensure_arp_successful() self.traffic_client.ensure_end_to_end() - def __get_result_per_frame_size(self, frame_size, actual_frame_size, bidirectional): + def __get_result_per_frame_size(self, frame_size, bidirectional): traffic_result = { frame_size: {} } result = {} if not self.config.no_traffic: - self.traffic_client.set_traffic(actual_frame_size, bidirectional) + self.traffic_client.set_traffic(frame_size, bidirectional) if self.config.single_run: result = self.stats_manager.run_fixed_rate() @@ -105,9 +105,6 @@ class ChainRunner(object): for dr in ['pdr', 'ndr']: if dr in results: - if frame_size != actual_frame_size: - results[dr]['l2frame_size'] = frame_size - results[dr]['actual_l2frame_size'] = actual_frame_size traffic_result[frame_size][dr] = results[dr] if 'warning' in results[dr]['stats'] and results[dr]['stats']['warning']: traffic_result['warning'] = results[dr]['stats']['warning'] @@ -117,8 +114,6 @@ class ChainRunner(object): result['run_config'] = self.traffic_client.get_run_config(result) required = result['run_config']['direction-total']['orig']['rate_pps'] actual = result['stats']['total_tx_rate'] - if frame_size != actual_frame_size: - result['actual_l2frame_size'] = actual_frame_size warning = self.traffic_client.compare_tx_rates(required, actual) if warning is not None: result['run_config']['warning'] = warning @@ -128,9 +123,8 @@ class ChainRunner(object): def __get_chain_result(self): result = OrderedDict() - for fs, actual_fs in zip(self.config.frame_sizes, self.config.actual_frame_sizes): + for fs in self.config.frame_sizes: result.update(self.__get_result_per_frame_size(fs, - actual_fs, self.config.traffic.bidirectional)) chain_result = { 'flow_count': self.config.flow_count, diff --git a/nfvbench/nfvbench.py b/nfvbench/nfvbench.py index 933d6fa..0d6da7f 100644 --- a/nfvbench/nfvbench.py +++ b/nfvbench/nfvbench.py @@ -90,18 +90,19 @@ class NFVBench(object): self.factory, self.notifier) new_frame_sizes = [] - min_packet_size = "68" if self.config.vlan_tagging else "64" + # make sure that the min frame size is 64 + min_packet_size = 64 for frame_size in self.config.frame_sizes: try: - if int(frame_size) < int(min_packet_size): - new_frame_sizes.append(min_packet_size) - LOG.info("Adjusting frame size %s Bytes to minimum size %s Bytes due to " + - "traffic generator restriction", frame_size, min_packet_size) - else: + if int(frame_size) < min_packet_size: + frame_size = str(min_packet_size) + LOG.info("Adjusting frame size %s bytes to minimum size %s bytes", + frame_size, min_packet_size) + if frame_size not in new_frame_sizes: new_frame_sizes.append(frame_size) except ValueError: - new_frame_sizes.append(frame_size) - self.config.actual_frame_sizes = tuple(new_frame_sizes) + new_frame_sizes.append(frame_size.upper()) + self.config.frame_sizes = new_frame_sizes result = { "date": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "nfvbench_version": __version__, diff --git a/nfvbench/stats_manager.py b/nfvbench/stats_manager.py index a1fb497..98ac413 100644 --- a/nfvbench/stats_manager.py +++ b/nfvbench/stats_manager.py @@ -73,9 +73,9 @@ class StatsManager(object): def _update_interface_stats(self, diff=False): """Update interface stats for both the traffic generator and the worker.""" - self.traffic_client.update_interface_stats(diff=True) + self.traffic_client.update_interface_stats(diff) if self.worker: - self.worker.update_interface_stats(diff=True) + self.worker.update_interface_stats(diff) def run_fixed_rate(self): """Run a fixed rate and analyze results.""" diff --git a/nfvbench/summarizer.py b/nfvbench/summarizer.py index 0d84ab2..f03d3bc 100644 --- a/nfvbench/summarizer.py +++ b/nfvbench/summarizer.py @@ -350,12 +350,6 @@ class NFVBenchSummarizer(Summarizer): def __chain_analysis_summarize(self, frame_size, analysis): self._put() self._put('L2 frame size:', frame_size) - if 'actual_l2frame_size' in analysis: - self._put('Actual l2 frame size:', analysis['actual_l2frame_size']) - elif self.config['ndr_run'] and 'actual_l2frame_size' in analysis['ndr']: - self._put('Actual l2 frame size:', analysis['ndr']['actual_l2frame_size']) - elif self.config['pdr_run'] and 'actual_l2frame_size' in analysis['pdr']: - self._put('Actual l2 frame size:', analysis['pdr']['actual_l2frame_size']) if self.config['ndr_run']: self._put('NDR search duration:', Formatter.float(0)(analysis['ndr']['time_taken_sec']), 'seconds') diff --git a/nfvbench/traffic_gen/traffic_base.py b/nfvbench/traffic_gen/traffic_base.py index 459af0f..0360591 100644 --- a/nfvbench/traffic_gen/traffic_base.py +++ b/nfvbench/traffic_gen/traffic_base.py @@ -18,6 +18,7 @@ import sys from nfvbench.log import LOG import traffic_utils + class Latency(object): """A class to hold latency data.""" @@ -50,14 +51,11 @@ class TrafficGeneratorException(Exception): class AbstractTrafficGenerator(object): + def __init__(self, traffic_client): self.traffic_client = traffic_client self.generator_config = traffic_client.generator_config self.config = traffic_client.config - self.imix_l2_sizes = [64, 594, 1518] - self.imix_ratios = [7, 4, 1] - self.imix_avg_l2_size = 0 - self.adjust_imix_min_size(64) @abc.abstractmethod def get_version(self): @@ -134,11 +132,3 @@ class AbstractTrafficGenerator(object): return: a list of speed in Gbps indexed by the port# """ pass - - def adjust_imix_min_size(self, min_size): - # assume the min size is always the first entry - self.imix_l2_sizes[0] = min_size - self.imix_avg_l2_size = sum( - [1.0 * imix[0] * imix[1] for imix in zip(self.imix_l2_sizes, self.imix_ratios)]) / sum( - self.imix_ratios) - traffic_utils.imix_avg_l2_size = self.imix_avg_l2_size diff --git a/nfvbench/traffic_gen/traffic_utils.py b/nfvbench/traffic_gen/traffic_utils.py index c3428a4..f856267 100644 --- a/nfvbench/traffic_gen/traffic_utils.py +++ b/nfvbench/traffic_gen/traffic_utils.py @@ -16,13 +16,18 @@ import bitmath from nfvbench.utils import multiplier_map -imix_avg_l2_size = None +# IMIX frame size including the 4-byte FCS field +IMIX_L2_SIZES = [64, 594, 1518] +IMIX_RATIOS = [7, 4, 1] +# weighted average l2 frame size includng the 4-byte FCS +IMIX_AVG_L2_FRAME_SIZE = sum( + [1.0 * imix[0] * imix[1] for imix in zip(IMIX_L2_SIZES, IMIX_RATIOS)]) / sum(IMIX_RATIOS) def convert_rates(l2frame_size, rate, intf_speed): """Convert a given rate unit into the other rate units. - l2frame_size: size of the L2 frame in bytes or 'IMIX' + l2frame_size: size of the L2 frame in bytes (includes 32-bit FCS) or 'IMIX' rate: a dict that has at least one of the following key: 'rate_pps', 'rate_bps', 'rate_percent' with the corresponding input value @@ -59,8 +64,13 @@ def convert_rates(l2frame_size, rate, intf_speed): def get_average_packet_size(l2frame_size): + """Retrieve the average L2 frame size + + l2frame_size: an L2 frame size in bytes (including FCS) or 'IMIX' + return: average l2 frame size inlcuding the 32-bit FCS + """ if l2frame_size.upper() == 'IMIX': - return imix_avg_l2_size + return IMIX_AVG_L2_FRAME_SIZE return float(l2frame_size) diff --git a/nfvbench/traffic_gen/trex.py b/nfvbench/traffic_gen/trex.py index 6aec57d..6bb0c34 100644 --- a/nfvbench/traffic_gen/trex.py +++ b/nfvbench/traffic_gen/trex.py @@ -27,6 +27,9 @@ from nfvbench.utils import TimeoutError from traffic_base import AbstractTrafficGenerator from traffic_base import TrafficGeneratorException import traffic_utils as utils +from traffic_utils import IMIX_AVG_L2_FRAME_SIZE +from traffic_utils import IMIX_L2_SIZES +from traffic_utils import IMIX_RATIOS # pylint: disable=import-error from trex_stl_lib.api import CTRexVmInsFixHwCs @@ -245,15 +248,17 @@ class TRex(AbstractTrafficGenerator): results['avg_delay_usec'] = int(average / self.chain_count) def _create_pkt(self, stream_cfg, l2frame_size): + """Create a packet of given size. + + l2frame_size: size of the L2 frame in bytes (including the 32-bit FCS) + """ + # Trex will add the FCS field, so we need to remove 4 bytes from the l2 frame size + frame_size = int(l2frame_size) - 4 + 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']) @@ -301,8 +306,9 @@ class TRex(AbstractTrafficGenerator): l4_offset="UDP", l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP) ] + pad = max(0, frame_size - len(pkt_base)) * 'x' - return STLPktBuilder(pkt=pkt_base / payload, vm=STLScVmRaw(vm_param)) + return STLPktBuilder(pkt=pkt_base / pad, vm=STLScVmRaw(vm_param)) def generate_streams(self, port, chain_id, stream_cfg, l2frame, latency=True): """Create a list of streams corresponding to a given chain and stream config. @@ -310,15 +316,13 @@ class TRex(AbstractTrafficGenerator): port: port where the streams originate (0 or 1) chain_id: the chain to which the streams are associated to stream_cfg: stream configuration - l2frame: L2 frame size + l2frame: L2 frame size (including 4-byte FCS) or 'IMIX' latency: if True also create a latency stream """ streams = [] pg_id, lat_pg_id = self.get_pg_id(port, chain_id) if l2frame == 'IMIX': - min_size = 64 if stream_cfg['vlan_tag'] is None else 68 - self.adjust_imix_min_size(min_size) - for ratio, l2_frame_size in zip(self.imix_ratios, self.imix_l2_sizes): + for ratio, l2_frame_size in zip(IMIX_RATIOS, IMIX_L2_SIZES): pkt = self._create_pkt(stream_cfg, l2_frame_size) streams.append(STLStream(packet=pkt, flow_stats=STLFlowStats(pg_id=pg_id), @@ -326,13 +330,20 @@ class TRex(AbstractTrafficGenerator): if latency: # for IMIX, the latency packets have the average IMIX packet size - pkt = self._create_pkt(stream_cfg, self.imix_avg_l2_size) + pkt = self._create_pkt(stream_cfg, IMIX_AVG_L2_FRAME_SIZE) else: - pkt = self._create_pkt(stream_cfg, l2frame) + l2frame_size = int(l2frame) + pkt = self._create_pkt(stream_cfg, l2frame_size) streams.append(STLStream(packet=pkt, flow_stats=STLFlowStats(pg_id=pg_id), mode=STLTXCont())) + # for the latency stream, the minimum payload is 16 bytes even in case of vlan tagging + # without vlan, the min l2 frame size is 64 + # with vlan it is 68 + # This only applies to the latency stream + if latency and stream_cfg['vlan_tag'] and l2frame_size < 68: + pkt = self._create_pkt(stream_cfg, 68) if latency: streams.append(STLStream(packet=pkt, |