X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=nfvbench%2Ftraffic_gen%2Ftrex_gen.py;h=af70cdea1e7da837b938a78e1680b9bd48d556e5;hb=423f360415e2834dd8de065434023b822e2ca3f8;hp=036c89976bc0166a648490181c53fc2b19afa782;hpb=108a9f65ed0792ccb427e081ef3068002443983e;p=nfvbench.git diff --git a/nfvbench/traffic_gen/trex_gen.py b/nfvbench/traffic_gen/trex_gen.py index 036c899..af70cde 100644 --- a/nfvbench/traffic_gen/trex_gen.py +++ b/nfvbench/traffic_gen/trex_gen.py @@ -20,17 +20,14 @@ import time import traceback from itertools import count +# pylint: disable=import-error +from scapy.contrib.mpls import MPLS # flake8: noqa +# pylint: enable=import-error from nfvbench.log import LOG from nfvbench.traffic_server import TRexTrafficServer from nfvbench.utils import cast_integer from nfvbench.utils import timeout 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.common.services.trex_service_arp import ServiceARP @@ -57,9 +54,15 @@ from trex.stl.api import ThreeBytesField from trex.stl.api import UDP from trex.stl.api import XByteField - # pylint: enable=import-error +from .traffic_base import AbstractTrafficGenerator +from .traffic_base import TrafficGeneratorException +from . 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 + class VXLAN(Packet): """VxLAN class.""" @@ -363,6 +366,17 @@ class TRex(AbstractTrafficGenerator): op="random") vm_param = [vxlan_udp_src_fv, STLVmWrFlowVar(fv_name="vxlan_udp_src", pkt_offset="UDP.sport")] + elif stream_cfg['mpls'] is True: + encap_level = '0' + pkt_base = Ether(src=stream_cfg['vtep_src_mac'], dst=stream_cfg['vtep_dst_mac']) + if stream_cfg['vtep_vlan'] is not None: + pkt_base /= Dot1Q(vlan=stream_cfg['vtep_vlan']) + if stream_cfg['mpls_outer_label'] is not None: + pkt_base /= MPLS(label=stream_cfg['mpls_outer_label'], cos=1, s=0, ttl=255) + if stream_cfg['mpls_inner_label'] is not None: + pkt_base /= MPLS(label=stream_cfg['mpls_inner_label'], cos=1, s=1, ttl=255) + # Flow stats and MPLS labels randomization TBD + pkt_base /= Ether(src=stream_cfg['mac_src'], dst=stream_cfg['mac_dst']) else: encap_level = '0' pkt_base = Ether(src=stream_cfg['mac_src'], dst=stream_cfg['mac_dst']) @@ -422,7 +436,8 @@ class TRex(AbstractTrafficGenerator): l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP)) pad = max(0, frame_size - len(pkt_base)) * 'x' - return STLPktBuilder(pkt=pkt_base / pad, vm=STLScVmRaw(vm_param)) + return STLPktBuilder(pkt=pkt_base / pad, + vm=STLScVmRaw(vm_param, cache_size=int(self.config.cache_size))) def generate_streams(self, port, chain_id, stream_cfg, l2frame, latency=True, e2e=False): @@ -437,21 +452,25 @@ class TRex(AbstractTrafficGenerator): """ streams = [] pg_id, lat_pg_id = self.get_pg_id(port, chain_id) + if self.config.no_flow_stats: + LOG.info("Traffic flow statistics are disabled.") if l2frame == 'IMIX': for ratio, l2_frame_size in zip(IMIX_RATIOS, IMIX_L2_SIZES): pkt = self._create_pkt(stream_cfg, l2_frame_size) - if e2e: + if e2e or stream_cfg['mpls']: streams.append(STLStream(packet=pkt, mode=STLTXCont(pps=ratio))) else: if stream_cfg['vxlan'] is True: streams.append(STLStream(packet=pkt, flow_stats=STLFlowStats(pg_id=pg_id, - vxlan=True), + vxlan=True) + if not self.config.no_flow_stats else None, mode=STLTXCont(pps=ratio))) else: streams.append(STLStream(packet=pkt, - flow_stats=STLFlowStats(pg_id=pg_id), + flow_stats=STLFlowStats(pg_id=pg_id) + if not self.config.no_flow_stats else None, mode=STLTXCont(pps=ratio))) if latency: @@ -461,18 +480,22 @@ class TRex(AbstractTrafficGenerator): else: l2frame_size = int(l2frame) pkt = self._create_pkt(stream_cfg, l2frame_size) - if e2e: + if e2e or stream_cfg['mpls']: streams.append(STLStream(packet=pkt, + # Flow stats is disabled for MPLS now + # flow_stats=STLFlowStats(pg_id=pg_id), mode=STLTXCont())) else: if stream_cfg['vxlan'] is True: streams.append(STLStream(packet=pkt, flow_stats=STLFlowStats(pg_id=pg_id, - vxlan=True), + vxlan=True) + if not self.config.no_flow_stats else None, mode=STLTXCont())) else: streams.append(STLStream(packet=pkt, - flow_stats=STLFlowStats(pg_id=pg_id), + flow_stats=STLFlowStats(pg_id=pg_id) + if not self.config.no_flow_stats else None, 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 @@ -482,10 +505,19 @@ class TRex(AbstractTrafficGenerator): pkt = self._create_pkt(stream_cfg, 68) if latency: - # TRex limitation: VXLAN skip is not supported for latency stream - streams.append(STLStream(packet=pkt, - flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id), - mode=STLTXCont(pps=self.LATENCY_PPS))) + if self.config.no_latency_stats: + LOG.info("Latency flow statistics are disabled.") + if stream_cfg['vxlan'] is True: + streams.append(STLStream(packet=pkt, + flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id, + vxlan=True) + if not self.config.no_latency_stats else None, + mode=STLTXCont(pps=self.LATENCY_PPS))) + else: + streams.append(STLStream(packet=pkt, + flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id) + if not self.config.no_latency_stats else None, + mode=STLTXCont(pps=self.LATENCY_PPS))) return streams @timeout(5) @@ -495,7 +527,7 @@ class TRex(AbstractTrafficGenerator): def __connect_after_start(self): # after start, Trex may take a bit of time to initialize # so we need to retry a few times - for it in xrange(self.config.generic_retry_count): + for it in range(self.config.generic_retry_count): try: time.sleep(1) self.client.connect() @@ -503,7 +535,7 @@ class TRex(AbstractTrafficGenerator): except Exception as ex: if it == (self.config.generic_retry_count - 1): raise - LOG.info("Retrying connection to TRex (%s)...", ex.message) + LOG.info("Retrying connection to TRex (%s)...", ex.msg) def connect(self): """Connect to the TRex server.""" @@ -568,7 +600,7 @@ class TRex(AbstractTrafficGenerator): if os.path.isfile(logpath): # Wait for TRex to finish writing error message last_size = 0 - for _ in xrange(self.config.generic_retry_count): + for _ in range(self.config.generic_retry_count): size = os.path.getsize(logpath) if size == last_size: # probably not writing anymore @@ -593,7 +625,7 @@ class TRex(AbstractTrafficGenerator): LOG.info("Restarting TRex ...") self.__stop_server() # Wait for server stopped - for _ in xrange(self.config.generic_retry_count): + for _ in range(self.config.generic_retry_count): time.sleep(1) if not self.client.is_connected(): LOG.info("TRex is stopped...") @@ -609,7 +641,7 @@ class TRex(AbstractTrafficGenerator): self.client.release(ports=ports) self.client.server_shutdown() except STLError as e: - LOG.warn('Unable to stop TRex. Error: %s', e) + LOG.warning('Unable to stop TRex. Error: %s', e) else: LOG.info('Using remote TRex. Unable to stop TRex') @@ -632,7 +664,7 @@ class TRex(AbstractTrafficGenerator): dst_macs = [None] * chain_count dst_macs_count = 0 # the index in the list is the chain id - if self.config.vxlan: + if self.config.vxlan or self.config.mpls: arps = [ ServiceARP(ctx, src_ip=device.vtep_src_ip, @@ -674,12 +706,12 @@ class TRex(AbstractTrafficGenerator): arp_dest_macs[port] = dst_macs LOG.info('ARP resolved successfully for port %s', port) break - else: - retry = attempt + 1 - LOG.info('Retrying ARP for: %s (retry %d/%d)', - unresolved, retry, self.config.generic_retry_count) - if retry < self.config.generic_retry_count: - time.sleep(self.config.generic_poll_sec) + + retry = attempt + 1 + LOG.info('Retrying ARP for: %s (retry %d/%d)', + unresolved, retry, self.config.generic_retry_count) + if retry < self.config.generic_retry_count: + time.sleep(self.config.generic_poll_sec) else: LOG.error('ARP timed out for port %s (resolved %d out of %d)', port, @@ -687,7 +719,10 @@ class TRex(AbstractTrafficGenerator): chain_count) break - self.client.set_service_mode(ports=self.port_handle, enabled=False) + # if the capture from the TRex console was started before the arp request step, + # it keeps 'service_mode' enabled, otherwise, it disables the 'service_mode' + if not self.config.service_mode: + self.client.set_service_mode(ports=self.port_handle, enabled=False) if len(arp_dest_macs) == len(self.port_handle): return arp_dest_macs return None @@ -829,7 +864,10 @@ class TRex(AbstractTrafficGenerator): 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) + # if the capture from TRex console was started before the connectivity step, + # it keeps 'service_mode' enabled, otherwise, it disables the 'service_mode' + if not self.config.service_mode: + self.client.set_service_mode(ports=self.port_handle, enabled=False) def cleanup(self): """Cleanup Trex driver.""" @@ -840,3 +878,7 @@ class TRex(AbstractTrafficGenerator): except STLError: # TRex does not like a reset while in disconnected state pass + + def set_service_mode(self, enabled=True): + """Enable/disable the 'service_mode'.""" + self.client.set_service_mode(ports=self.port_handle, enabled=enabled)