def __restart(self): LOG.info("Restarting TRex ...") self.__stop_server() # Wait for server stopped for _ in xrange(self.config.generic_retry_count): time.sleep(1) if not self.client.is_connected(): LOG.info("TRex is stopped...") break self.__start_local_server()
def modify_rate(self, rate, reverse): """Change the rate per port. rate: new rate in % (0 to 100) reverse: 0 for port 0, 1 for port 1 """ port_index = int(reverse) port = self.port_handle[port_index] self.rates[port_index] = traffic_utils.to_rate_str(rate) LOG.info('Modified traffic stream for port %s, new rate=%s.', port, self.rates[port_index])
def create_traffic(self, l2frame_size, rates, bidirectional, latency=True, e2e=False): """Program all the streams in Trex server. l2frame_size: L2 frame size or IMIX rates: a list of 2 rates to run each direction each rate is a dict like {'rate_pps': '10kpps'} bidirectional: True if bidirectional latency: True if latency measurement is needed """ r = self.__is_rate_enough(l2frame_size, rates, bidirectional, latency) if not r['result']: raise TrafficGeneratorException( 'Required rate in total is at least one of: \n{pps}pps \n{bps}bps \n{load}%.' .format(pps=r['rate_pps'], bps=r['rate_bps'], load=r['rate_percent'])) # 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) # for IMIX, has self.chain_count * 2 * 4 streams # (3 normal + 1 latency stream per direction per chain) streamblock = {} for port in self.port_handle: streamblock[port] = [] stream_cfgs = [ d.get_stream_configs() for d in self.generator_config.devices ] self.rates = [utils.to_rate_str(rate) for rate in rates] for chain_id, (fwd_stream_cfg, rev_stream_cfg) in enumerate(zip(*stream_cfgs)): streamblock[0].extend( self.generate_streams(self.port_handle[0], chain_id, fwd_stream_cfg, l2frame_size, latency=latency, e2e=e2e)) if len(self.rates) > 1: streamblock[1].extend( self.generate_streams(self.port_handle[1], chain_id, rev_stream_cfg, l2frame_size, latency=bidirectional and latency, e2e=e2e)) for port in self.port_handle: self.client.add_streams(streamblock[port], ports=port) LOG.info('Created %d traffic streams for port %s.', len(streamblock[port]), port)
def resolve_arp(self): """Resolve ARP sucessfully.""" def get_macs(port, scc): return [ '00:00:00:00:%02x:%02x' % (port, chain) for chain in range(scc) ] scc = self.traffic_client.generator_config.service_chain_count res = [get_macs(port, scc) for port in range(2)] LOG.info('Dummy TG ARP: %s', str(res)) return res
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): try: time.sleep(1) self.client.connect() break except Exception as ex: if it == (self.config.generic_retry_count - 1): raise LOG.info("Retrying connection to TRex (%s)...", ex.message)
def __stop_server(self): if self.generator_config.ip == '127.0.0.1': ports = self.client.get_acquired_ports() LOG.info('Release ports %s and stopping TRex...', ports) try: if ports: self.client.release(ports=ports) self.client.server_shutdown() except STLError as e: LOG.warn('Unable to stop TRex. Error: %s', e) else: LOG.info('Using remote TRex. Unable to stop TRex')
def connect(self): """Connect to the TRex server.""" server_ip = self.generator_config.ip LOG.info("Connecting to TRex (%s)...", server_ip) # Connect to TRex server self.client = STLClient(server=server_ip, sync_port=self.generator_config.zmq_rpc_port, async_port=self.generator_config.zmq_pub_port) try: self.__connect(self.client) if server_ip == '127.0.0.1': config_updated = self.__check_config() if config_updated or self.config.restart: self.__restart() except (TimeoutError, STLError) as e: if server_ip == '127.0.0.1': self.__start_local_server() else: raise TrafficGeneratorException(e.message) ports = list(self.generator_config.ports) self.port_handle = ports # Prepare the ports self.client.reset(ports) # Read HW information from each port # this returns an array of dict (1 per port) """ Example of output for Intel XL710 [{'arp': '-', 'src_ipv4': '-', u'supp_speeds': [40000], u'is_link_supported': True, 'grat_arp': 'off', 'speed': 40, u'index': 0, 'link_change_supported': 'yes', u'rx': {u'counters': 127, u'caps': [u'flow_stats', u'latency']}, u'is_virtual': 'no', 'prom': 'off', 'src_mac': u'3c:fd:fe:a8:24:48', 'status': 'IDLE', u'description': u'Ethernet Controller XL710 for 40GbE QSFP+', 'dest': u'fa:16:3e:3c:63:04', u'is_fc_supported': False, 'vlan': '-', u'driver': u'net_i40e', 'led_change_supported': 'yes', 'rx_filter_mode': 'hardware match', 'fc': 'none', 'link': 'UP', u'hw_mac': u'3c:fd:fe:a8:24:48', u'pci_addr': u'0000:5e:00.0', 'mult': 'off', 'fc_supported': 'no', u'is_led_supported': True, 'rx_queue': 'off', 'layer_mode': 'Ethernet', u'numa': 0}, ...] """ self.port_info = self.client.get_port_info(ports) LOG.info('Connected to TRex') for id, port in enumerate(self.port_info): LOG.info(' Port %d: %s speed=%dGbps mac=%s pci=%s driver=%s', id, port['description'], port['speed'], port['src_mac'], port['pci_addr'], port['driver']) # Make sure the 2 ports have the same speed if self.port_info[0]['speed'] != self.port_info[1]['speed']: raise TrafficGeneratorException('Traffic generator ports speed mismatch: %d/%d Gbps' % (self.port_info[0]['speed'], self.port_info[1]['speed']))
def __start_local_server(self): try: LOG.info("Starting TRex ...") self.__start_server() self.__connect_after_start() except (TimeoutError, STLError) as e: LOG.error('Cannot connect to TRex') LOG.error(traceback.format_exc()) logpath = '/tmp/trex.log' if os.path.isfile(logpath): # Wait for TRex to finish writing error message last_size = 0 for _ in xrange(self.config.generic_retry_count): size = os.path.getsize(logpath) if size == last_size: # probably not writing anymore break last_size = size time.sleep(1) with open(logpath, 'r') as f: message = f.read() else: message = e.message raise TrafficGeneratorException(message)
def clear_streamblock(self): """Clear all streams from TRex.""" self.rates = [] self.client.reset(self.port_handle) LOG.info('Cleared all existing streams')
def resolve_arp(self): """Resolve all configured remote IP addresses. return: None if ARP failed to resolve for all IP addresses else a dict of list of dest macs indexed by port# the dest macs in the list are indexed by the chain id """ self.client.set_service_mode(ports=self.port_handle) LOG.info('Polling ARP until successful...') arp_dest_macs = {} for port, device in zip(self.port_handle, self.generator_config.devices): # there should be 1 stream config per chain stream_configs = device.get_stream_configs() chain_count = len(stream_configs) ctx = self.client.create_service_ctx(port=port) # all dest macs on this port indexed by chain ID dst_macs = [None] * chain_count dst_macs_count = 0 # the index in the list is the chain id if self.config.vxlan: arps = [ ServiceARP(ctx, src_ip=device.vtep_src_ip, dst_ip=device.vtep_dst_ip, vlan=device.vtep_vlan) for cfg in stream_configs ] else: arps = [ ServiceARP(ctx, src_ip=cfg['ip_src_tg_gw'], dst_ip=cfg['mac_discovery_gw'], # will be None if no vlan tagging vlan=cfg['vlan_tag']) for cfg in stream_configs ] for attempt in range(self.config.generic_retry_count): try: ctx.run(arps) except STLError: LOG.error(traceback.format_exc()) continue unresolved = [] for chain_id, mac in enumerate(dst_macs): if not mac: arp_record = arps[chain_id].get_record() if arp_record.dst_mac: dst_macs[chain_id] = arp_record.dst_mac dst_macs_count += 1 LOG.info(' ARP: port=%d chain=%d src IP=%s dst IP=%s -> MAC=%s', port, chain_id, arp_record.src_ip, arp_record.dst_ip, arp_record.dst_mac) else: unresolved.append(arp_record.dst_ip) if dst_macs_count == chain_count: 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) else: LOG.error('ARP timed out for port %s (resolved %d out of %d)', port, dst_macs_count, chain_count) break 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
def connect(self): """Connect to the TRex server.""" server_ip = self.generator_config.ip LOG.info("Connecting to TRex (%s)...", server_ip) # Connect to TRex server self.client = STLClient(server=server_ip) try: self.__connect(self.client) except (TimeoutError, STLError) as e: if server_ip == '127.0.0.1': try: self.__start_server() self.__connect_after_start() except (TimeoutError, STLError) as e: LOG.error('Cannot connect to TRex') LOG.error(traceback.format_exc()) logpath = '/tmp/trex.log' if os.path.isfile(logpath): # Wait for TRex to finish writing error message last_size = 0 for _ in xrange(self.config.generic_retry_count): size = os.path.getsize(logpath) if size == last_size: # probably not writing anymore break last_size = size time.sleep(1) with open(logpath, 'r') as f: message = f.read() else: message = e.message raise TrafficGeneratorException(message) else: raise TrafficGeneratorException(e.message) ports = list(self.generator_config.ports) self.port_handle = ports # Prepare the ports self.client.reset(ports) # Read HW information from each port # this returns an array of dict (1 per port) """ Example of output for Intel XL710 [{'arp': '-', 'src_ipv4': '-', u'supp_speeds': [40000], u'is_link_supported': True, 'grat_arp': 'off', 'speed': 40, u'index': 0, 'link_change_supported': 'yes', u'rx': {u'counters': 127, u'caps': [u'flow_stats', u'latency']}, u'is_virtual': 'no', 'prom': 'off', 'src_mac': u'3c:fd:fe:a8:24:48', 'status': 'IDLE', u'description': u'Ethernet Controller XL710 for 40GbE QSFP+', 'dest': u'fa:16:3e:3c:63:04', u'is_fc_supported': False, 'vlan': '-', u'driver': u'net_i40e', 'led_change_supported': 'yes', 'rx_filter_mode': 'hardware match', 'fc': 'none', 'link': 'UP', u'hw_mac': u'3c:fd:fe:a8:24:48', u'pci_addr': u'0000:5e:00.0', 'mult': 'off', 'fc_supported': 'no', u'is_led_supported': True, 'rx_queue': 'off', 'layer_mode': 'Ethernet', u'numa': 0}, ...] """ self.port_info = self.client.get_port_info(ports) LOG.info('Connected to TRex') for id, port in enumerate(self.port_info): LOG.info(' Port %d: %s speed=%dGbps mac=%s pci=%s driver=%s', id, port['description'], port['speed'], port['src_mac'], port['pci_addr'], port['driver']) # Make sure the 2 ports have the same speed if self.port_info[0]['speed'] != self.port_info[1]['speed']: raise TrafficGeneratorException( 'Traffic generator ports speed mismatch: %d/%d Gbps' % (self.port_info[0]['speed'], self.port_info[1]['speed']))