class TrexTest(BaseTest): """ Base test for setting up and tearing down TRex client instance for linerate tests. """ def setUp(self): super(TrexTest, self).setUp() trex_server_addr = testutils.test_param_get("trex_server_addr") self.trex_client = STLClient(server=trex_server_addr) self.trex_client.connect() self.trex_client.acquire() self.trex_client.reset() # Resets configs from all ports self.trex_client.clear_stats() # Clear status from all ports # Put all ports to promiscuous mode, otherwise they will drop all # incoming packets if the destination mac is not the port mac address. self.trex_client.set_port_attr(self.trex_client.get_all_ports(), promiscuous=True) def tearDown(self): print("Tearing down STLClient...") self.trex_client.stop() self.trex_client.release() self.trex_client.disconnect() super(TrexTest, self).tearDown()
def main() -> int: # Initialize the argument parser and subparsers # First we initialize general arguments. parser = argparse.ArgumentParser(description="Linerate test control plane") parser.add_argument( "--server-addr", type=str, help="The server address", default="127.0.0.1", required=False, ) parser.add_argument( "--trex-config", type=str, help="The Trex config to be placed on the server.", required=True, ) parser.add_argument( "--keep-running", action="store_true", default=False, help="Keep Trex running after the test.", ) parser.add_argument( "--force-restart", action="store_true", default=False, help="Force restart the Trex process " + "if there is one running.", ) # Second, we initialize subparsers from all test scripts subparsers = parser.add_subparsers( dest="test", help="The test profile, which is the " + "filename(without .py) in the test directory", required=True, ) test_py_list = glob.glob(join(dirname(__file__), "tests", "*.py")) test_list = [ basename(f)[:-3] for f in test_py_list if isfile(f) and not f.endswith("__init__.py") ] for test in test_list: test_class = get_test_class(test) if not test_class: continue test_parser = subparsers.add_parser(test) test_class.setup_subparser(test_parser) # Finally, we get the arguments args = parser.parse_args() # Set up the Trex server if not os.path.exists(args.trex_config): logging.error("Can not find Trex config file: %s", args.trex_config) return if not os.path.isfile(args.trex_config): logging.error("%s is not a file", args.trex_config) return 1 trex_config_file_on_server = TREX_FILES_DIR + os.path.basename( args.trex_config) trex_daemon_client = CTRexClient(args.server_addr) trex_started = False try: logging.info("Pushing Trex config %s to the server", args.trex_config) if not trex_daemon_client.push_files(args.trex_config): logging.error("Unable to push %s to Trex server", args.trex_config) return 1 if args.force_restart: logging.info("Killing all Trexes... with meteorite... Boom!") trex_daemon_client.kill_all_trexes() # Wait until Trex enter the Idle state start_time = time.time() success = False while time.time() - start_time < DEFAULT_KILL_TIMEOUT: if trex_daemon_client.is_idle(): success = True break time.sleep(1) if not success: logging.error("Unable to kill Trex process, please login " + "to the server and kill it manually.") return 1 if not trex_daemon_client.is_idle(): logging.info("The Trex server process is running") logging.warning("A Trex server process is still running, " + "use --force-restart to kill it if necessary.") return 1 test_class = get_test_class(args.test) if not test_class: logging.error("Unable to get test class for test %s", args.test) return 1 test_type = test_class.test_type() logging.info("Starting Trex with %s mode", test_class.test_type()) try: start_trex_function = getattr(trex_daemon_client, "start_{}".format(test_type)) except AttributeError: logging.error("Unkonwon test type %s", test_type) return 1 # Not checking the return value from this # call since it always return True start_trex_function(cfg=trex_config_file_on_server) trex_started = True # Start the test if test_type == "stateless": trex_client = STLClient(server=args.server_addr) elif test_type == "astf": trex_client = ASTFClient(server=args.server_addr) else: logging.error("Unknown test type %s", test_type) return 1 test = test_class(trex_client) try: logging.info("Connecting to Trex server...") trex_client.connect() logging.info("Acquaring ports...") trex_client.acquire() logging.info("Resetting and clearing port...") trex_client.reset() # Resets configs from all ports trex_client.clear_stats() # Clear status from all ports logging.info("Running the test: %s...", test) test.start(args) except STLError as e: logging.error("Got error from Trex server: %s", e) return 1 finally: logging.info("Cleaning up Trex client") trex_client.stop() trex_client.release() trex_client.disconnect() except ConnectionRefusedError: logging.error( "Unable to connect to server %s.\n" + "Did you start the Trex daemon?", args.server_addr, ) return 1 except ProtocolError as pe: logging.error("%s", pe) return 1 except TRexError as te: logging.error("TRex error: %s", te.msg) return 1 except TRexInUseError as tiue: logging.error("TRex is already taken: %s", tiue.msg) return 1 except TRexRequestDenied as trd: logging.error("Request denied: %s", trd.msg) return 1 finally: if trex_started and not args.keep_running: logging.info("Stopping Trex server") trex_daemon_client.stop_trex()
class TRex(TrafficGeneratorChassis): def __init__(self, **kwargs): super(TRex, self).__init__(**kwargs) self.hostname = kwargs.pop("hostname", "localhost") self.__trex_client = STLClient(server=self.hostname) def _verify_port_action(self, port_name): if self.is_connected() and self._verify_port_string(port_name) and \ port_name in self.port_data: return (True) return (False) def _verify_port_string(self, port_name): try: if int(port_name) < 0: return False except ValueError: return False return True def connect(self): if not self.is_connected(): self.__trex_client.connect() return self.is_connected() def disconnect(self): if self.is_connected: for port in list(self.port_data.keys()): self.port_data[port] = self.release_port(port) self.__trex_client.disconnect() return True def is_connected(self): return self.__trex_client.is_connected() def reserve_port(self, port_name): if not self._verify_port_string(port_name): return False try: self.__trex_client.acquire(ports=[int(port_name)], force=True) except STLError: return False try: self.__trex_client.reset(ports=[int(port_name)]) except STLError: self.__trex_client.release(ports=[int(port_name)]) return False tport = _TRexPort(port_name, self.__trex_client) if tport is None: return False return super(TRex, self).reserve_port(port_name, tport) def release_port(self, port_name): if not self._verify_port_string(port_name) or \ port_name not in self.port_data: return False try: self.__trex_client.release(ports=[port_name]) except STLError: pass return super(TRex, self).release_port(port_name) # # FIXME: All the port specific functions should be re factored to use the # base class so the shared code in _xena and _trex can be removed. # def clear_statistics(self, port_name): if self._verify_port_action(port_name): self.port_data[port_name].clear_statistics() def take_tx_statistics_snapshot(self, port_name): if self._verify_port_action(port_name): self.port_data[port_name].take_tx_statistics_snapshot() def take_rx_statistics_snapshot(self, port_name): if self._verify_port_action(port_name): self.port_data[port_name].take_rx_statistics_snapshot() def get_tx_statistics_snapshots(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].get_tx_statistics_snapshots() return None def get_rx_statistics_snapshots(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].get_rx_statistics_snapshots() return None def start_traffic(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].start_traffic() return False def stop_traffic(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].stop_traffic() return False def configure_traffic_stream(self, port_name, traffic_flows, nr_of_flows, packet_size, **kwargs): if self._verify_port_action(port_name): return self.port_data[port_name].configure_traffic_stream( traffic_flows, nr_of_flows, packet_size, **kwargs) return False def next_traffic_stream(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].next_traffic_stream() return False def get_port_limits(self, port_name): if self._verify_port_action(port_name): return self.port_data[port_name].get_port_limits() return dict()
def main(): """Stop traffic if any is running. Report xstats.""" parser = argparse.ArgumentParser() parser.add_argument(u"--xstat0", type=str, default=u"", help=u"Reference xstat object if any.") parser.add_argument(u"--xstat1", type=str, default=u"", help=u"Reference xstat object if any.") args = parser.parse_args() client = STLClient() try: # connect to server client.connect() client.acquire(force=True) # TODO: Support unidirection. client.stop(ports=[0, 1]) # Read the stats after the test, # we need to update values before the last trial started. if args.xstat0: snapshot = eval(args.xstat0) client.ports[0].get_xstats().reference_stats = snapshot if args.xstat1: snapshot = eval(args.xstat1) client.ports[1].get_xstats().reference_stats = snapshot # Now we can call the official method to get differences. xstats0 = client.get_xstats(0) xstats1 = client.get_xstats(1) # If STLError happens, let the script fail with stack trace. finally: client.disconnect() print(u"##### statistics port 0 #####") print(json.dumps(xstats0, indent=4, separators=(u",", u": "))) print(u"##### statistics port 1 #####") print(json.dumps(xstats1, indent=4, separators=(u",", u": "))) tx_0, rx_0 = xstats0[u"tx_good_packets"], xstats0[u"rx_good_packets"] tx_1, rx_1 = xstats1[u"tx_good_packets"], xstats1[u"rx_good_packets"] lost_a, lost_b = tx_0 - rx_1, tx_1 - rx_0 print(f"\npackets lost from 0 --> 1: {lost_a} pkts") print(f"packets lost from 1 --> 0: {lost_b} pkts") total_rcvd, total_sent = rx_0 + rx_1, tx_0 + tx_1 total_lost = total_sent - total_rcvd print(f"rate='unknown'; " f"total_received={total_rcvd}; " f"total_sent={total_sent}; " f"frame_loss={total_lost}; " f"target_duration='manual'; " f"approximated_duration='manual'; " f"approximated_rate='unknown'; " f"latency_stream_0(usec)=-1/-1/-1; " f"latency_stream_1(usec)=-1/-1/-1; ")