diff options
57 files changed, 1474 insertions, 424 deletions
diff --git a/linux/ws_main.py b/linux/ws_main.py index 2a0d7286..79e26915 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -103,6 +103,7 @@ bp_sim_gtest = SrcGroup(dir='src', main_src = SrcGroup(dir='src', src_list=[ + 'inet_pton.cpp', 'bp_sim.cpp', 'os_time.cpp', 'rx_check.cpp', diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index 0a2c9dfa..0a6ff7c1 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -106,6 +106,7 @@ def getstatusoutput(cmd): main_src = SrcGroup(dir='src', src_list=[ + 'bp_sim.cpp', 'utl_term_io.cpp', 'global_io_mode.cpp', 'main_dpdk.cpp', @@ -114,7 +115,7 @@ main_src = SrcGroup(dir='src', 'debug.cpp', 'flow_stat.cpp', 'flow_stat_parser.cpp', - 'bp_sim.cpp', + 'inet_pton.cpp', 'pkt_gen.cpp', 'platform_cfg.cpp', 'pre_test.cpp', diff --git a/scripts/automation/regression/CPlatform.py b/scripts/automation/regression/CPlatform.py index bc9d3c4b..0017e7db 100755 --- a/scripts/automation/regression/CPlatform.py +++ b/scripts/automation/regression/CPlatform.py @@ -520,18 +520,18 @@ class CPlatform(object): p1 = 'p'+str(idx), p2 = 'p'+str(idx+1) ) ) # config global arp to interfaces net address and vrf - if dual_if.client_if.get_dest_mac(): + if dual_if.client_if.get_ipv6_dest_mac(): conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format( mode = unconfig_str, next_hop = server_net_next_hop, intf = dual_if.client_if.get_name(), - dest_mac = dual_if.client_if.get_dest_mac())) - if dual_if.server_if.get_dest_mac(): + dest_mac = dual_if.client_if.get_ipv6_dest_mac())) + if dual_if.server_if.get_ipv6_dest_mac(): conf_t_command_set.append('{mode}ipv6 neighbor {next_hop} {intf} {dest_mac}'.format( mode = unconfig_str, next_hop = client_net_next_hop, intf = dual_if.server_if.get_name(), - dest_mac = dual_if.server_if.get_dest_mac())) + dest_mac = dual_if.server_if.get_ipv6_dest_mac())) conf_t_command_set.append('{mode}route-map {pre}_{p1}_to_{p2} permit 10'.format( mode = unconfig_str, diff --git a/scripts/automation/regression/functional_tests/cpp_gtests_test.py b/scripts/automation/regression/functional_tests/cpp_gtests_test.py new file mode 100644 index 00000000..6535da84 --- /dev/null +++ b/scripts/automation/regression/functional_tests/cpp_gtests_test.py @@ -0,0 +1,46 @@ +import outer_packages +from nose.plugins.attrib import attr +import functional_general_test +from trex import CTRexScenario +import os, sys +from subprocess import Popen, STDOUT +import shlex +import time +import errno +import tempfile + +# runs command +def run_command(command, timeout = 15, poll_rate = 0.1, cwd = None): + # pipes might stuck, even with timeout + with tempfile.TemporaryFile() as stdout_file: + proc = Popen(shlex.split(command), stdout = stdout_file, stderr = STDOUT, cwd = cwd, close_fds = True, universal_newlines = True) + if timeout > 0: + for i in range(int(timeout/poll_rate)): + time.sleep(poll_rate) + if proc.poll() is not None: # process stopped + break + if proc.poll() is None: + proc.kill() # timeout + stdout_file.seek(0) + return (errno.ETIME, '%s\n\n...Timeout of %s second(s) is reached!' % (stdout_file.read().decode(errors = 'replace'), timeout)) + else: + proc.wait() + stdout_file.seek(0) + return (proc.returncode, stdout_file.read().decode(errors = 'replace')) + +@attr('run_on_trex') +class CPP_Test(functional_general_test.CGeneralFunctional_Test): + def test_gtests_all(self): + print('') + bp_sim = os.path.join(CTRexScenario.scripts_path, 'bp-sim-64') + ret, out = run_command('%s --ut' % bp_sim, cwd = CTRexScenario.scripts_path) + print('Output:\n%s' % out) + if ret: + raise Exception('Non zero return status of gtests (%s)' % ret) + + def test_gtests_valgrind(self): + print('') + ret, out = run_command(os.path.join(CTRexScenario.scripts_path, 'run-gtest-clean'), cwd = CTRexScenario.scripts_path) + print('Output:\n%s' % out) + if ret: + raise Exception('Non zero return status of Valgrind gtests (%s)' % ret) diff --git a/scripts/automation/regression/functional_tests/platform_dual_if_obj_test.py b/scripts/automation/regression/functional_tests/platform_dual_if_obj_test.py index d848b466..a97a3305 100755 --- a/scripts/automation/regression/functional_tests/platform_dual_if_obj_test.py +++ b/scripts/automation/regression/functional_tests/platform_dual_if_obj_test.py @@ -9,10 +9,10 @@ from nose.tools import assert_not_equal class CDualIfObj_Test(functional_general_test.CGeneralFunctional_Test): def setUp(self): - self.if_1 = CIfObj('gig0/0/1', '1.1.1.1', '2001:DB8:0:2222:0:0:0:1', '0000.0001.0000', '0000.0001.0000', IFType.Client) - self.if_2 = CIfObj('gig0/0/2', '1.1.2.1', '2001:DB8:1:2222:0:0:0:1', '0000.0002.0000', '0000.0002.0000', IFType.Server) - self.if_3 = CIfObj('gig0/0/3', '1.1.3.1', '2001:DB8:2:2222:0:0:0:1', '0000.0003.0000', '0000.0003.0000', IFType.Client) - self.if_4 = CIfObj('gig0/0/4', '1.1.4.1', '2001:DB8:3:2222:0:0:0:1', '0000.0004.0000', '0000.0004.0000', IFType.Server) + self.if_1 = CIfObj('gig0/0/1', '1.1.1.1', '2001:DB8:0:2222:0:0:0:1', '0000.0001.0000', '0000.0001.0000', 0, IFType.Client) + self.if_2 = CIfObj('gig0/0/2', '1.1.2.1', '2001:DB8:1:2222:0:0:0:1', '0000.0002.0000', '0000.0002.0000', 0, IFType.Server) + self.if_3 = CIfObj('gig0/0/3', '1.1.3.1', '2001:DB8:2:2222:0:0:0:1', '0000.0003.0000', '0000.0003.0000', 0, IFType.Client) + self.if_4 = CIfObj('gig0/0/4', '1.1.4.1', '2001:DB8:3:2222:0:0:0:1', '0000.0004.0000', '0000.0004.0000', 0, IFType.Server) self.dual_1 = CDualIfObj(None, self.if_1, self.if_2) self.dual_2 = CDualIfObj('dup', self.if_3, self.if_4) @@ -28,4 +28,4 @@ class CDualIfObj_Test(functional_general_test.CGeneralFunctional_Test): assert_equal ( self.dual_2.is_duplicated() , True ) def tearDown(self): - pass
\ No newline at end of file + pass diff --git a/scripts/automation/regression/functional_tests/platform_if_obj_test.py b/scripts/automation/regression/functional_tests/platform_if_obj_test.py index 534d4170..2412d3cc 100755 --- a/scripts/automation/regression/functional_tests/platform_if_obj_test.py +++ b/scripts/automation/regression/functional_tests/platform_if_obj_test.py @@ -10,8 +10,8 @@ class CIfObj_Test(functional_general_test.CGeneralFunctional_Test): test_idx = 1 def setUp(self): - self.if_1 = CIfObj('gig0/0/1', '1.1.1.1', '2001:DB8:0:2222:0:0:0:1', '0000.0001.0000', '0000.0001.0000', IFType.Client) - self.if_2 = CIfObj('TenGig0/0/0', '1.1.2.1', '2001:DB8:1:2222:0:0:0:1', '0000.0002.0000', '0000.0002.0000', IFType.Server) + self.if_1 = CIfObj('gig0/0/1', '1.1.1.1', '2001:DB8:0:2222:0:0:0:1', '0000.0001.0000', '0000.0001.0000', 0, IFType.Client) + self.if_2 = CIfObj('TenGig0/0/0', '1.1.2.1', '2001:DB8:1:2222:0:0:0:1', '0000.0002.0000', '0000.0002.0000', 0, IFType.Server) CIfObj_Test.test_idx += 1 def test_id_allocation(self): diff --git a/scripts/automation/regression/platform_cmd_link.py b/scripts/automation/regression/platform_cmd_link.py index 8162e29d..275da656 100755 --- a/scripts/automation/regression/platform_cmd_link.py +++ b/scripts/automation/regression/platform_cmd_link.py @@ -189,12 +189,13 @@ class CDeviceCfg(object): class CIfObj(object): _obj_id = 0 - def __init__(self, if_name, ipv4_addr, ipv6_addr, src_mac_addr, dest_mac_addr, if_type): + def __init__(self, if_name, ipv4_addr, ipv6_addr, src_mac_addr, dest_mac_addr, dest_ipv6_mac_addr, if_type): self.__get_and_increment_id() self.if_name = if_name self.if_type = if_type self.src_mac_addr = src_mac_addr self.dest_mac_addr = dest_mac_addr + self.dest_ipv6_mac_addr = dest_ipv6_mac_addr self.ipv4_addr = ipv4_addr self.ipv6_addr = ipv6_addr self.pair_parent = None # a pointer to CDualIfObj which holds this interface and its pair-complement @@ -212,6 +213,12 @@ class CIfObj(object): def get_dest_mac (self): return self.dest_mac_addr + def get_ipv6_dest_mac (self): + if self.dest_mac_addr != 0: + return self.dest_mac_addr + else: + return self.dest_ipv6_mac_addr + def get_id (self): return self._obj_id @@ -312,11 +319,16 @@ class CIfManager(object): client_dest_mac = intf_pair['client']['dest_mac_addr'] else: client_dest_mac = 0 + if 'dest_ipv6_mac_addr' in intf_pair['client']: + client_dest_ipv6_mac = intf_pair['client']['dest_ipv6_mac_addr'] + else: + client_dest_ipv6_mac = 0 client_obj = CIfObj(if_name = intf_pair['client']['name'], ipv4_addr = tmp_ipv4_addr, ipv6_addr = tmp_ipv6_addr, src_mac_addr = intf_pair['client']['src_mac_addr'], dest_mac_addr = client_dest_mac, + dest_ipv6_mac_addr = client_dest_ipv6_mac, if_type = IFType.Client) # generate network addresses for server side, and initialize server if object @@ -327,11 +339,16 @@ class CIfManager(object): server_dest_mac = intf_pair['server']['dest_mac_addr'] else: server_dest_mac = 0 + if 'dest_ipv6_mac_addr' in intf_pair['server']: + server_dest_ipv6_mac = intf_pair['server']['dest_ipv6_mac_addr'] + else: + server_dest_ipv6_mac = 0 server_obj = CIfObj(if_name = intf_pair['server']['name'], ipv4_addr = tmp_ipv4_addr, ipv6_addr = tmp_ipv6_addr, src_mac_addr = intf_pair['server']['src_mac_addr'], dest_mac_addr = server_dest_mac, + dest_ipv6_mac_addr = server_dest_ipv6_mac, if_type = IFType.Server) dual_intf_obj = CDualIfObj(vrf_name = intf_pair['vrf_name'], diff --git a/scripts/automation/regression/setups/trex-dan/config.yaml b/scripts/automation/regression/setups/trex-dan/config.yaml index be972001..d147502f 100644 --- a/scripts/automation/regression/setups/trex-dan/config.yaml +++ b/scripts/automation/regression/setups/trex-dan/config.yaml @@ -54,11 +54,11 @@ router: - client : name : GigabitEthernet0/0/1 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 server : name : GigabitEthernet0/0/2 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 vrf_name : null tftp: diff --git a/scripts/automation/regression/setups/trex25/config.yaml b/scripts/automation/regression/setups/trex25/config.yaml index ac19f170..c4b3743d 100644 --- a/scripts/automation/regression/setups/trex25/config.yaml +++ b/scripts/automation/regression/setups/trex25/config.yaml @@ -52,38 +52,38 @@ router: - client : name : GigabitEthernet0/1/0 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 server : name : GigabitEthernet0/1/1 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 vrf_name : - client : name : GigabitEthernet0/1/2 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 server : name : GigabitEthernet0/1/4 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 vrf_name : - client : name : GigabitEthernet0/1/5 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 server : name : GigabitEthernet0/1/3 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 vrf_name : - client : name : GigabitEthernet0/1/6 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 server : name : GigabitEthernet0/1/7 src_mac_addr : 0000.0001.0000 -# dest_mac_addr : 0000.0001.0000 + dest_ipv6_mac_addr : 0000.0001.0000 vrf_name : tftp: diff --git a/scripts/automation/regression/stateful_tests/trex_general_test.py b/scripts/automation/regression/stateful_tests/trex_general_test.py index 968eea1c..e968d380 100755 --- a/scripts/automation/regression/stateful_tests/trex_general_test.py +++ b/scripts/automation/regression/stateful_tests/trex_general_test.py @@ -175,10 +175,11 @@ class CTRexGeneral_Test(unittest.TestCase): # report benchmarks if self.GAManager: try: - setup_test = '%s.%s' % (CTRexScenario.setup_name, self.get_name()) - self.GAManager.gaAddAction(Event = 'stateful_test', action = setup_test, label = 'bw_per_core', value = int(test_norm_cpu)) - self.GAManager.gaAddAction(Event = 'stateful_test', action = setup_test, label = 'bw_per_core_exp', value = int(expected_norm_cpu)) - self.GAManager.emptyAndReportQ() + pass + #setup_test = '%s.%s' % (CTRexScenario.setup_name, self.get_name()) + #self.GAManager.gaAddAction(Event = 'stateful_test', action = setup_test, label = 'bw_per_core', value = int(test_norm_cpu)) + #self.GAManager.gaAddAction(Event = 'stateful_test', action = setup_test, label = 'bw_per_core_exp', value = int(expected_norm_cpu)) + #self.GAManager.emptyAndReportQ() except Exception as e: print('Sending GA failed: %s' % e) diff --git a/scripts/automation/regression/stateful_tests/trex_ipv6_test.py b/scripts/automation/regression/stateful_tests/trex_ipv6_test.py index b03de0b4..4d6f7953 100755 --- a/scripts/automation/regression/stateful_tests/trex_ipv6_test.py +++ b/scripts/automation/regression/stateful_tests/trex_ipv6_test.py @@ -29,6 +29,7 @@ class CTRexIPv6_Test(CTRexGeneral_Test): core = self.get_benchmark_param('cores') ret = self.trex.start_trex( + cfg = '/etc/trex_cfg_mac.yaml', c = core, m = mult, p = True, @@ -66,6 +67,7 @@ class CTRexIPv6_Test(CTRexGeneral_Test): core = self.get_benchmark_param('cores', test_name = 'test_ipv6_simple') ret = self.trex.start_trex( + cfg = '/etc/trex_cfg_mac.yaml', c = core, m = mult, p = True, diff --git a/scripts/automation/regression/stateful_tests/trex_rx_test.py b/scripts/automation/regression/stateful_tests/trex_rx_test.py index 6c6c535a..161856b1 100755 --- a/scripts/automation/regression/stateful_tests/trex_rx_test.py +++ b/scripts/automation/regression/stateful_tests/trex_rx_test.py @@ -165,6 +165,7 @@ class CTRexRx_Test(CTRexGeneral_Test): sample_rate = self.get_benchmark_param('rx_sample_rate') ret = self.trex.start_trex( + cfg = '/etc/trex_cfg_mac.yaml', c = core, m = mult, p = True, @@ -199,6 +200,7 @@ class CTRexRx_Test(CTRexGeneral_Test): sample_rate = self.get_benchmark_param('rx_sample_rate') ret = self.trex.start_trex( + cfg = '/etc/trex_cfg_mac.yaml', c = core, m = mult, p = True, diff --git a/scripts/automation/regression/stateless_tests/stl_benchmark_test.py b/scripts/automation/regression/stateless_tests/stl_benchmark_test.py index bbdf2d30..6940efd3 100755 --- a/scripts/automation/regression/stateless_tests/stl_benchmark_test.py +++ b/scripts/automation/regression/stateless_tests/stl_benchmark_test.py @@ -54,15 +54,16 @@ class STLBenchmark_Test(CStlGeneral_Test): # report benchmarks if self.GAManager: try: - profile_repr = '%s.%s %s' % (CTRexScenario.setup_name, - os.path.basename(profile_bench['name']), - repr(kwargs).replace("'", '')) - self.GAManager.gaAddAction(Event = 'stateless_test', action = profile_repr, - label = 'bw_per_core', value = int(agv_bw_per_core)) + pass + #profile_repr = '%s.%s %s' % (CTRexScenario.setup_name, + # os.path.basename(profile_bench['name']), + # repr(kwargs).replace("'", '')) + #self.GAManager.gaAddAction(Event = 'stateless_test', action = profile_repr, + # label = 'bw_per_core', value = int(agv_bw_per_core)) # TODO: report expected once acquired #self.GAManager.gaAddAction(Event = 'stateless_test', action = profile_repr, # label = 'bw_per_core_exp', value = int(expected_norm_cpu)) - self.GAManager.emptyAndReportQ() + #self.GAManager.emptyAndReportQ() except Exception as e: print('Sending GA failed: %s' % e) diff --git a/scripts/automation/regression/stateless_tests/stl_general_test.py b/scripts/automation/regression/stateless_tests/stl_general_test.py index a5fb905e..590733ba 100644 --- a/scripts/automation/regression/stateless_tests/stl_general_test.py +++ b/scripts/automation/regression/stateless_tests/stl_general_test.py @@ -10,7 +10,7 @@ class CStlGeneral_Test(CTRexGeneral_Test): """This class defines the general stateless testcase of the TRex traffic generator""" def setUp(self): - self.stl_trex = CTRexScenario.stl_trex + self.stl_trex = CTRexScenario.stl_trex if CTRexScenario.stl_trex else 'mock' CTRexGeneral_Test.setUp(self) # check basic requirements, should be verified at test_connectivity, here only skip test if CTRexScenario.stl_init_error: @@ -67,15 +67,40 @@ class STLBasic_Test(CStlGeneral_Test): def test_connectivity(self): if not self.is_loopback: try: + sys.stdout.flush() + sys.stdout.write('Configuring DUT... ') + start_time = time.time() if CTRexScenario.router_cfg['forceCleanConfig']: CTRexScenario.router.load_clean_config() CTRexScenario.router.configure_basic_interfaces() CTRexScenario.router.config_pbr(mode = "config") CTRexScenario.router.config_ipv6_pbr(mode = "config") + sys.stdout.write('done. (%ss)\n' % int(time.time() - start_time)) except Exception as e: + print('') CTRexScenario.stl_init_error = 'Could not configure device, err: %s' % e self.fail(CTRexScenario.stl_init_error) return + + try: + sys.stdout.write('Starting TRex... ') + start_time = time.time() + cores = self.configuration.trex.get('trex_cores', 1) + if self.is_virt_nics and cores > 1: + raise Exception('Number of cores should be 1 with virtual NICs') + if not CTRexScenario.no_daemon: + self.trex.start_stateless(c = cores) + self.stl_trex = STLClient(username = 'TRexRegression', + server = self.configuration.trex['trex_name'], + verbose_level = CTRexScenario.json_verbose) + CTRexScenario.stl_trex = self.stl_trex + sys.stdout.write('done. (%ss)\n' % int(time.time() - start_time)) + except Exception as e: + print('') + CTRexScenario.stl_init_error = 'Could not start stateless TRex, err: %s' % e + self.fail(CTRexScenario.stl_init_error) + return + if not self.connect(): CTRexScenario.stl_init_error = 'Client could not connect' self.fail(CTRexScenario.stl_init_error) diff --git a/scripts/automation/regression/stateless_tests/stl_performance_test.py b/scripts/automation/regression/stateless_tests/stl_performance_test.py index ac39ee6b..62a1912f 100644 --- a/scripts/automation/regression/stateless_tests/stl_performance_test.py +++ b/scripts/automation/regression/stateless_tests/stl_performance_test.py @@ -54,12 +54,25 @@ class PerformanceReport(object): return self.GOLDEN_NORMAL + def report_to_analytics(self, ga, golden_mpps): + print("\n* Reporting to GA *\n") + ga.gaAddTestQuery(TestName = self.scenario, + TRexMode = 'stl', + SetupName = self.machine_name, + TestType = 'performance', + Mppspc = self.avg_mpps_per_core, + ActionNumber = '<fill_me>', + GoldenMin = golden_mpps['min'], + GoldenMax = golden_mpps['max']) + + ga.emptyAndReportQ() class STLPerformance_Test(CStlGeneral_Test): """Tests for stateless client""" def setUp(self): + CStlGeneral_Test.setUp(self) self.c = CTRexScenario.stl_trex @@ -233,7 +246,10 @@ class STLPerformance_Test(CStlGeneral_Test): report = self.execute_single_scenario_iteration(scenario_cfg) rc = report.check_golden(golden) - if rc == PerformanceReport.GOLDEN_NORMAL: + if (rc == PerformanceReport.GOLDEN_NORMAL) or (rc == PerformanceReport.GOLDEN_BETTER): + if self.GAManager: + report.report_to_analytics(self.GAManager, golden) + return if rc == PerformanceReport.GOLDEN_BETTER: @@ -315,7 +331,7 @@ class STLPerformance_Test(CStlGeneral_Test): avg_mpps_per_core = avg_mpps * (100.0 / avg_cpu) report = PerformanceReport(scenario = scenario_cfg['name'], - machine_name = os.uname()[1], + machine_name = CTRexScenario.setup_name, core_count = scenario_cfg['core_count'], avg_cpu = avg_cpu, avg_gbps = avg_gbps, diff --git a/scripts/automation/regression/trex.py b/scripts/automation/regression/trex.py index aad8f041..7b96f2f8 100644 --- a/scripts/automation/regression/trex.py +++ b/scripts/automation/regression/trex.py @@ -40,6 +40,7 @@ class CTRexScenario: no_daemon = False debug_image = False test = None + json_verbose = False class CTRexRunner: """This is an instance for generating a CTRexRunner""" diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 7c2e317b..7a6c4260 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -39,7 +39,7 @@ from trex import CTRexScenario from trex_stf_lib.trex_client import * from trex_stf_lib.trex_exceptions import * from trex_stl_lib.api import * -from trex_stl_lib.utils.GAObjClass import GAmanager +from trex_stl_lib.utils.GAObjClass import GAmanager_Regression import trex import socket from pprint import pprint @@ -186,6 +186,8 @@ class CTRexTestConfiguringPlugin(Plugin): options.config_path = CTRexScenario.setup_dir if not options.config_path: raise Exception('Please specify path to config.yaml using --cfg parameter or env. variable SETUP_DIR') + options.config_path = options.config_path.rstrip('/') + CTRexScenario.setup_name = os.path.basename(options.config_path) self.configuration = misc_methods.load_complete_config_file(os.path.join(options.config_path, 'config.yaml')) self.configuration.trex['trex_name'] = address_to_ip(self.configuration.trex['trex_name']) # translate hostname to ip self.benchmark = misc_methods.load_benchmark_config_file(os.path.join(options.config_path, 'benchmark.yaml')) @@ -204,6 +206,7 @@ class CTRexTestConfiguringPlugin(Plugin): CTRexScenario.modes = set(self.modes) CTRexScenario.server_logs = self.server_logs CTRexScenario.debug_image = options.debug_image + CTRexScenario.json_verbose = self.json_verbose if not self.no_daemon: CTRexScenario.trex = CTRexClient(trex_host = self.configuration.trex['trex_name'], verbose = self.json_verbose, @@ -213,14 +216,14 @@ class CTRexTestConfiguringPlugin(Plugin): print('Could not connect to master daemon') sys.exit(-1) if options.ga and CTRexScenario.setup_name: - CTRexScenario.GAManager = GAmanager(GoogleID = 'UA-75220362-4', - UserID = CTRexScenario.setup_name, - QueueSize = 100, - Timeout = 5, # seconds - UserPermission = 1, - BlockingMode = 1, - appName = 'TRex', - appVer = '1.11.232') + CTRexScenario.GAManager = GAmanager_Regression(GoogleID = 'UA-75220362-3', + AnalyticsUserID = CTRexScenario.setup_name, + QueueSize = 100, + Timeout = 3, # seconds + UserPermission = 1, + BlockingMode = 0, + appName = 'TRex', + appVer = CTRexScenario.trex_version) def begin (self): @@ -253,15 +256,6 @@ class CTRexTestConfiguringPlugin(Plugin): print('TRex is already running') sys.exit(-1) - if self.stateless: - cores = self.configuration.trex.get('trex_cores', 1) - if 'virt_nics' in self.modes and cores > 1: - raise Exception('Number of cores should be 1 with virtual NICs') - if not self.no_daemon: - client.start_stateless(c = cores) - CTRexScenario.stl_trex = STLClient(username = 'TRexRegression', - server = self.configuration.trex['trex_name'], - verbose_level = self.json_verbose) if 'loopback' not in self.modes: CTRexScenario.router_cfg = dict(config_dict = self.configuration.router, forceImageReload = self.load_image, diff --git a/scripts/automation/trex_control_plane/server/singleton_daemon.py b/scripts/automation/trex_control_plane/server/singleton_daemon.py index cd16d173..507967aa 100755 --- a/scripts/automation/trex_control_plane/server/singleton_daemon.py +++ b/scripts/automation/trex_control_plane/server/singleton_daemon.py @@ -37,6 +37,7 @@ class SingletonDaemon(object): lock_socket.close() except socket.error: # Unix socket in use return True + sleep(0.5) # Unix socket is not used, but maybe it's old version of daemon not using socket return bool(self.get_pid_by_listening_port()) diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py index ecf6083b..e9d2b8a0 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py @@ -1087,7 +1087,9 @@ class CTRexClient(object): """ # handle known exceptions based on known error codes. # if error code is not known, raise ProtocolError - raise exception_handler.gen_exception(err) + exc = exception_handler.gen_exception(err) + exc.__cause__ = None # remove "During handling of the above exception, another exception occurred:" in Python3.3+ + raise exc class CTRexResult(object): diff --git a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_exceptions.py b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_exceptions.py index 0de38411..89134e7f 100755 --- a/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_exceptions.py +++ b/scripts/automation/trex_control_plane/stf/trex_stf_lib/trex_exceptions.py @@ -19,11 +19,12 @@ class RPCError(Exception): def __str__(self): return self.__repr__() + def __repr__(self): if self.args[2] is not None: - return u"[errcode:%r] %r. Extended data: %r" % (self.args[0], self.args[1], self.args[2]) + return u"[errcode:%s] %s. Extended data: %s" % self.args else: - return u"[errcode:%r] %r" % (self.args[0], self.args[1]) + return u"[errcode:%s] %s" % self.args[:2] class TRexException(RPCError): """ diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index 5d23d8da..b23b5f1f 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -230,14 +230,17 @@ class TRexConsole(TRexGeneralCmd): self.save_console_history() lines = line.split(';') - - for line in lines: - stop = self.onecmd(line) - stop = self.postcmd(stop, line) - if stop: - return "quit" - - return "" + try: + for line in lines: + stop = self.onecmd(line) + stop = self.postcmd(stop, line) + if stop: + return "quit" + + return "" + except STLError as e: + print(e) + return '' def postcmd(self, stop, line): @@ -364,7 +367,7 @@ class TRexConsole(TRexGeneralCmd): 'help': "an history item index", 'default': 0}) - parser = parsing_opts.gen_parser(self, + parser = parsing_opts.gen_parser(self.stateless_client, "history", self.do_history.__doc__, item) @@ -551,16 +554,16 @@ class TRexConsole(TRexGeneralCmd): @verify_connected def do_tui (self, line): '''Shows a graphical console\n''' - parser = parsing_opts.gen_parser(self, + parser = parsing_opts.gen_parser(self.stateless_client, "tui", self.do_tui.__doc__, parsing_opts.XTERM, parsing_opts.LOCKED) opts = parser.parse_args(line.split()) - if opts is None: - return + if not opts: + return opts if opts.xterm: if not os.path.exists('/usr/bin/xterm'): print(format_text("XTERM does not exists on this machine", 'bold')) @@ -784,14 +787,18 @@ def show_intro (logger, c): # find out which NICs the server has port_types = {} for port in x['ports']: - key = (port['speed'], port['driver']) - if not key in port_types: + if 'supp_speeds' in port: + speed = max(port['supp_speeds']) // 1000 + else: + speed = port['speed'] + key = (speed, port.get('description', port['driver'])) + if key not in port_types: port_types[key] = 0 port_types[key] += 1 port_line = '' for k, v in port_types.items(): - port_line += "{0} x {1}Gbps @ {2}".format(v, k[0], k[1]) + port_line += "{0} x {1}Gbps @ {2}\t".format(v, k[0], k[1]) logger.log(format_text("\nServer Info:\n", 'underline')) logger.log("Server version: {:>}".format(format_text(ver, 'bold'))) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 82aa932d..80a4c4dc 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -222,18 +222,18 @@ class EventsHandler(object): # dispatcher for server async events (port started, port stopped and etc.) - def on_async_event (self, type, data): + def on_async_event (self, event_type, data): # DP stopped show_event = False # port started - if (type == 0): + if (event_type == 0): port_id = int(data['port_id']) ev = "Port {0} has started".format(port_id) self.__async_event_port_started(port_id) # port stopped - elif (type == 1): + elif (event_type == 1): port_id = int(data['port_id']) ev = "Port {0} has stopped".format(port_id) @@ -242,7 +242,7 @@ class EventsHandler(object): # port paused - elif (type == 2): + elif (event_type == 2): port_id = int(data['port_id']) ev = "Port {0} has paused".format(port_id) @@ -250,7 +250,7 @@ class EventsHandler(object): self.__async_event_port_paused(port_id) # port resumed - elif (type == 3): + elif (event_type == 3): port_id = int(data['port_id']) ev = "Port {0} has resumed".format(port_id) @@ -258,7 +258,7 @@ class EventsHandler(object): self.__async_event_port_resumed(port_id) # port finished traffic - elif (type == 4): + elif (event_type == 4): port_id = int(data['port_id']) ev = "Port {0} job done".format(port_id) @@ -267,7 +267,7 @@ class EventsHandler(object): show_event = True # port was acquired - maybe stolen... - elif (type == 5): + elif (event_type == 5): session_id = data['session_id'] port_id = int(data['port_id']) @@ -297,7 +297,7 @@ class EventsHandler(object): # port was released - elif (type == 6): + elif (event_type == 6): port_id = int(data['port_id']) who = data['who'] session_id = data['session_id'] @@ -315,13 +315,31 @@ class EventsHandler(object): if session_id != self.client.session_id: self.__async_event_port_released(port_id) - elif (type == 7): + elif (event_type == 7): port_id = int(data['port_id']) ev = "port {0} job failed".format(port_id) show_event = True + # port attr changed + elif (event_type == 8): + port_id = int(data['port_id']) + if data['attr'] == self.client.ports[port_id].attr: + return # false alarm + old_info = self.client.ports[port_id].get_info() + self.__async_event_port_attr_changed(port_id, data['attr']) + new_info = self.client.ports[port_id].get_info() + ev = "port {0} attributes changed".format(port_id) + for key, old_val in old_info.items(): + new_val = new_info[key] + if old_val != new_val: + ev += '\n {key}: {old} -> {new}'.format( + key = key, + old = old_val.lower() if type(old_val) is str else old_val, + new = new_val.lower() if type(new_val) is str else new_val) + show_event = True + # server stopped - elif (type == 100): + elif (event_type == 100): ev = "Server has stopped" self.__async_event_server_stopped() show_event = True @@ -372,6 +390,9 @@ class EventsHandler(object): def __async_event_server_stopped (self): self.client.connected = False + def __async_event_port_attr_changed (self, port_id, attr): + if port_id in self.client.ports: + self.client.ports[port_id].async_event_port_attr_changed(attr) # add event to log def __add_event_log (self, origin, ev_type, msg, show = False): @@ -560,11 +581,14 @@ class STLClient(object): self.util_stats = trex_stl_stats.CUtilStats(self) + self.xstats = trex_stl_stats.CXStats(self) + self.stats_generator = trex_stl_stats.CTRexInfoGenerator(self.global_stats, self.ports, self.flow_stats, self.latency_stats, self.util_stats, + self.xstats, self.async_client.monitor) @@ -884,7 +908,7 @@ class STLClient(object): # clear stats - def __clear_stats(self, port_id_list, clear_global, clear_flow_stats, clear_latency_stats): + def __clear_stats(self, port_id_list, clear_global, clear_flow_stats, clear_latency_stats, clear_xstats): # we must be sync with the server self.async_client.barrier() @@ -901,6 +925,9 @@ class STLClient(object): if clear_latency_stats: self.latency_stats.clear_stats() + if clear_xstats: + self.xstats.clear_stats() + self.logger.log_cmd("Clearing stats on port(s) {0}:".format(port_id_list)) return RC @@ -1785,6 +1812,25 @@ class STLClient(object): self.logger.pre_cmd('Getting Utilization stats') return self.util_stats.get_stats() + @__api_check(True) + def get_xstats(self, port_id): + print(port_id) + """ + Get extended stats of port: all the counters as dict. + + :parameters: + port_id: int + + :returns: + Dict with names of counters as keys and values of uint64. Actual keys may vary per NIC. + + :raises: + + :exc:`STLError` + + """ + self.logger.pre_cmd('Getting xstats') + return self.xstats.get_stats(port_id) + @__api_check(True) def reset(self, ports = None): @@ -2004,6 +2050,11 @@ class STLClient(object): validate_type('total', total, bool) validate_type('core_mask', core_mask, (int, list)) + # verify link status + ports_link_down = [port_id for port_id in ports if self.ports[port_id].attr.get('link',{}).get('up') == False] + if not force and ports_link_down: + raise STLError("Port(s) %s - link DOWN - check the connection or specify 'force'" % ports_link_down) + ######################### # decode core mask argument decoded_mask = self.__decode_core_mask(ports, core_mask) @@ -2462,7 +2513,7 @@ class STLClient(object): @__api_check(False) - def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True, clear_latency_stats = True): + def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True, clear_latency_stats = True, clear_xstats = True): """ Clear stats on port(s) @@ -2479,6 +2530,9 @@ class STLClient(object): clear_latency_stats : bool Clear the latency stats + clear_xstats : bool + Clear the extended stats + :raises: + :exc:`STLError` @@ -2491,7 +2545,7 @@ class STLClient(object): if not type(clear_global) is bool: raise STLArgumentError('clear_global', clear_global) - rc = self.__clear_stats(ports, clear_global, clear_flow_stats, clear_latency_stats) + rc = self.__clear_stats(ports, clear_global, clear_flow_stats, clear_latency_stats, clear_xstats) if not rc: raise STLError(rc) @@ -2572,15 +2626,18 @@ class STLClient(object): @__api_check(True) - def set_port_attr (self, ports = None, promiscuous = None): + def set_port_attr (self, ports = None, promiscuous = None, link_up = None, led_on = None, flow_ctrl = None): """ Set port attributes :parameters: promiscuous - True or False + link_up - True or False + led_on - True or False + flow_ctrl - 0: disable all, 1: enable tx side, 2: enable rx side, 3: full enable :raises: - None + + :exe:'STLError' """ @@ -2589,11 +2646,20 @@ class STLClient(object): # check arguments validate_type('promiscuous', promiscuous, (bool, type(None))) + validate_type('link_up', link_up, (bool, type(None))) + validate_type('led_on', led_on, (bool, type(None))) + validate_type('flow_ctrl', flow_ctrl, (int, type(None))) # build attributes attr_dict = {} if promiscuous is not None: - attr_dict['promiscuous'] = {'enabled': bool(promiscuous)} + attr_dict['promiscuous'] = {'enabled': promiscuous} + if link_up is not None: + attr_dict['link_status'] = {'up': link_up} + if led_on is not None: + attr_dict['led_status'] = {'on': led_on} + if flow_ctrl is not None: + attr_dict['flow_ctrl_mode'] = {'mode': flow_ctrl} # no attributes to set if not attr_dict: @@ -3167,20 +3233,39 @@ class STLClient(object): "port_attr", self.set_port_attr_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, - parsing_opts.PROMISCUOUS_SWITCH) + parsing_opts.PROMISCUOUS, + parsing_opts.LINK_STATUS, + parsing_opts.LED_STATUS, + parsing_opts.FLOW_CTRL, + parsing_opts.SUPPORTED, + ) opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True) if not opts: return opts + opts.prom = parsing_opts.ON_OFF_DICT.get(opts.prom) + opts.link = parsing_opts.UP_DOWN_DICT.get(opts.link) + opts.led = parsing_opts.ON_OFF_DICT.get(opts.led) + opts.flow_ctrl = parsing_opts.FLOW_CTRL_DICT.get(opts.flow_ctrl) + # if no attributes - fall back to printing the status - if opts.prom is None: + if not filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp]): self.show_stats_line("--ps --port {0}".format(' '.join(str(port) for port in opts.ports))) return - self.set_port_attr(opts.ports, opts.prom) - return RC_OK() - + if opts.supp: + info = self.ports[0].get_info() # assume for now all ports are same + print('') + print('Supported attributes for current NICs:') + print(' Promiscuous: yes') + print(' Link status: %s' % info['link_change_supported']) + print(' LED status: %s' % info['led_change_supported']) + print(' Flow control: %s' % info['fc_supported']) + print('') + else: + return self.set_port_attr(opts.ports, opts.prom, opts.link, opts.led, opts.flow_ctrl) + @__console def show_profile_line (self, line): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py index 609ea076..1461fcec 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py @@ -182,7 +182,7 @@ class JsonRpcClient(object): tries += 1 if tries > 5: self.disconnect() - return RC_ERR("*** [RPC] - Failed to get server response at {0}".format(self.transport)) + return RC_ERR("*** [RPC] - Failed to get server response from {0}".format(self.transport)) return response diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py index aa002d59..dc06f9fb 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py @@ -738,8 +738,8 @@ class STLVmFlowVarRepetableRandom(CTRexVmDescBase): .. code-block:: python - :caption: Example1 + # Example1 # input , 1 byte or random with limit of 5 STLVmFlowVarRepetableRandom("var1",size=1,limit=5) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index f0e3b109..cec3761f 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -5,6 +5,7 @@ from .trex_stl_packet_builder_scapy import STLPktBuilder from .trex_stl_streams import STLStream from .trex_stl_types import * from . import trex_stl_stats +from .utils.constants import FLOW_CTRL_DICT_REVERSED import base64 import copy @@ -42,9 +43,9 @@ class Port(object): STATES_MAP = {STATE_DOWN: "DOWN", STATE_IDLE: "IDLE", STATE_STREAMS: "IDLE", - STATE_TX: "ACTIVE", + STATE_TX: "TRANSMITTING", STATE_PAUSE: "PAUSE", - STATE_PCAP_TX : "ACTIVE"} + STATE_PCAP_TX : "TRANSMITTING"} def __init__ (self, port_id, user, comm_link, session_id, info): @@ -251,8 +252,9 @@ class Port(object): # attributes self.attr = rc.data()['attr'] + if 'speed' in rc.data(): + self.info['speed'] = rc.data()['speed'] // 1000 - return self.ok() @@ -577,7 +579,7 @@ class Port(object): return self.err(rc.err()) - self.attr.update(attr_dict) + #self.attr.update(attr_dict) return self.ok() @@ -650,13 +652,46 @@ class Port(object): def get_info (self): info = dict(self.info) - info['status'] = self.get_port_state_name() + info['status'] = self.get_port_state_name() - if self.attr.get('promiscuous'): + if 'link' in self.attr: + info['link'] = 'UP' if self.attr['link']['up'] else 'DOWN' + else: + info['link'] = 'N/A' + + if 'fc' in self.attr: + info['fc'] = FLOW_CTRL_DICT_REVERSED.get(self.attr['fc']['mode'], 'N/A') + else: + info['fc'] = 'N/A' + + if 'promiscuous' in self.attr: info['prom'] = "on" if self.attr['promiscuous']['enabled'] else "off" else: info['prom'] = "N/A" + if 'description' not in info: + info['description'] = "N/A" + + if 'is_fc_supported' in info: + info['fc_supported'] = 'yes' if info['is_fc_supported'] else 'no' + else: + info['fc_supported'] = 'N/A' + + if 'is_led_supported' in info: + info['led_change_supported'] = 'yes' if info['is_led_supported'] else 'no' + else: + info['led_change_supported'] = 'N/A' + + if 'is_link_supported' in info: + info['link_change_supported'] = 'yes' if info['is_link_supported'] else 'no' + else: + info['link_change_supported'] = 'N/A' + + if 'is_virtual' in info: + info['is_virtual'] = 'yes' if info['is_virtual'] else 'no' + else: + info['is_virtual'] = 'N/A' + return info @@ -672,6 +707,7 @@ class Port(object): info = self.get_info() return {"driver": info['driver'], + "description": info.get('description', 'N/A')[:18], "HW src mac": info['hw_macaddr'], "SW src mac": info['src_macaddr'], "SW dst mac": info['dst_macaddr'], @@ -679,9 +715,11 @@ class Port(object): "NUMA Node": info['numa'], "--": "", "---": "", - "maximum": "{speed} Gb/s".format(speed=info['speed']), - "status": info['status'], - "promiscuous" : info['prom'] + "link speed": "{speed} Gb/s".format(speed=info['speed']), + "port status": info['status'], + "link status": info['link'], + "promiscuous" : info['prom'], + "flow ctrl" : info['fc'], } def clear_stats(self): @@ -726,6 +764,10 @@ class Port(object): self.state = self.STATE_STREAMS self.last_factor_type = None + def async_event_port_attr_changed (self, attr): + self.info['speed'] = attr['speed'] // 1000 + self.attr = attr + # rest of the events are used for TUI / read only sessions def async_event_port_stopped (self): if not self.is_acquired(): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 5d9cdcaa..9f601484 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -3,6 +3,7 @@ from .utils import text_tables from .utils.text_opts import format_text, format_threshold, format_num from .trex_stl_types import StatNotAvailable, is_integer +from .trex_stl_exceptions import STLError from collections import namedtuple, OrderedDict, deque import sys @@ -23,8 +24,10 @@ LATENCY_STATS = 'ls' LATENCY_HISTOGRAM = 'lh' CPU_STATS = 'c' MBUF_STATS = 'm' +EXTENDED_STATS = 'x' +EXTENDED_INC_ZERO_STATS = 'xz' -ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM, CPU_STATS, MBUF_STATS] +ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM, CPU_STATS, MBUF_STATS, EXTENDED_STATS, EXTENDED_INC_ZERO_STATS] COMPACT = [GLOBAL_STATS, PORT_STATS] GRAPH_PORT_COMPACT = [GLOBAL_STATS, PORT_GRAPH] SS_COMPAT = [GLOBAL_STATS, STREAMS_STATS] # stream stats @@ -147,12 +150,13 @@ class CTRexInfoGenerator(object): STLClient and the ports. """ - def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, util_stats_ref, async_monitor): + def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, util_stats_ref, xstats_ref, async_monitor): self._global_stats = global_stats_ref self._ports_dict = ports_dict_ref self._rx_stats_ref = rx_stats_ref self._latency_stats_ref = latency_stats_ref self._util_stats_ref = util_stats_ref + self._xstats_ref = xstats_ref self._async_monitor = async_monitor def generate_single_statistic(self, port_id_list, statistic_type): @@ -183,6 +187,12 @@ class CTRexInfoGenerator(object): elif statistic_type == MBUF_STATS: return self._generate_mbuf_util_stats() + elif statistic_type == EXTENDED_STATS: + return self._generate_xstats(port_id_list, include_zero_lines = False) + + elif statistic_type == EXTENDED_INC_ZERO_STATS: + return self._generate_xstats(port_id_list, include_zero_lines = True) + else: # ignore by returning empty object return {} @@ -205,10 +215,9 @@ class CTRexInfoGenerator(object): def _generate_global_stats(self): global_stats = self._global_stats - stats_data = OrderedDict([("connection", "{host}, Port {port}".format(host=global_stats.connection_info.get("server"), + stats_data_left = OrderedDict([("connection", "{host}, Port {port}".format(host=global_stats.connection_info.get("server"), port=global_stats.connection_info.get("sync_port"))), - ("version", "{ver}, UUID: {uuid}".format(ver=global_stats.server_version.get("version", "N/A"), - uuid="N/A")), + ("version", "{ver}".format(ver=global_stats.server_version.get("version", "N/A"))), ("cpu_util.", "{0}% @ {2} cores ({3} per port) {1}".format( format_threshold(round_float(global_stats.get("m_cpu_util")), [85, 100], [0, 85]), global_stats.get_trend_gui("m_cpu_util", use_raw = True), @@ -221,14 +230,13 @@ class CTRexInfoGenerator(object): ("async_util.", "{0}% / {1}".format( format_threshold(round_float(self._async_monitor.get_cpu_util()), [85, 100], [0, 85]), format_num(self._async_monitor.get_bps() / 8.0, suffix = "B/sec"))), - - - (" ", ""), + ]) + stats_data_right = OrderedDict([ ("total_tx_L2", "{0} {1}".format( global_stats.get("m_tx_bps", format=True, suffix="b/sec"), global_stats.get_trend_gui("m_tx_bps"))), - ("total_tx_L1", "{0} {1}".format( global_stats.get("m_tx_bps_L1", format=True, suffix="b/sec"), + ("total_tx_L1", "{0} {1}".format( global_stats.get("m_tx_bps_L1", format=True, suffix="b/sec"), global_stats.get_trend_gui("m_tx_bps_L1"))), ("total_rx", "{0} {1}".format( global_stats.get("m_rx_bps", format=True, suffix="b/sec"), @@ -237,8 +245,6 @@ class CTRexInfoGenerator(object): ("total_pps", "{0} {1}".format( global_stats.get("m_tx_pps", format=True, suffix="pkt/sec"), global_stats.get_trend_gui("m_tx_pps"))), - #(" ", ""), - ("drop_rate", "{0}".format( format_num(global_stats.get("m_rx_drop_bps"), suffix = 'b/sec', opts = 'green' if (global_stats.get("m_rx_drop_bps")== 0) else 'red'), @@ -248,19 +254,29 @@ class CTRexInfoGenerator(object): suffix = 'pkts', compact = False, opts = 'green' if (global_stats.get_rel("m_total_queue_full")== 0) else 'red'))), - - ] - ) + ]) # build table representation stats_table = text_tables.TRexTextInfo() stats_table.set_cols_align(["l", "l"]) + stats_table.set_deco(0) + stats_table.set_cols_width([50, 45]) + max_lines = max(len(stats_data_left), len(stats_data_right)) + for line_num in range(max_lines): + row = [] + if line_num < len(stats_data_left): + key = list(stats_data_left.keys())[line_num] + row.append('{:<12} : {}'.format(key, stats_data_left[key])) + else: + row.append('') + if line_num < len(stats_data_right): + key = list(stats_data_right.keys())[line_num] + row.append('{:<12} : {}'.format(key, stats_data_right[key])) + else: + row.append('') + stats_table.add_row(row) - stats_table.add_rows([[k.replace("_", " ").title(), v] - for k, v in stats_data.items()], - header=False) - - return {"global_statistics": ExportableStats(stats_data, stats_table)} + return {"global_statistics": ExportableStats(None, stats_table)} def _generate_streams_stats (self): flow_stats = self._rx_stats_ref @@ -325,7 +341,7 @@ class CTRexInfoGenerator(object): def _generate_latency_stats(self): lat_stats = self._latency_stats_ref - latency_window_size = 10 + latency_window_size = 14 # for TUI - maximum 5 pg_ids = list(filter(is_intable, lat_stats.latest_stats.keys()))[:5] @@ -439,7 +455,7 @@ class CTRexInfoGenerator(object): stats_table.set_cols_width([10, 3, 6] + [3] * (show_len - 1)) stats_table.set_cols_dtype(['t'] * (show_len + 2)) - for i in range(min(14, len(cpu_stats))): + for i in range(min(18, len(cpu_stats))): history = cpu_stats[i]["history"] ports = cpu_stats[i]["ports"] avg = int(round(sum(history[:avg_len]) / avg_len)) @@ -504,6 +520,28 @@ class CTRexInfoGenerator(object): stats_table.add_row(['No Data.']) return {'mbuf_util': ExportableStats(None, stats_table)} + def _generate_xstats(self, port_id_list, include_zero_lines = False): + relevant_ports = [port.port_id for port in self.__get_relevant_ports(port_id_list)] + # get the data on relevant ports + xstats_data = OrderedDict() + for port_id in relevant_ports: + for key, val in self._xstats_ref.get_stats(port_id).items(): + if key not in xstats_data: + xstats_data[key] = [] + xstats_data[key].append(val) + + # put into table + stats_table = text_tables.TRexTextTable() + stats_table.header(['Name:'] + ['Port %s:' % port_id for port_id in relevant_ports]) + stats_table.set_cols_align(['l'] + ['r'] * len(relevant_ports)) + stats_table.set_cols_width([30] + [15] * len(relevant_ports)) + stats_table.set_cols_dtype(['t'] * (len(relevant_ports) + 1)) + for key, arr in xstats_data.items(): + if include_zero_lines or list(filter(None, arr)): + key = key[:28] + stats_table.add_row([key] + arr) + return {'xstats:': ExportableStats(None, stats_table)} + @staticmethod def _get_rational_block_char(value, range_start, interval): # in Konsole, utf-8 is sometimes printed with artifacts, return ascii for now @@ -557,6 +595,7 @@ class CTRexInfoGenerator(object): return_stats_data = {} per_field_stats = OrderedDict([("owner", []), + ('link', []), ("state", []), ("speed", []), ("CPU util.", []), @@ -584,8 +623,7 @@ class CTRexInfoGenerator(object): ("oerrors", []), ("ierrors", []), - ] - ) + ]) total_stats = CPortStats(None) @@ -625,9 +663,12 @@ class CTRexInfoGenerator(object): return_stats_data = {} per_field_status = OrderedDict([("driver", []), - ("maximum", []), - ("status", []), + ("description", []), + ("link status", []), + ("link speed", []), + ("port status", []), ("promiscuous", []), + ("flow ctrl", []), ("--", []), ("HW src mac", []), ("SW src mac", []), @@ -1003,6 +1044,7 @@ class CPortStats(CTRexStats): def _update(self, snapshot): + speed = self._port_obj.get_speed_bps() # L1 bps tx_bps = snapshot.get("m_total_tx_bps") @@ -1015,22 +1057,34 @@ class CPortStats(CTRexStats): bps_rx_L1 = calc_bps_L1(rx_bps, rx_pps) snapshot['m_total_tx_bps_L1'] = bps_tx_L1 - snapshot['m_tx_util'] = (bps_tx_L1 / self._port_obj.get_speed_bps()) * 100.0 + if speed: + snapshot['m_tx_util'] = (bps_tx_L1 / speed) * 100.0 + else: + snapshot['m_tx_util'] = 0 snapshot['m_total_rx_bps_L1'] = bps_rx_L1 - snapshot['m_rx_util'] = (bps_rx_L1 / self._port_obj.get_speed_bps()) * 100.0 + if speed: + snapshot['m_rx_util'] = (bps_rx_L1 / speed) * 100.0 + else: + snapshot['m_rx_util'] = 0 # TX line util not smoothed diff_tx_pkts = snapshot.get('opackets', 0) - self.latest_stats.get('opackets', 0) diff_tx_bytes = snapshot.get('obytes', 0) - self.latest_stats.get('obytes', 0) tx_bps_L1 = calc_bps_L1(8.0 * diff_tx_bytes / ts_diff, float(diff_tx_pkts) / ts_diff) - snapshot['tx_percentage'] = 100.0 * tx_bps_L1 / self._port_obj.get_speed_bps() + if speed: + snapshot['tx_percentage'] = 100.0 * tx_bps_L1 / speed + else: + snapshot['tx_percentage'] = 0 # RX line util not smoothed diff_rx_pkts = snapshot.get('ipackets', 0) - self.latest_stats.get('ipackets', 0) diff_rx_bytes = snapshot.get('ibytes', 0) - self.latest_stats.get('ibytes', 0) rx_bps_L1 = calc_bps_L1(8.0 * diff_rx_bytes / ts_diff, float(diff_rx_pkts) / ts_diff) - snapshot['rx_percentage'] = 100.0 * rx_bps_L1 / self._port_obj.get_speed_bps() + if speed: + snapshot['rx_percentage'] = 100.0 * rx_bps_L1 / speed + else: + snapshot['rx_percentage'] = 0 # simple... self.latest_stats = snapshot @@ -1040,13 +1094,24 @@ class CPortStats(CTRexStats): def generate_stats(self): - state = self._port_obj.get_port_state_name() if self._port_obj else "" - if state == "ACTIVE": - state = format_text(state, 'green', 'bold') - elif state == "PAUSE": - state = format_text(state, 'magenta', 'bold') + port_state = self._port_obj.get_port_state_name() if self._port_obj else "" + if port_state == "TRANSMITTING": + port_state = format_text(port_state, 'green', 'bold') + elif port_state == "PAUSE": + port_state = format_text(port_state, 'magenta', 'bold') + else: + port_state = format_text(port_state, 'bold') + + if self._port_obj: + if 'link' in self._port_obj.attr: + if self._port_obj.attr.get('link', {}).get('up') == False: + link_state = format_text('DOWN', 'red', 'bold') + else: + link_state = 'UP' + else: + link_state = 'N/A' else: - state = format_text(state, 'bold') + link_state = '' # default rate format modifiers rate_format = {'bpsl1': None, 'bps': None, 'pps': None, 'percentage': 'bold'} @@ -1063,7 +1128,8 @@ class CPortStats(CTRexStats): return {"owner": owner, - "state": "{0}".format(state), + "state": "{0}".format(port_state), + 'link': link_state, "speed": self._port_obj.get_formatted_speed() if self._port_obj else '', "CPU util.": "{0} {1}%".format(self.get_trend_gui("m_cpu_util", use_raw = True), format_threshold(round_float(self.get("m_cpu_util")), [85, 100], [0, 85])) if self._port_obj else '' , @@ -1417,7 +1483,7 @@ class CUtilStats(CTRexStats): self.client = client self.history = deque(maxlen = 1) self.mbuf_types_list = None - self.last_update_ts = 0 + self.last_update_ts = -999 def get_stats(self, use_1sec_cache = False): time_now = time.time() @@ -1425,7 +1491,7 @@ class CUtilStats(CTRexStats): if self.client.is_connected(): rc = self.client._transmit('get_utilization') if not rc: - raise Exception(rc) + raise STLError(rc) self.last_update_ts = time_now self.history.append(rc.data()) else: @@ -1433,6 +1499,51 @@ class CUtilStats(CTRexStats): return self.history[-1] +class CXStats(CTRexStats): + + def __init__(self, client): + super(CXStats, self).__init__() + self.client = client + self.names = [] + self.last_update_ts = -999 + + def clear_stats(self, port_id = None): + if port_id == None: + ports = self.client.get_all_ports() + elif type(port_id) is list: + ports = port_id + else: + ports = [port_id] + + for port_id in ports: + self.reference_stats[port_id] = self.get_stats(port_id, relative = False) + + def get_stats(self, port_id, use_1sec_cache = False, relative = True): + time_now = time.time() + if self.last_update_ts + 1 < time_now or not self.latest_stats or not use_1sec_cache: + if self.client.is_connected(): + rc = self.client._transmit('get_port_xstats_values', params = {'port_id': port_id}) + if not rc: + raise STLError(rc) + self.last_update_ts = time_now + values = rc.data().get('xstats_values', []) + if len(values) != len(self.names): # need to update names ("keys") + rc = self.client._transmit('get_port_xstats_names', params = {'port_id': port_id}) + if not rc: + raise STLError(rc) + self.names = rc.data().get('xstats_names', []) + if len(values) != len(self.names): + raise STLError('Length of get_xstats_names: %s and get_port_xstats_values: %s' % (len(self.names), len(values))) + self.latest_stats[port_id] = OrderedDict([(key, val) for key, val in zip(self.names, values)]) + + stats = OrderedDict() + for key, val in self.latest_stats[port_id].items(): + if relative: + stats[key] = self.get_rel([port_id, key]) + else: + stats[key] = self.get([port_id, key]) + return stats + if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py index 3993ad5e..fe4fc893 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py @@ -85,27 +85,29 @@ class GA_EXCEPTION_ObjClass(GA_ObjClass): #..................................................................class GA_TESTING_ObjClass................................................................
class GA_TESTING_ObjClass(GA_ObjClass):
- def __init__(self,cid,uuid,trackerID,TRexMode,test_name,setup_name,appName,appVer,commitID,bandwidthPerCore,goldenBPC):
+ def __init__(self,cid,trackerID,TRexMode,TestName,SetupName,appName,ActionNumber,appVer,TestType,Mppspc,GoldenMin,GoldenMax):
GA_ObjClass.__init__(self,cid,trackerID,appName,appVer)
- self.uid = uuid
+ self.ActionNumber = ActionNumber
self.TRexMode = TRexMode
- self.test_name = test_name
- self.setup_name = setup_name
- self.commitID = commitID
- self.bandwidthPerCore = bandwidthPerCore
- self.goldenBPC = goldenBPC
+ self.TestName = TestName
+ self.SetupName = SetupName
+ self.TestType = TestType
+ self.Mppspc = Mppspc
+ self.GoldenMin = GoldenMin
+ self.GoldenMax = GoldenMax
self.payload = self.generate_payload()
self.size = sys.getsizeof(self.payload)
def generate_payload(self):
- self.payload+='&ec='+str(self.TRexMode)
- self.payload+='&ea=RegressionReport'
- self.payload+='&cd5='+str(self.uid)
- self.payload+='&cd1='+str(self.test_name)
- self.payload+='&cd2='+str(self.setup_name)
- self.payload+='&cd3='+str(self.commitID)
- self.payload+='&cm1='+str(self.bandwidthPerCore)
- self.payload+='&cm2='+str(self.goldenBPC)
+ self.payload+='&ec=TRexTests'
+ self.payload+='&ea='+str(self.ActionNumber)
+ self.payload+='&cd2='+str(self.TRexMode)
+ self.payload+='&cd1='+str(self.TestName)
+ self.payload+='&cd3='+str(self.SetupName)
+ self.payload+='&cd4='+str(self.TestType)
+ self.payload+='&cm1='+str(self.Mppspc)
+ self.payload+='&cm2='+str(self.GoldenMin)
+ self.payload+='&cm3='+str(self.GoldenMax)
return self.payload
#.....................................................................class ga_Thread.................................................................
"""
@@ -265,7 +267,6 @@ class GAmanager: attributes:
GoogleID - the tracker ID that Google uses in order to track the activity of a property. for regression use: 'UA-75220362-4'
AnalyticsUserID - text value - used by Google to differ between 2 users sending data. (will not be presented on reports). use only as a way to differ between different users
-UUID - text - will be presented on analysis. put here UUID
TRexMode - text - will be presented on analysis. put here TRexMode
appName - text - will be presented on analysis. put here appName as string describing app name
appVer - text - will be presented on analysis. put here the appVer
@@ -274,83 +275,21 @@ Timeout - integer (seconds) - the timeout in seconds between automated reports w UserPermission - boolean (1/0) - required in order to send packets, should be 1.
BlockingMode - boolean (1/0) - required when each tracked event is critical and program should halt until the event is reported
SetupName - text - will be presented on analysis. put here setup name as string.
-CommitID - text - will be presented on analysis. put here CommitID
"""
class GAmanager_Regression(GAmanager):
- def __init__(self,GoogleID,AnalyticsUserID,UUID,TRexMode,appName,appVer,
- QueueSize,Timeout,UserPermission,BlockingMode,SetupName,CommitID):
- GAmanager.__init__(self,GoogleID,AnalyticsUserID,appName,appVer,
- QueueSize,Timeout,UserPermission,BlockingMode)
- self.UUID = UUID
- self.TRexMode = TRexMode
- self.SetupName = SetupName
- self.CommitID = CommitID
-
- def gaAddTestQuery(self,TestName,BandwidthPerCore,GoldenBPC):
- self.gaAddObject(GA_TESTING_ObjClass(self.UserID,self.UUID,self.GoogleID,
- self.TRexMode,TestName,self.SetupName,
- self.appName,self.appVer,self.CommitID,
- BandwidthPerCore,GoldenBPC))
-
-
-
-
-#***************************************------TEST--------------**************************************
-
-
-#if __name__ == '__main__':
-
-#g= GAmanager_Regression(GoogleID='UA-75220362-4',AnalyticsUserID=3845,UUID='trex18UUID_GA_TEST',TRexMode='stateFull_GA_TEST',
-# appName='TRex_GA_TEST',appVer='1.1_GA_TEST',QueueSize=20,Timeout=11,UserPermission=1,BlockingMode=0,SetupName='setup1_GA_TEST',CommitID='commitID1_GA_TEST')
-#for j in range(1,3,1):
-#for i in range(100,118,1):
-# g.gaAddTestQuery('test_name_GA_TEST',i+0.5,150)
-# sleep(11)
-# print "finished batch"
-#g.emptyAndReportQ()
-
-#g.printSelf()
-#g.emptyAndReportQ()
-
-#g = GAmanager(GoogleID='UA-75220362-4',UserID=1,QueueSize=100,Timeout=5,UserPermission=1,BlockingMode=0,appName='TRex',appVer='1.11.232') #timeout in seconds
-#for i in range(0,35,1):
-# g.gaAddAction(Event='test',action='start',label='1',value=i)
-#g.gaAddException('MEMFAULT',1)
-#g.emptyAndReportQ()
-#g.printSelf()
-#print g.payload
-#print g.size
-
-
-
-
-#g.activate()
-#g.gaAddAction(Event='test',action='start',label='1',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-#g.gaAddAction(Event='test',action='start',label='2',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-#g.gaAddAction(Event='test',action='start',label='3',value='1')
-#sys.stdout.write('element added \n')
-#sys.stdout.flush()
-
-#testdata = "v=1&t=event&tid=UA-75220362-4&cid=2&ec=test&ea=testing&el=testpacket&ev=2"
-#r = requests.post(url_debug,data=testdata)
-#print r
-
-#thread1 = ga_Thread(1,g)
-#thread1.start()
-#thread1.join()
-#for i in range(1,10,1):
-# sys.stdout.write('yesh %d'% (i))
-# sys.stdout.flush()
+ def __init__(self, GoogleID, AnalyticsUserID, appName, appVer,
+ QueueSize, Timeout, UserPermission, BlockingMode):
+ GAmanager.__init__(self, GoogleID, AnalyticsUserID, appName, appVer,
+ QueueSize, Timeout, UserPermission, BlockingMode)
+ self.GoogleID = GoogleID
+ self.AnalyticsUserID = AnalyticsUserID
+
+ def gaAddTestQuery(self, TestName, TRexMode, SetupName, ActionNumber, TestType, Mppspc, GoldenMin, GoldenMax):
+ self.gaAddObject(GA_TESTING_ObjClass(self.AnalyticsUserID, self.GoogleID, TRexMode, TestName, SetupName, self.appName, ActionNumber, self.appVer, TestType, Mppspc, GoldenMin, GoldenMax))
-
-
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py index 638684c3..72ee8972 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py @@ -27,9 +27,9 @@ def user_input(): return raw_input() -def random_id_gen(length=8): +class random_id_gen: """ - A generator for creating a random chars id of specific length + Emulated generator for creating a random chars id of specific length :parameters: length : int @@ -40,12 +40,15 @@ def random_id_gen(length=8): :return: a random id with each next() request. """ - id_chars = string.ascii_lowercase + string.digits - while True: - return_id = '' - for i in range(length): - return_id += random.choice(id_chars) - yield return_id + def __init__(self, length=8): + self.id_chars = string.ascii_lowercase + string.digits + self.length = length + + def next(self): + return ''.join(random.choice(self.id_chars) for _ in range(self.length)) + + __next__ = next + # try to get number from input, return None in case of fail def get_number(input): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py new file mode 100755 index 00000000..a4942094 --- /dev/null +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py @@ -0,0 +1,26 @@ +from collections import OrderedDict + +ON_OFF_DICT = OrderedDict([ + ('on', True), + ('off', False), +]) + +UP_DOWN_DICT = OrderedDict([ + ('up', True), + ('down', False), +]) + +FLOW_CTRL_DICT = OrderedDict([ + ('none', 0), # Disable flow control + ('tx', 1), # Enable flowctrl on TX side (RX pause frames) + ('rx', 2), # Enable flowctrl on RX side (TX pause frames) + ('full', 3), # Enable flow control on both sides +]) + + + +# generate reverse dicts + +for var_name in list(vars().keys()): + if var_name.endswith('_DICT'): + exec('{0}_REVERSED = OrderedDict([(val, key) for key, val in {0}.items()])'.format(var_name)) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py index 8ae86981..7eda8635 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py @@ -1,8 +1,9 @@ import argparse -from collections import namedtuple +from collections import namedtuple, OrderedDict from .common import list_intersect, list_difference from .text_opts import format_text from ..trex_stl_types import * +from .constants import ON_OFF_DICT, UP_DOWN_DICT, FLOW_CTRL_DICT import sys import re @@ -32,14 +33,16 @@ IPG = 16 SPEEDUP = 17 COUNT = 18 PROMISCUOUS = 19 -NO_PROMISCUOUS = 20 -PROMISCUOUS_SWITCH = 21 +LINK_STATUS = 20 +LED_STATUS = 21 TUNABLES = 22 REMOTE_FILE = 23 LOCKED = 24 PIN_CORES = 25 CORE_MASK = 26 DUAL = 27 +FLOW_CTRL = 28 +SUPPORTED = 29 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -48,6 +51,8 @@ STREAMS_STATS = 53 STATS_MASK = 54 CPU_STATS = 55 MBUF_STATS = 56 +EXTENDED_STATS = 57 +EXTENDED_INC_ZERO_STATS = 58 STREAMS_MASK = 60 CORE_MASK_GROUP = 61 @@ -282,10 +287,26 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'type': int}), PROMISCUOUS: ArgumentPack(['--prom'], - {'help': "Sets port promiscuous on", - 'dest': "prom", - 'default': None, - 'action': "store_true"}), + {'help': "Set port promiscuous on/off", + 'choices': ON_OFF_DICT}), + + LINK_STATUS: ArgumentPack(['--link'], + {'help': 'Set link status up/down', + 'choices': UP_DOWN_DICT}), + + LED_STATUS: ArgumentPack(['--led'], + {'help': 'Set LED status on/off', + 'choices': ON_OFF_DICT}), + + FLOW_CTRL: ArgumentPack(['--fc'], + {'help': 'Set Flow Control type', + 'dest': 'flow_ctrl', + 'choices': FLOW_CTRL_DICT}), + + SUPPORTED: ArgumentPack(['--supp'], + {'help': 'Show which attributes are supported by current NICs', + 'default': None, + 'action': 'store_true'}), TUNABLES: ArgumentPack(['-t'], {'help': "Sets tunables for a profile. Example: '-t fsize=100,pg_id=7'", @@ -295,12 +316,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'action': 'merge', 'type': decode_tunables}), - NO_PROMISCUOUS: ArgumentPack(['--no-prom', '--no_prom'], - {'help': "Sets port promiscuous off", - 'dest': "prom", - 'default': None, - 'action': "store_false"}), - PORT_LIST: ArgumentPack(['--port', '-p'], {"nargs": '+', 'dest':'ports', @@ -401,6 +416,14 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], {'action': 'store_true', 'help': "Fetch only MBUF utilization stats"}), + EXTENDED_STATS: ArgumentPack(['-x'], + {'action': 'store_true', + 'help': "Fetch xstats of port, excluding lines with zero values"}), + + EXTENDED_INC_ZERO_STATS: ArgumentPack(['--xz'], + {'action': 'store_true', + 'help': "Fetch xstats of port, including lines with zero values"}), + STREAMS_MASK: ArgumentPack(['--streams'], {"nargs": '+', 'dest':'streams', @@ -424,12 +447,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': None, 'help': "Core mask - only cores responding to the bit mask will be active"}), - - # promiscuous - PROMISCUOUS_SWITCH: ArgumentGroup(MUTEX, [PROMISCUOUS, - NO_PROMISCUOUS], - {'required': False}), - # advanced options PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST, ALL_PORTS], @@ -443,7 +460,9 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], PORT_STATUS, STREAMS_STATS, CPU_STATS, - MBUF_STATS], + MBUF_STATS, + EXTENDED_STATS, + EXTENDED_INC_ZERO_STATS,], {}), @@ -462,6 +481,8 @@ class _MergeAction(argparse._AppendAction): items.extend(values) elif type(items) is dict and type(values) is dict: # tunables are dict items.update(values) + else: + raise Exception("Argparser 'merge' option should be used on dict or list.") setattr(namespace, self.dest, items) diff --git a/scripts/dpdk_nic_bind.py b/scripts/dpdk_nic_bind.py index 44d4e82d..a85ecb71 100755 --- a/scripts/dpdk_nic_bind.py +++ b/scripts/dpdk_nic_bind.py @@ -45,6 +45,10 @@ import getpass # The PCI device class for ETHERNET devices ETHERNET_CLASS = "0200" +PATH = os.getenv('PATH', '') +needed_path = '.:/bin:/usr/bin:/usr/sbin' +if needed_path not in PATH: + os.environ['PATH'] = '%s:%s' % (PATH, needed_path) # global dict ethernet devices present. Dictionary indexed by PCI address. # Each device within this is itself a dictionary of device properties @@ -629,6 +633,13 @@ def show_table(): table.add_row([id, d['NUMA'], d['Slot_str'], d.get('MAC', ''), d['Device_str'], d.get('Driver_str', ''), d['Interface'], d['Active']]) print(table.draw()) +# dumps pci address and description (user friendly device name) +def dump_pci_description(): + if not devices: + get_nic_details() + for d in devices.values(): + print('%s - %s' % (d['Slot'], d['Device_str'])) + def parse_args(): '''Parses the command-line arguments given by the user and takes the appropriate action for each''' diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 58d58690..5bbbdb28 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -358,11 +358,13 @@ Other network devices if if_list and map_driver.args.parent and dpdk_nic_bind.get_igb_uio_usage(): pid = dpdk_nic_bind.get_pid_using_pci(if_list) - cmdline = dpdk_nic_bind.read_pid_cmdline(pid) - print('Some or all of given interfaces are in use by following process:\npid: %s, cmd: %s' % (pid, cmdline)) - if not dpdk_nic_bind.confirm('Ignore and proceed (y/N):'): - sys.exit(1) - + if pid: + cmdline = dpdk_nic_bind.read_pid_cmdline(pid) + print('Some or all of given interfaces are in use by following process:\npid: %s, cmd: %s' % (pid, cmdline)) + if not dpdk_nic_bind.confirm('Ignore and proceed (y/N):'): + sys.exit(1) + else: + print('WARNING: Some other program is using DPDK driver.\nIf it is TRex and you did not configure it for dual run, current command will fail.') def do_return_to_linux(self): if not self.m_devices: @@ -459,11 +461,14 @@ Other network devices wanted_interfaces.append(dev) unbound = [] + dpdk_bound = [] for interface in wanted_interfaces: if 'Driver_str' not in interface: unbound.append(interface['Slot']) - if unbound: - for pci, info in dpdk_nic_bind.get_info_from_trex(unbound).items(): + elif interface.get('Driver_str') in dpdk_nic_bind.dpdk_drivers: + dpdk_bound.append(interface['Slot']) + if unbound or dpdk_bound: + for pci, info in dpdk_nic_bind.get_info_from_trex(unbound + dpdk_bound).items(): if pci not in self.m_devices: raise DpdkSetup('Internal error: PCI %s is not found among devices' % pci) self.m_devices[pci].update(info) @@ -653,7 +658,7 @@ Other network devices def parse_parent_cfg (parent_cfg): - parent_parser = argparse.ArgumentParser() + parent_parser = argparse.ArgumentParser(add_help = False) parent_parser.add_argument('--cfg', default='') parent_parser.add_argument('--dump-interfaces', nargs='*', default=None) args, unkown = parent_parser.parse_known_args(shlex.split(parent_cfg)) @@ -699,6 +704,8 @@ To see more detailed info on interfaces (table): help=argparse.SUPPRESS ) + parser.add_argument('--dump-pci-description', help=argparse.SUPPRESS, dest='dump_pci_desc', action='store_true') + parser.add_argument("-i", "--interactive", action='store_true', help=""" Create TRex config in interactive mode """, ) @@ -786,6 +793,10 @@ def main (): dpdk_nic_bind.show_table() return + if map_driver.args.dump_pci_desc: + dpdk_nic_bind.dump_pci_description() + return + obj =CIfMap(map_driver.cfg_file); if map_driver.args.create_interfaces is not None: diff --git a/scripts/t-rex-64 b/scripts/t-rex-64 index 4e5c0fae..d2388cfd 100755 --- a/scripts/t-rex-64 +++ b/scripts/t-rex-64 @@ -12,12 +12,28 @@ if [ $RESULT -ne 0 ]; then exit $RESULT fi +pci_desc_re='^(\S+) - (.+)$' +source find_python.sh +while read line +do + if [[ "$line" =~ $pci_desc_re ]]; then + pci_name="pci$(echo ${BASH_REMATCH[1]} | tr ':' '_' | tr '.' '_')" # make alphanumeric name + export $pci_name="${BASH_REMATCH[2]}" + fi +done <<< "$($PYTHON dpdk_setup_ports.py --dump-pci-description)" cd $(dirname $0) export LD_LIBRARY_PATH=$PWD -saveterm="$(stty -g)" + +if [ -t 0 ] && [ -t 1 ]; then + export is_tty=true + saveterm="$(stty -g)" +else + export is_tty=false +fi + # if we have a new core run optimized trex -if cat /proc/cpuinfo | grep -q avx ; then +if grep -q avx /proc/cpuinfo ; then ./_$(basename $0) $INPUT_ARGS RESULT=$? if [ $RESULT -eq 132 ]; then @@ -31,7 +47,10 @@ else ./_t-rex-64-o $INPUT_ARGS RESULT=$? fi -stty $saveterm + +if $is_tty; then + stty $saveterm +fi if [ $RESULT -ne 0 ]; then exit $RESULT diff --git a/signedoff/yarslavbrustinov b/signedoff/yarslavbrustinov index 1b7224d0..cb26ccbe 100755 --- a/signedoff/yarslavbrustinov +++ b/signedoff/yarslavbrustinov @@ -2,6 +2,10 @@ I, Yaroslav Brustinov hearby sign-off-by all of my past commits to this repo sub My contributions were: + 3fb8837d4fe0d63ee42903a02a10860e4562e3b4 - Yaroslav Brustinov - ybrustin@cisco.com - regression: fix for python3 client test + 04300e5690aff199563cf69db39639d7cca32ce6 - Yaroslav Brustinov - ybrustin@cisco.com - typo + 572c98db3944a53bbff51d08fd1f9c8e9674b08c - Yaroslav Brustinov - ybrustin@cisco.com - regression: stateless rx_check allow 0.1% errors + 270cf64af087f110fd69064017edc311ddf82025 - Yaroslav Brustinov - ybrustin@cisco.com - regression: fix client pkg test to configure the dut interfaces 5591bec0425ea906feb109a1142eca66ac1ce937 - Yaroslav Brustinov - ybrustin@cisco.com - fix parsing tunables, add support for separate -t in console, add benchmark profile 5497c271302aa417814aa2e368b1ab2cf1fcef62 - Yaroslav Brustinov - ybrustin@cisco.com - cpp arg parser changes argv, on second iteration data might be not valid => copy the argv before each call. eef160385f07aa94e1dfc67b481a659465410d61 - Yaroslav Brustinov - ybrustin@cisco.com - trex-console: add print of Python error in case of error loading profile in TUI diff --git a/src/debug.cpp b/src/debug.cpp index 542d2fa1..3a9cd506 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -213,8 +213,11 @@ int CTrexDebug::test_send_pkts(rte_mbuf_t *m, uint16_t queue_id, int num_pkts, i int CTrexDebug::set_promisc_all(bool enable) { int i; for (i=0; i < m_max_ports; i++) { - CPhyEthIF *_if = &m_ports[i]; - _if->set_promiscuous(enable); + if (enable) { + rte_eth_promiscuous_enable(i); + }else{ + rte_eth_promiscuous_disable(i); + } } return 0; diff --git a/src/dpdk/drivers/net/virtio/virtio_ethdev.c b/src/dpdk/drivers/net/virtio/virtio_ethdev.c index 07d64497..35e67b90 100644 --- a/src/dpdk/drivers/net/virtio/virtio_ethdev.c +++ b/src/dpdk/drivers/net/virtio/virtio_ethdev.c @@ -1550,6 +1550,8 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->default_txconf = (struct rte_eth_txconf) { .txq_flags = ETH_TXQ_FLAGS_NOOFFLOADS }; + /* TRex patch */ + dev_info->speed_capa = ETH_LINK_SPEED_10G; } /* diff --git a/src/dpdk/drivers/net/vmxnet3/vmxnet3_ethdev.c b/src/dpdk/drivers/net/vmxnet3/vmxnet3_ethdev.c index 58742153..47fdc3ec 100644 --- a/src/dpdk/drivers/net/vmxnet3/vmxnet3_ethdev.c +++ b/src/dpdk/drivers/net/vmxnet3/vmxnet3_ethdev.c @@ -706,6 +706,8 @@ vmxnet3_dev_info_get(__attribute__((unused))struct rte_eth_dev *dev, dev_info->min_rx_bufsize = 1518 + RTE_PKTMBUF_HEADROOM; dev_info->max_rx_pktlen = 16384; /* includes CRC, cf MAXFRS register */ dev_info->max_mac_addrs = VMXNET3_MAX_MAC_ADDRS; + /* TRex patch */ + dev_info->speed_capa = ETH_LINK_SPEED_10G; dev_info->default_txconf.txq_flags = ETH_TXQ_FLAGS_NOXSUMSCTP; dev_info->flow_type_rss_offloads = VMXNET3_RSS_OFFLOAD_ALL; diff --git a/src/inet_pton.cpp b/src/inet_pton.cpp new file mode 100644 index 00000000..3a4a12d7 --- /dev/null +++ b/src/inet_pton.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +typedef unsigned char u_char; +typedef unsigned int u_int; +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +int +my_inet_pton4(const char *src, u_char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; +#define NS_INADDRSZ 4 + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new_d = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return (0); + if (new_d > 255) + return (0); + *tp = new_d; + if (!saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +int +my_inet_pton6(const char *src, u_char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; +#define NS_IN6ADDRSZ 16 +#define NS_INT16SZ 2 + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return (0); + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') { + return (0); + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + my_inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + seen_xdigits = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + return (0); + } + if (seen_xdigits) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h index a55e8cd7..631f9a3e 100644 --- a/src/internal_api/trex_platform_api.h +++ b/src/internal_api/trex_platform_api.h @@ -28,6 +28,7 @@ limitations under the License. #include <string.h> #include "flow_stat_parser.h" #include "trex_defs.h" +#include "trex_port_attr.h" #include <json/json.h> /** @@ -123,7 +124,6 @@ public: */ struct intf_info_st { std::string driver_name; - uint32_t speed; mac_cfg_st mac_info; std::string pci_addr; int numa_node; @@ -137,6 +137,7 @@ public: virtual void get_interface_info(uint8_t interface_id, intf_info_st &info) const = 0; virtual void publish_async_data_now(uint32_t key, bool baseline) const = 0; + virtual void publish_async_port_attr_changed(uint8_t port_id) const = 0; virtual uint8_t get_dp_core_count() const = 0; virtual void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const =0; virtual int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset @@ -149,14 +150,15 @@ public: , uint8_t ipv6_next_h, uint16_t id) const = 0; virtual int del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto , uint8_t ipv6_next_h, uint16_t id) const = 0; - virtual void set_promiscuous(uint8_t port_id, bool enabled) const = 0; - virtual bool get_promiscuous(uint8_t port_id) const = 0; virtual void flush_dp_messages() const = 0; virtual int get_active_pgids(flow_stat_active_t &result) const = 0; virtual int get_cpu_util_full(cpu_util_full_t &result) const = 0; virtual int get_mbuf_util(Json::Value &result) const = 0; virtual CFlowStatParser *get_flow_stat_parser() const = 0; + virtual TRexPortAttr *getPortAttrObj(uint8_t port_id) const = 0; virtual void mark_for_shutdown() const = 0; + virtual int get_xstats_values(uint8_t port_id, xstats_values_t &xstats_values) const = 0; + virtual int get_xstats_names(uint8_t port_id, xstats_names_t &xstats_names) const = 0; virtual ~TrexPlatformApi() {} }; @@ -176,6 +178,7 @@ public: void get_interface_info(uint8_t interface_id, intf_info_st &info) const; void publish_async_data_now(uint32_t key, bool baseline) const; + void publish_async_port_attr_changed(uint8_t port_id) const; uint8_t get_dp_core_count() const; void get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const; int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset @@ -188,14 +191,16 @@ public: , uint8_t ipv6_next_h, uint16_t id) const; virtual int del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto , uint8_t ipv6_next_h, uint16_t id) const; - void set_promiscuous(uint8_t port_id, bool enabled) const; - bool get_promiscuous(uint8_t port_id) const; void flush_dp_messages() const; int get_active_pgids(flow_stat_active_t &result) const; int get_cpu_util_full(cpu_util_full_t &result) const; int get_mbuf_util(Json::Value &result) const; void mark_for_shutdown() const; CFlowStatParser *get_flow_stat_parser() const; + TRexPortAttr *getPortAttrObj(uint8_t port_id) const; + + int get_xstats_values(uint8_t port_id, xstats_values_t &xstats_values) const; + int get_xstats_names(uint8_t port_id, xstats_names_t &xstats_names) const; }; @@ -209,6 +214,11 @@ public: SimPlatformApi(int dp_core_count) { m_dp_core_count = dp_core_count; + m_port_attr = new SimTRexPortAttr(); + } + + ~SimPlatformApi() { + delete m_port_attr; } virtual uint8_t get_dp_core_count() const { @@ -221,7 +231,6 @@ public: virtual void get_interface_info(uint8_t interface_id, intf_info_st &info) const { info.driver_name = "TEST"; - info.speed = 10000; info.has_crc = true; info.numa_node = 0; @@ -241,6 +250,10 @@ public: virtual void publish_async_data_now(uint32_t key, bool baseline) const { } + + virtual void publish_async_port_attr_changed(uint8_t port_id) const { + } + int get_flow_stats(uint8_t port_id, void *stats, void *tx_stats, int min, int max, bool reset , TrexPlatformApi::driver_stat_cap_e type) const {return 0;}; virtual int get_rfc2544_info(void *rfc2544_info, int min, int max, bool reset) const {return 0;}; @@ -251,11 +264,6 @@ public: , uint8_t ipv6_next_h, uint16_t id) const {return 0;}; virtual int del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type, uint8_t l4_proto , uint8_t ipv6_next_h, uint16_t id) const {return 0;}; - void set_promiscuous(uint8_t port_id, bool enabled) const { - } - bool get_promiscuous(uint8_t port_id) const { - return false; - } void flush_dp_messages() const { } @@ -263,11 +271,15 @@ public: int get_cpu_util_full(cpu_util_full_t &result) const {return 0;} int get_mbuf_util(Json::Value &result) const {return 0;} CFlowStatParser *get_flow_stat_parser() const {return new CFlowStatParser();} + TRexPortAttr *getPortAttrObj(uint8_t port_id) const {return m_port_attr;} void mark_for_shutdown() const {} + int get_xstats_values(uint8_t port_id, xstats_values_t &xstats_values) const {return 0;}; + int get_xstats_names(uint8_t port_id, xstats_names_t &xstats_names) const {return 0;}; private: int m_dp_core_count; + SimTRexPortAttr * m_port_attr; }; #endif /* __TREX_PLATFORM_API_H__ */ diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 46fa7335..fbd55173 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -77,6 +77,7 @@ extern "C" { #include "stateful_rx_core.h" #include "debug.h" #include "pkt_gen.h" +#include "trex_port_attr.h" #include "internal_api/trex_platform_api.h" #include "main_dpdk.h" #include "trex_watchdog.h" @@ -120,6 +121,15 @@ static inline int get_is_rx_thread_enabled() { struct port_cfg_t; +#define MAX_DPDK_ARGS 40 +static CPlatformYamlInfo global_platform_cfg_info; +static int global_dpdk_args_num ; +static char * global_dpdk_args[MAX_DPDK_ARGS]; +static char global_cores_str[100]; +static char global_prefix_str[100]; +static char global_loglevel_str[20]; + + class CTRexExtendedDriverBase { public: @@ -147,7 +157,6 @@ public: virtual void clear_extended_stats(CPhyEthIF * _if)=0; virtual int wait_for_stable_link(); virtual void wait_after_link_up(); - virtual bool flow_control_disable_supported(){return true;} virtual bool hw_rx_stat_supported(){return false;} virtual int get_rx_stats(CPhyEthIF * _if, uint32_t *pkts, uint32_t *prev_pkts, uint32_t *bytes, uint32_t *prev_bytes , int min, int max) {return -1;} @@ -158,6 +167,7 @@ public: virtual int verify_fw_ver(int i) {return 0;} virtual CFlowStatParser *get_flow_stat_parser(); virtual int set_rcv_all(CPhyEthIF * _if, bool set_on)=0; + virtual TRexPortAttr * create_port_attr(uint8_t port_id) = 0; }; @@ -167,6 +177,10 @@ public: CTRexExtendedDriverBase1G(){ } + TRexPortAttr * create_port_attr(uint8_t port_id) { + return new DpdkTRexPortAttr(port_id, false, true); + } + static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase1G() ); } @@ -212,6 +226,10 @@ public: CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true); } + TRexPortAttr * create_port_attr(uint8_t port_id) { + return new DpdkTRexPortAttr(port_id, true, true); + } + virtual bool has_crc_added() { return false; } @@ -257,6 +275,10 @@ public: CTRexExtendedDriverBase10G(){ } + TRexPortAttr * create_port_attr(uint8_t port_id) { + return new DpdkTRexPortAttr(port_id, false, true); + } + static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase10G() ); } @@ -298,6 +320,11 @@ public: m_if_per_card = 4; } + TRexPortAttr * create_port_attr(uint8_t port_id) { + // disabling flow control on 40G using DPDK API causes the interface to malfunction + return new DpdkTRexPortAttr(port_id, false, false); + } + static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBase40G() ); } @@ -325,8 +352,6 @@ public: return TrexPlatformApi::IF_STAT_IPV4_ID | TrexPlatformApi::IF_STAT_PAYLOAD; } virtual int wait_for_stable_link(); - // disabling flow control on 40G using DPDK API causes the interface to malfunction - virtual bool flow_control_disable_supported(){return false;} virtual bool hw_rx_stat_supported(){return true;} virtual int verify_fw_ver(int i); virtual CFlowStatParser *get_flow_stat_parser(); @@ -347,6 +372,10 @@ public: CTRexExtendedDriverBaseVIC(){ } + TRexPortAttr * create_port_attr(uint8_t port_id) { + return new DpdkTRexPortAttr(port_id, false, false); + } + static CTRexExtendedDriverBase * create(){ return ( new CTRexExtendedDriverBaseVIC() ); } @@ -357,8 +386,6 @@ public: virtual int verify_fw_ver(int i) {return 0;} - bool flow_control_disable_supported(){return false;} - virtual void update_configuration(port_cfg_t * cfg); }; @@ -413,12 +440,12 @@ private: register_driver(std::string("rte_ixgbe_pmd"),CTRexExtendedDriverBase10G::create); register_driver(std::string("rte_igb_pmd"),CTRexExtendedDriverBase1G::create); register_driver(std::string("rte_i40e_pmd"),CTRexExtendedDriverBase40G::create); + register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBaseVIC::create); /* virtual devices */ register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBase1GVm::create); register_driver(std::string("rte_vmxnet3_pmd"),CTRexExtendedDriverBase1GVm::create); register_driver(std::string("rte_virtio_pmd"),CTRexExtendedDriverBase1GVm::create); - register_driver(std::string("rte_enic_pmd"),CTRexExtendedDriverBaseVIC::create); @@ -488,14 +515,6 @@ static inline int get_min_sample_rate(void){ return ( get_ex_drv()->get_min_sample_rate()); } -#define MAX_DPDK_ARGS 40 -static CPlatformYamlInfo global_platform_cfg_info; -static int global_dpdk_args_num ; -static char * global_dpdk_args[MAX_DPDK_ARGS]; -static char global_cores_str[100]; -static char global_prefix_str[100]; -static char global_loglevel_str[20]; - // cores =0==1,1*2,2,3,4,5,6 // An enum for all the option types enum { OPT_HELP, @@ -589,6 +608,7 @@ static CSimpleOpt::SOption parser_options[] = { OPT_NO_FLOW_CONTROL, "--no-flow-control-change", SO_NONE }, { OPT_VLAN, "--vlan", SO_NONE }, { OPT_CLIENT_CFG_FILE, "--client_cfg", SO_REQ_SEP }, + { OPT_CLIENT_CFG_FILE, "--client-cfg", SO_REQ_SEP }, { OPT_NO_KEYBOARD_INPUT ,"--no-key", SO_NONE }, { OPT_VIRT_ONE_TX_RX_QUEUE, "--vm-sim", SO_NONE }, { OPT_PREFIX, "--prefix", SO_REQ_SEP }, @@ -1443,9 +1463,107 @@ void CPhyEthIF::disable_flow_control(){ ret, m_port_id); } +/* +Get user frienly devices description from saved env. var +Changes certain attributes based on description +*/ +void DpdkTRexPortAttr::update_description(){ + struct rte_pci_addr pci_addr; + char pci[16]; + char * envvar; + std::string pci_envvar_name; + pci_addr = rte_eth_devices[m_port_id].pci_dev->addr; + snprintf(pci, sizeof(pci), "%04x:%02x:%02x.%d", pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function); + intf_info_st.pci_addr = pci; + pci_envvar_name = "pci" + intf_info_st.pci_addr; + std::replace(pci_envvar_name.begin(), pci_envvar_name.end(), ':', '_'); + std::replace(pci_envvar_name.begin(), pci_envvar_name.end(), '.', '_'); + envvar = std::getenv(pci_envvar_name.c_str()); + if (envvar) { + intf_info_st.description = envvar; + } else { + intf_info_st.description = "Unknown"; + } + if (intf_info_st.description.find("82599ES") != std::string::npos) { // works for 82599EB etc. DPDK does not distinguish them + flag_is_link_change_supported = false; + } + if (intf_info_st.description.find("82545EM") != std::string::npos) { // in virtual E1000, DPDK claims fc is supported, but it's not + flag_is_fc_change_supported = false; + flag_is_led_change_supported = false; + } + if ( CGlobalInfo::m_options.preview.getVMode() > 0){ + printf("port %d desc: %s\n", m_port_id, intf_info_st.description.c_str()); + } +} + +int DpdkTRexPortAttr::set_led(bool on){ + if (on) { + return rte_eth_led_on(m_port_id); + }else{ + return rte_eth_led_off(m_port_id); + } +} + +int DpdkTRexPortAttr::get_flow_ctrl(int &mode) { + int ret = rte_eth_dev_flow_ctrl_get(m_port_id, &fc_conf_tmp); + if (ret) { + return ret; + } + mode = (int) fc_conf_tmp.mode; + return 0; +} + +int DpdkTRexPortAttr::set_flow_ctrl(int mode) { + if (!flag_is_fc_change_supported) { + return -ENOTSUP; + } + int ret = rte_eth_dev_flow_ctrl_get(m_port_id, &fc_conf_tmp); + if (ret) { + return ret; + } + fc_conf_tmp.mode = (enum rte_eth_fc_mode) mode; + return rte_eth_dev_flow_ctrl_set(m_port_id, &fc_conf_tmp); +} + +void DpdkTRexPortAttr::reset_xstats() { + rte_eth_xstats_reset(m_port_id); +} + +int DpdkTRexPortAttr::get_xstats_values(xstats_values_t &xstats_values) { + int size = rte_eth_xstats_get(m_port_id, NULL, 0); + if (size < 0) { + return size; + } + xstats_values_tmp.resize(size); + xstats_values.resize(size); + size = rte_eth_xstats_get(m_port_id, xstats_values_tmp.data(), size); + if (size < 0) { + return size; + } + for (int i=0; i<size; i++) { + xstats_values[xstats_values_tmp[i].id] = xstats_values_tmp[i].value; + } + return 0; +} +int DpdkTRexPortAttr::get_xstats_names(xstats_names_t &xstats_names){ + int size = rte_eth_xstats_get_names(m_port_id, NULL, 0); + if (size < 0) { + return size; + } + xstats_names_tmp.resize(size); + xstats_names.resize(size); + size = rte_eth_xstats_get_names(m_port_id, xstats_names_tmp.data(), size); + if (size < 0) { + return size; + } + for (int i=0; i<size; i++) { + xstats_names[i] = xstats_names_tmp[i].name; + } + return 0; +} -void CPhyEthIF::dump_link(FILE *fd){ +void DpdkTRexPortAttr::dump_link(FILE *fd){ fprintf(fd,"port : %d \n",(int)m_port_id); fprintf(fd,"------------\n"); @@ -1461,32 +1579,66 @@ void CPhyEthIF::dump_link(FILE *fd){ fprintf(fd,"promiscuous : %d \n",get_promiscuous()); } -void CPhyEthIF::update_link_status(){ +void DpdkTRexPortAttr::update_device_info(){ + rte_eth_dev_info_get(m_port_id, &dev_info); +} + +void DpdkTRexPortAttr::get_supported_speeds(supp_speeds_t &supp_speeds){ + uint32_t speed_capa = dev_info.speed_capa; + if (speed_capa & ETH_LINK_SPEED_1G) + supp_speeds.push_back(ETH_SPEED_NUM_1G); + if (speed_capa & ETH_LINK_SPEED_10G) + supp_speeds.push_back(ETH_SPEED_NUM_10G); + if (speed_capa & ETH_LINK_SPEED_40G) + supp_speeds.push_back(ETH_SPEED_NUM_40G); + if (speed_capa & ETH_LINK_SPEED_100G) + supp_speeds.push_back(ETH_SPEED_NUM_100G); +} + +void DpdkTRexPortAttr::update_link_status(){ rte_eth_link_get(m_port_id, &m_link); } -void CPhyEthIF::update_link_status_nowait(){ - rte_eth_link_get_nowait(m_port_id, &m_link); +bool DpdkTRexPortAttr::update_link_status_nowait(){ + rte_eth_link new_link; + bool changed = false; + rte_eth_link_get_nowait(m_port_id, &new_link); + if (new_link.link_speed != m_link.link_speed || + new_link.link_duplex != m_link.link_duplex || + new_link.link_autoneg != m_link.link_autoneg || + new_link.link_status != m_link.link_status) { + changed = true; + } + m_link = new_link; + return changed; } -void CPhyEthIF::add_mac(char * mac){ +int DpdkTRexPortAttr::add_mac(char * mac){ struct ether_addr mac_addr; - int i=0; - for (i=0; i<6;i++) { + for (int i=0; i<6;i++) { mac_addr.addr_bytes[i] =mac[i]; } - rte_eth_dev_mac_addr_add(m_port_id, &mac_addr,0); + return rte_eth_dev_mac_addr_add(m_port_id, &mac_addr,0); } -void CPhyEthIF::set_promiscuous(bool enable){ +int DpdkTRexPortAttr::set_promiscuous(bool enable){ if (enable) { rte_eth_promiscuous_enable(m_port_id); }else{ rte_eth_promiscuous_disable(m_port_id); } + return 0; +} + +int DpdkTRexPortAttr::set_link_up(bool up){ + if (up) { + return rte_eth_dev_set_link_up(m_port_id); + }else{ + return rte_eth_dev_set_link_down(m_port_id); + } } -bool CPhyEthIF::get_promiscuous(){ +bool DpdkTRexPortAttr::get_promiscuous(){ int ret=rte_eth_promiscuous_get(m_port_id); if (ret<0) { rte_exit(EXIT_FAILURE, "rte_eth_promiscuous_get: " @@ -1498,7 +1650,7 @@ bool CPhyEthIF::get_promiscuous(){ } -void CPhyEthIF::macaddr_get(struct ether_addr *mac_addr){ +void DpdkTRexPortAttr::macaddr_get(struct ether_addr *mac_addr){ rte_eth_macaddr_get(m_port_id , mac_addr); } @@ -1929,12 +2081,22 @@ int CCoreEthIF::send_pkt_lat(CCorePerPort *lp_port, rte_mbuf_t *m, CVirtualIFPer int ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1); +#ifdef DELAY_IF_NEEDED while ( unlikely( ret != 1 ) ){ rte_delay_us(1); lp_stats->m_tx_queue_full += 1; ret = lp_port->m_port->tx_burst(lp_port->m_tx_queue_id_lat, &m, 1); } +#else + if ( unlikely( ret != 1 ) ) { + lp_stats->m_tx_drop ++; + rte_pktmbuf_free(m); + return 0; + } + +#endif + return ret; } @@ -2826,6 +2988,7 @@ public: void publish_async_data(bool sync_now, bool baseline = false); void publish_async_barrier(uint32_t key); + void publish_async_port_attr_changed(uint8_t port_id); void dump_stats(FILE *fd, CGlobalStats::DumpFormat format); @@ -2867,6 +3030,7 @@ public: CLatencyManager m_mg; // statefull RX core CRxCoreStateless m_rx_sl; // stateless RX core CTrexGlobalIoMode m_io_modes; + CTRexExtendedDriverBase * m_drv; private: CLatencyHWPort m_latency_vports[TREX_MAX_PORTS]; /* read hardware driver */ @@ -2920,7 +3084,7 @@ void CGlobalTRex::pre_test() { do { ret = pretest.resolve_all(); count++; - } while ((ret != true) && (count < 3)); + } while ((ret != true) && (count < 10)); if ( CGlobalInfo::m_options.preview.getVMode() > 0) { pretest.dump(stdout); @@ -3000,11 +3164,11 @@ bool CGlobalTRex::is_all_links_are_up(bool dump){ int i; for (i=0; i<m_max_ports; i++) { CPhyEthIF * _if=&m_ports[i]; - _if->update_link_status(); + _if->get_port_attr()->update_link_status(); if ( dump ){ _if->dump_stats(stdout); } - if ( _if->is_link_up() == false){ + if ( _if->get_port_attr()->is_link_up() == false){ all_link_are=false; break; } @@ -3234,11 +3398,11 @@ int CGlobalTRex::ixgbe_start(void){ _if->configure_rx_duplicate_rules(); if ( ! get_vm_one_queue_enable() && ! CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting() - && get_ex_drv()->flow_control_disable_supported()) { + && _if->get_port_attr()->is_fc_change_supported()) { _if->disable_flow_control(); } - _if->add_mac((char *)CGlobalInfo::m_options.get_src_mac_addr(i)); + _if->get_port_attr()->add_mac((char *)CGlobalInfo::m_options.get_src_mac_addr(i)); fflush(stdout); } @@ -3247,7 +3411,7 @@ int CGlobalTRex::ixgbe_start(void){ /* wait for ports to be stable */ get_ex_drv()->wait_for_stable_link(); - if ( !is_all_links_are_up(true) ){ + if ( !is_all_links_are_up(true) /*&& !get_is_stateless()*/ ){ // disable start with link down for now dump_links_status(stdout); rte_exit(EXIT_FAILURE, " " " one of the link is down \n"); @@ -3478,10 +3642,11 @@ int CGlobalTRex::ixgbe_prob_init(void){ } CTRexExtendedDriverDb::Ins()->set_driver_name(dev_info.driver_name); + m_drv = CTRexExtendedDriverDb::Ins()->get_drv(); // check if firmware version is new enough for (i = 0; i < m_max_ports; i++) { - if (CTRexExtendedDriverDb::Ins()->get_drv()->verify_fw_ver(i) < 0) { + if (m_drv->verify_fw_ver(i) < 0) { // error message printed by verify_fw_ver exit(1); } @@ -3552,9 +3717,8 @@ void CGlobalTRex::dump_config(FILE *fd){ void CGlobalTRex::dump_links_status(FILE *fd){ for (int i=0; i<m_max_ports; i++) { - CPhyEthIF * _if=&m_ports[i]; - _if->update_link_status_nowait(); - _if->dump_link(fd); + m_ports[i].get_port_attr()->update_link_status_nowait(); + m_ports[i].get_port_attr()->dump_link(fd); } } @@ -4001,11 +4165,37 @@ CGlobalTRex::publish_async_barrier(uint32_t key) { m_zmq_publisher.publish_barrier(key); } +void +CGlobalTRex:: publish_async_port_attr_changed(uint8_t port_id) { + Json::Value data; + data["port_id"] = port_id; + TRexPortAttr * _attr = m_ports[port_id].get_port_attr(); + + /* attributes */ + data["attr"]["speed"] = _attr->get_link_speed(); + data["attr"]["promiscuous"]["enabled"] = _attr->get_promiscuous(); + data["attr"]["link"]["up"] = _attr->is_link_up(); + int mode; + int ret = _attr->get_flow_ctrl(mode); + if (ret != 0) { + mode = -1; + } + data["attr"]["fc"]["mode"] = mode; + + m_zmq_publisher.publish_event(TrexPublisher::EVENT_PORT_ATTR_CHANGED, data); +} void CGlobalTRex::handle_slow_path() { m_stats_cnt+=1; + // update speed, link up/down etc. + for (int i=0; i<m_max_ports; i++) { + bool changed = m_ports[i].get_port_attr()->update_link_status_nowait(); + if (changed) { + publish_async_port_attr_changed(i); + } + } if ( CGlobalInfo::m_options.preview.get_no_keyboard() ==false ) { if ( m_io_modes.handle_io_modes() ) { @@ -4487,6 +4677,7 @@ bool CPhyEthIF::Create(uint8_t portid) { m_last_rx_rate = 0.0; m_last_tx_rate = 0.0; m_last_tx_pps = 0.0; + m_port_attr = g_trex.m_drv->create_port_attr(portid); return true; } @@ -6203,6 +6394,15 @@ static void trex_termination_handler(int signum) { * TODO: REMOVE THIS TO A SEPERATE FILE * **********************************************************/ +int TrexDpdkPlatformApi::get_xstats_values(uint8_t port_id, xstats_values_t &xstats_values) const { + return g_trex.m_ports[port_id].get_port_attr()->get_xstats_values(xstats_values); +} + +int TrexDpdkPlatformApi::get_xstats_names(uint8_t port_id, xstats_names_t &xstats_names) const { + return g_trex.m_ports[port_id].get_port_attr()->get_xstats_names(xstats_names); +} + + void TrexDpdkPlatformApi::get_port_num(uint8_t &port_num) const { port_num = g_trex.m_max_ports; } @@ -6248,19 +6448,18 @@ TrexDpdkPlatformApi::port_id_to_cores(uint8_t port_id, std::vector<std::pair<uin cores_id_list = lpt->get_core_list(); } + void TrexDpdkPlatformApi::get_interface_info(uint8_t interface_id, intf_info_st &info) const { struct ether_addr rte_mac_addr; info.driver_name = CTRexExtendedDriverDb::Ins()->get_driver_name(); - g_trex.m_ports[interface_id].update_link_status_nowait(); - g_trex.m_ports[interface_id].get_link_speed(&info.speed); info.has_crc = CTRexExtendedDriverDb::Ins()->get_drv()->has_crc_added(); /* mac INFO */ /* hardware */ - g_trex.m_ports[interface_id].macaddr_get(&rte_mac_addr); + g_trex.m_ports[interface_id].get_port_attr()->macaddr_get(&rte_mac_addr); assert(ETHER_ADDR_LEN == 6); /* software */ @@ -6268,6 +6467,7 @@ TrexDpdkPlatformApi::get_interface_info(uint8_t interface_id, intf_info_st &info memcpy(sw_macaddr, CGlobalInfo::m_options.get_dst_src_mac_addr(interface_id), 12); for (int i = 0; i < 6; i++) { + info.mac_info.hw_macaddr[i] = rte_mac_addr.addr_bytes[i]; info.mac_info.dst_macaddr[i] = sw_macaddr[i]; info.mac_info.src_macaddr[i] = sw_macaddr[6 + i]; @@ -6289,6 +6489,11 @@ TrexDpdkPlatformApi::publish_async_data_now(uint32_t key, bool baseline) const { } void +TrexDpdkPlatformApi::publish_async_port_attr_changed(uint8_t port_id) const { + g_trex.publish_async_port_attr_changed(port_id); +} + +void TrexDpdkPlatformApi::get_interface_stat_info(uint8_t interface_id, uint16_t &num_counters, uint16_t &capabilities) const { num_counters = CTRexExtendedDriverDb::Ins()->get_drv()->get_stat_counters_num(); capabilities = CTRexExtendedDriverDb::Ins()->get_drv()->get_rx_stat_capabilities(); @@ -6329,14 +6534,6 @@ int TrexDpdkPlatformApi::del_rx_flow_stat_rule(uint8_t port_id, uint16_t l3_type ->add_del_rx_flow_stat_rule(port_id, RTE_ETH_FILTER_DELETE, l3_type, l4_proto, ipv6_next_h, id); } -void TrexDpdkPlatformApi::set_promiscuous(uint8_t port_id, bool enabled) const { - g_trex.m_ports[port_id].set_promiscuous(enabled); -} - -bool TrexDpdkPlatformApi::get_promiscuous(uint8_t port_id) const { - return g_trex.m_ports[port_id].get_promiscuous(); -} - void TrexDpdkPlatformApi::flush_dp_messages() const { g_trex.check_for_dp_messages(); } @@ -6376,6 +6573,10 @@ CFlowStatParser *TrexDpdkPlatformApi::get_flow_stat_parser() const { return CTRexExtendedDriverDb::Ins()->get_drv()->get_flow_stat_parser(); } +TRexPortAttr *TrexDpdkPlatformApi::getPortAttrObj(uint8_t port_id) const { + return g_trex.m_ports[port_id].get_port_attr(); +} + /** * marks the control plane for a total server shutdown * diff --git a/src/main_dpdk.h b/src/main_dpdk.h index 97994c47..6402d106 100644 --- a/src/main_dpdk.h +++ b/src/main_dpdk.h @@ -87,7 +87,6 @@ class CPhyEthIF { void configure(uint16_t nb_rx_queue, uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf); - void macaddr_get(struct ether_addr *mac_addr); void get_stats(CPhyEthIFStats *stats); int dump_fdir_global_stats(FILE *fd); int reset_hw_flow_stats(); @@ -106,19 +105,7 @@ class CPhyEthIF { void configure_rx_duplicate_rules(); void start(); void stop(); - void update_link_status(); - void update_link_status_nowait(); - bool is_link_up(){ - return (m_link.link_status?true:false); - } - void get_link_speed(uint32_t *link_speed){ - *link_speed = m_link.link_speed; - } - void dump_link(FILE *fd); void disable_flow_control(); - void set_promiscuous(bool enable); - void add_mac(char * mac); - bool get_promiscuous(); void dump_stats(FILE *fd); void set_ignore_stats_base(CPreTestStats &pre_stats); void update_counters(); @@ -180,9 +167,9 @@ class CPhyEthIF { int get_rx_stat_capabilities(); const std::vector<std::pair<uint8_t, uint8_t>> & get_core_list(); + TRexPortAttr * get_port_attr() { return m_port_attr; } private: - struct rte_eth_link m_link; uint8_t m_port_id; uint8_t m_rx_queue; uint64_t m_sw_try_tx_pkt; @@ -193,6 +180,7 @@ class CPhyEthIF { CPPSMeasure m_pps_rx; CPhyEthIFStats m_stats; CPhyEthIgnoreStats m_ignore_stats; + TRexPortAttr *m_port_attr; float m_last_tx_rate; float m_last_rx_rate; float m_last_tx_pps; diff --git a/src/pal/linux/rte_ethdev_includes.h b/src/pal/linux/rte_ethdev_includes.h new file mode 100644 index 00000000..e957b68b --- /dev/null +++ b/src/pal/linux/rte_ethdev_includes.h @@ -0,0 +1,27 @@ +#ifndef __RTE_ETHDEV_INCLUDES_H__ +#define __RTE_ETHDEV_INCLUDES_H__ + +struct rte_eth_link { + int link_autoneg; + int link_speed; + int link_duplex; + int link_status; +}; + + +enum rte_eth_fc_mode { +}; + +struct rte_eth_xstat { +}; + +struct rte_eth_xstat_name { +}; + +struct rte_eth_fc_conf { +}; + +struct rte_eth_dev_info { +}; + +#endif /* __RTE_ETHDEV_INCLUDES_H__ */ diff --git a/src/pal/linux_dpdk/rte_ethdev_includes.h b/src/pal/linux_dpdk/rte_ethdev_includes.h new file mode 100644 index 00000000..0429fe44 --- /dev/null +++ b/src/pal/linux_dpdk/rte_ethdev_includes.h @@ -0,0 +1,6 @@ +#ifndef __RTE_ETHDEV_INCLUDES_H__ +#define __RTE_ETHDEV_INCLUDES_H__ + +#include <rte_ethdev.h> + +#endif /* __RTE_ETHDEV_INCLUDES_H__ */
\ No newline at end of file diff --git a/src/publisher/trex_publisher.h b/src/publisher/trex_publisher.h index fb7226c4..522c8c69 100644 --- a/src/publisher/trex_publisher.h +++ b/src/publisher/trex_publisher.h @@ -49,6 +49,7 @@ public: EVENT_PORT_ACQUIRED = 5, EVENT_PORT_RELEASED = 6, EVENT_PORT_ERROR = 7, + EVENT_PORT_ATTR_CHANGED = 8, EVENT_SERVER_STOPPED = 100, diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 342ec594..109cc1a4 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -295,6 +295,8 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { string src_macaddr; string dst_macaddr; string pci_addr; + string description; + supp_speeds_t supp_speeds; int numa; TrexStatelessPort *port = main->get_port_by_id(i); @@ -302,10 +304,13 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { port->get_macaddr(hw_macaddr, src_macaddr, dst_macaddr); port->get_pci_info(pci_addr, numa); + main->get_platform_api()->getPortAttrObj(i)->get_description(description); + main->get_platform_api()->getPortAttrObj(i)->get_supported_speeds(supp_speeds); section["ports"][i]["index"] = i; section["ports"][i]["driver"] = driver; + section["ports"][i]["description"] = description; section["ports"][i]["hw_macaddr"] = hw_macaddr; section["ports"][i]["src_macaddr"] = src_macaddr; section["ports"][i]["dst_macaddr"] = dst_macaddr; @@ -326,6 +331,14 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { } section["ports"][i]["rx"]["counters"] = port->get_rx_count_num(); section["ports"][i]["speed"] = (uint16_t) speed / 1000; + section["ports"][i]["is_fc_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_fc_change_supported(); + section["ports"][i]["is_led_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_led_change_supported(); + section["ports"][i]["is_link_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_link_change_supported(); + section["ports"][i]["is_virtual"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_virtual(); + section["ports"][i]["supp_speeds"] = Json::arrayValue; + for (int speed_id=0; speed_id<supp_speeds.size(); speed_id++) { + section["ports"][i]["supp_speeds"].append(supp_speeds[speed_id]); + } } @@ -346,19 +359,45 @@ trex_rpc_cmd_rc_e TrexRpcCmdSetPortAttr::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_port(params, result); - TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); const Json::Value &attr = parse_object(params, "attr", result); - + int ret = 0; + bool changed = false; /* iterate over all attributes in the dict */ for (const std::string &name : attr.getMemberNames()) { - - /* handle promiscuous */ if (name == "promiscuous") { bool enabled = parse_bool(attr[name], "enabled", result); - port->set_promiscuous(enabled); + ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_promiscuous(enabled); + } + else if (name == "link_status") { + bool up = parse_bool(attr[name], "up", result); + ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_link_up(up); + } + else if (name == "led_status") { + bool on = parse_bool(attr[name], "on", result); + ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_led(on); + } else if (name == "flow_ctrl_mode") { + int mode = parse_int(attr[name], "mode", result); + ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_flow_ctrl(mode); + } else { + generate_execute_err(result, "Not recognized attribute: " + name); + break; + } + if (ret != 0){ + if ( ret == -ENOTSUP ) { + generate_execute_err(result, "Error applying " + name + ": operation is not supported for this NIC."); + } + else if (ret) { + generate_execute_err(result, "Error applying " + name + " attribute, return value: " + to_string(ret)); + } + break; + } else { + changed = true; } } + if (changed) { + get_stateless_obj()->get_platform_api()->publish_async_port_attr_changed(port_id); + } result["result"] = Json::objectValue; return (TREX_RPC_CMD_OK); @@ -437,6 +476,60 @@ TrexRpcCmdRelease::_run(const Json::Value ¶ms, Json::Value &result) { } /** + * get port extended stats names (keys of dict) + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetPortXStatsNames::_run(const Json::Value ¶ms, Json::Value &result) { + + uint8_t port_id = parse_port(params, result); + xstats_names_t xstats_names; + + int ret = get_stateless_obj()->get_platform_api()->get_xstats_names(port_id, xstats_names); + if (ret < 0) { + if ( ret == -ENOTSUP ) { + generate_execute_err(result, "Operation not supported"); + } + else if (ret) { + generate_execute_err(result, "Operation failed, error code: " + to_string(ret)); + } + } else { + for (int i=0; i<xstats_names.size(); i++) { + result["result"]["xstats_names"].append(xstats_names[i]); + } + } + + return (TREX_RPC_CMD_OK); +} + +/** + * get port extended stats (values of dict) + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetPortXStatsValues::_run(const Json::Value ¶ms, Json::Value &result) { + + uint8_t port_id = parse_port(params, result); + xstats_values_t xstats_values; + + int ret = get_stateless_obj()->get_platform_api()->get_xstats_values(port_id, xstats_values); + if (ret < 0) { + if ( ret == -ENOTSUP ) { + generate_execute_err(result, "Operation not supported"); + } + else if (ret) { + generate_execute_err(result, "Operation failed, error code: " + to_string(ret)); + } + } else { + for (int i=0; i<xstats_values.size(); i++) { + result["result"]["xstats_values"].append((Json::Value::UInt64) xstats_values[i]); + } + } + + return (TREX_RPC_CMD_OK); +} + +/** * get port stats * */ @@ -475,9 +568,17 @@ TrexRpcCmdGetPortStatus::_run(const Json::Value ¶ms, Json::Value &result) { result["result"]["owner"] = (port->get_owner().is_free() ? "" : port->get_owner().get_name()); result["result"]["state"] = port->get_state_as_string(); result["result"]["max_stream_id"] = port->get_max_stream_id(); + result["result"]["speed"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_link_speed(); /* attributes */ - result["result"]["attr"]["promiscuous"]["enabled"] = port->get_promiscuous(); + result["result"]["attr"]["promiscuous"]["enabled"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_promiscuous(); + result["result"]["attr"]["link"]["up"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->is_link_up(); + int mode; + int ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_flow_ctrl(mode); + if (ret != 0) { + mode = -1; + } + result["result"]["attr"]["fc"]["mode"] = mode; return (TREX_RPC_CMD_OK); } diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index a68796ae..5fde1d0c 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -87,9 +87,11 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdRelease, "release", 1, true, APIClass: /** * port commands */ -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, false, APIClass::API_CLASS_TYPE_CORE); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStatus, "get_port_status", 1, false, APIClass::API_CLASS_TYPE_CORE); -TREX_RPC_CMD_DEFINE(TrexRpcCmdSetPortAttr, "set_port_attr", 3, false, APIClass::API_CLASS_TYPE_CORE); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, false, APIClass::API_CLASS_TYPE_CORE); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStatus, "get_port_status", 1, false, APIClass::API_CLASS_TYPE_CORE); +TREX_RPC_CMD_DEFINE(TrexRpcCmdSetPortAttr, "set_port_attr", 2, true, APIClass::API_CLASS_TYPE_CORE); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortXStatsValues, "get_port_xstats_values", 1, false, APIClass::API_CLASS_TYPE_CORE); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortXStatsNames, "get_port_xstats_names", 1, false, APIClass::API_CLASS_TYPE_CORE); /** * stream cmds diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp index 28145f13..265d426b 100644 --- a/src/rpc-server/trex_rpc_cmd.cpp +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -87,7 +87,7 @@ TrexRpcCommand::check_param_count(const Json::Value ¶ms, int expected, Json: if (params.size() < expected) { std::stringstream ss; - ss << "method expects at least '" << expected << "' parameter(s), '" << params.size() << "' provided"; + ss << "method '" << m_name << "' expects at least " << expected << " parameter(s), " << params.size() << " provided"; generate_parse_err(result, ss.str()); } } diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp index 762dd614..cddf19b9 100644 --- a/src/rpc-server/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -47,6 +47,8 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() { register_command(new TrexRpcCmdGetPortStats()); register_command(new TrexRpcCmdGetPortStatus()); register_command(new TrexRpcCmdSetPortAttr()); + register_command(new TrexRpcCmdGetPortXStatsValues()); + register_command(new TrexRpcCmdGetPortXStatsNames()); /* stream commands */ diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp index 9d9de53a..4fa2447d 100644 --- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp @@ -192,7 +192,9 @@ void TrexJsonRpcV2Parser::parse_single_request(Json::Value &request, /* lookup the method in the DB */ TrexRpcCommand * rpc_cmd = TrexRpcCommandsTable::get_instance().lookup(method_name); if (!rpc_cmd) { - commands.push_back(new JsonRpcError(msg_id, JSONRPC_V2_ERR_METHOD_NOT_FOUND, "Method not registered")); + std::stringstream err; + err << "Method " << method_name << " not registered"; + commands.push_back(new JsonRpcError(msg_id, JSONRPC_V2_ERR_METHOD_NOT_FOUND, err.str())); return; } diff --git a/src/stateless/cp/trex_stateless.cpp b/src/stateless/cp/trex_stateless.cpp index 22389d6a..6029cbd5 100644 --- a/src/stateless/cp/trex_stateless.cpp +++ b/src/stateless/cp/trex_stateless.cpp @@ -152,10 +152,8 @@ TrexStateless::get_dp_core_count() { void TrexStateless::encode_stats(Json::Value &global) { - const TrexPlatformApi *api = get_stateless_obj()->get_platform_api(); - TrexPlatformGlobalStats stats; - api->get_global_stats(stats); + m_platform_api->get_global_stats(stats); global["cpu_util"] = stats.m_stats.m_cpu_util; global["rx_cpu_util"] = stats.m_stats.m_rx_cpu_util; diff --git a/src/stateless/cp/trex_stateless.h b/src/stateless/cp/trex_stateless.h index 7ea669df..3a1a2c24 100644 --- a/src/stateless/cp/trex_stateless.h +++ b/src/stateless/cp/trex_stateless.h @@ -137,6 +137,18 @@ public: void shutdown(); /** + * fetch xstats names (keys of dict) + * + */ + void encode_xstats_names(Json::Value &global); + + /** + * fetch xstats values + * + */ + void encode_xstats_values(Json::Value &global); + + /** * fetch all the stats * */ diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 58410fea..9bb20990 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -158,6 +158,7 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api m_port_id = port_id; m_port_state = PORT_STATE_IDLE; + m_platform_api = api; /* get the platform specific data */ api->get_interface_info(port_id, m_api_info); @@ -252,6 +253,11 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, /* on start - we can only provide absolute values */ assert(mul.m_op == TrexPortMultiplier::OP_ABS); + /* check link state */ + if ( !m_platform_api->getPortAttrObj(m_port_id)->is_link_up() && !force ) { + throw TrexException("Link state is DOWN."); + } + /* caclulate the effective factor for DP */ double factor = calculate_effective_factor(mul, force); @@ -278,7 +284,7 @@ TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, feeder.set_status(true); - /* generate a message to all the relevant DP cores to start transmitting */ + /* generate a message to all the relevant DP cores to stop transmitting */ assert(m_pending_async_stop_event == TrexDpPortEvents::INVALID_ID); m_pending_async_stop_event = m_dp_events.create_event(new AsyncStopEvent()); @@ -581,7 +587,7 @@ void TrexStatelessPort::get_properties(std::string &driver, uint32_t &speed) { driver = m_api_info.driver_name; - speed = m_api_info.speed; + speed = m_platform_api->getPortAttrObj(m_port_id)->get_link_speed(); } bool @@ -609,10 +615,8 @@ TrexStatelessPort::change_state(port_state_e new_state) { void TrexStatelessPort::encode_stats(Json::Value &port) { - const TrexPlatformApi *api = get_stateless_obj()->get_platform_api(); - TrexPlatformInterfaceStats stats; - api->get_interface_stats(m_port_id, stats); + m_platform_api->get_interface_stats(m_port_id, stats); port["tx_bps"] = stats.m_stats.m_tx_bps; port["rx_bps"] = stats.m_stats.m_rx_bps; @@ -664,7 +668,7 @@ TrexStatelessPort::send_message_to_rx(TrexStatelessCpToRxMsgBase *msg) { uint64_t TrexStatelessPort::get_port_speed_bps() const { - return (uint64_t) m_api_info.speed * 1000 * 1000; + return (uint64_t) m_platform_api->getPortAttrObj(m_port_id)->get_link_speed() * 1000 * 1000; } static inline double @@ -687,6 +691,20 @@ TrexStatelessPort::calculate_effective_factor(const TrexPortMultiplier &mul, boo throw TrexException(ss.str()); } + /* L1 BW must be positive */ + if (expected_l1_rate <= 0){ + stringstream ss; + ss << "Effective bandwidth must be positive, got: " << expected_l1_rate; + throw TrexException(ss.str()); + } + + /* factor must be positive */ + if (factor <= 0) { + stringstream ss; + ss << "Factor must be positive, got: " << factor; + throw TrexException(ss.str()); + } + return factor; } @@ -869,18 +887,6 @@ TrexStatelessPort::get_port_effective_rate(double &pps, } - -void -TrexStatelessPort::set_promiscuous(bool enabled) { - get_stateless_obj()->get_platform_api()->set_promiscuous(m_port_id, enabled); -} - -bool -TrexStatelessPort::get_promiscuous() { - return get_stateless_obj()->get_platform_api()->get_promiscuous(m_port_id); -} - - void TrexStatelessPort::get_macaddr(std::string &hw_macaddr, std::string &src_macaddr, diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 147efc70..e2a2aeba 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -363,14 +363,6 @@ public: double &percentage); - /** - * set port promiscuous on/off - * - * @param enabled - */ - void set_promiscuous(bool enabled); - bool get_promiscuous(); - void get_macaddr(std::string &hw_macaddr, std::string &src_macaddr, std::string &dst_macaddr); @@ -443,6 +435,7 @@ private: port_state_e m_port_state; TrexPlatformApi::intf_info_st m_api_info; + const TrexPlatformApi *m_platform_api; uint16_t m_rx_count_num; uint16_t m_rx_caps; diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h index c944df4a..43fee09b 100644 --- a/src/stateless/cp/trex_streams_compiler.h +++ b/src/stateless/cp/trex_streams_compiler.h @@ -309,7 +309,7 @@ public: } double get_factor_pps(double req_pps) const { - if ( (req_pps - m_fixed.m_pps) <= 0 ) { + if ( (req_pps - m_fixed.m_pps) < 0 ) { std::stringstream ss; ss << "current stream configuration enforces a minimum rate of '" << m_fixed.m_pps << "' pps"; throw TrexException(ss.str()); @@ -319,7 +319,7 @@ public: } double get_factor_bps_l1(double req_bps_l1) const { - if ( (req_bps_l1 - m_fixed.m_bps_l1) <= 0 ) { + if ( (req_bps_l1 - m_fixed.m_bps_l1) < 0 ) { std::stringstream ss; ss << "current stream configuration enforces a minimum rate of '" << m_fixed.m_bps_l1 << "' BPS L1"; throw TrexException(ss.str()); @@ -329,7 +329,7 @@ public: } double get_factor_bps_l2(double req_bps_l2) const { - if ( (req_bps_l2 - m_fixed.m_bps_l2) <= 0 ) { + if ( (req_bps_l2 - m_fixed.m_bps_l2) < 0 ) { std::stringstream ss; ss << "current stream configuration enforces a minimum rate of '" << m_fixed.m_bps_l2 << "' BPS L2"; throw TrexException(ss.str()); diff --git a/src/trex_defs.h b/src/trex_defs.h index c659c337..8a4bf664 100644 --- a/src/trex_defs.h +++ b/src/trex_defs.h @@ -16,6 +16,7 @@ limitations under the License. #include <set> #include <queue> #include <vector> +#include <string> #ifndef __TREX_DEFS_H__ #define __TREX_DEFS_H__ @@ -52,5 +53,8 @@ struct cpu_vct_st { typedef std::set<uint32_t> flow_stat_active_t; typedef std::set<uint32_t>::iterator flow_stat_active_it_t; typedef std::vector<cpu_vct_st> cpu_util_full_t; +typedef std::vector<std::string> xstats_names_t; +typedef std::vector<uint64_t> xstats_values_t; +typedef std::vector<uint32_t> supp_speeds_t; #endif diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h new file mode 100755 index 00000000..9231e263 --- /dev/null +++ b/src/trex_port_attr.h @@ -0,0 +1,164 @@ +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_PORT_ATTR_H__ +#define __TREX_PORT_ATTR_H__ + +#include <string> +#include <vector> +#include "rte_ethdev_includes.h" +#include "trex_defs.h" + + +class TRexPortAttr { +public: + virtual ~TRexPortAttr(){} + +/* UPDATES */ + virtual void update_link_status() = 0; + virtual bool update_link_status_nowait() = 0; // returns true if the status was changed + virtual void update_device_info() = 0; + virtual void reset_xstats() = 0; + virtual void update_description() = 0; + +/* GETTERS */ + virtual bool get_promiscuous() = 0; + virtual void macaddr_get(struct ether_addr *mac_addr) = 0; + virtual uint32_t get_link_speed() { return m_link.link_speed; } // L1 Mbps + virtual bool is_link_duplex() { return (m_link.link_duplex ? true : false); } + virtual bool is_link_autoneg() { return (m_link.link_autoneg ? true : false); } + virtual bool is_link_up() { return (m_link.link_status ? true : false); } + virtual int get_xstats_values(xstats_values_t &xstats_values) = 0; + virtual int get_xstats_names(xstats_names_t &xstats_names) = 0; + virtual int get_flow_ctrl(int &mode) = 0; + virtual bool is_virtual() { return flag_is_virtual; } + virtual bool is_fc_change_supported() { return flag_is_fc_change_supported; } + virtual bool is_led_change_supported() { return flag_is_led_change_supported; } + virtual bool is_link_change_supported() { return flag_is_link_change_supported; } + virtual void get_description(std::string &description) { description = intf_info_st.description; } + virtual void get_supported_speeds(supp_speeds_t &supp_speeds) = 0; + +/* SETTERS */ + virtual int set_promiscuous(bool enabled) = 0; + virtual int add_mac(char * mac) = 0; + virtual int set_link_up(bool up) = 0; + virtual int set_flow_ctrl(int mode) = 0; + virtual int set_led(bool on) = 0; + +/* DUMPS */ + virtual void dump_link(FILE *fd) = 0; + +protected: + uint8_t m_port_id; + rte_eth_link m_link; + struct rte_eth_dev_info dev_info; + bool flag_is_virtual; + bool flag_is_fc_change_supported; + bool flag_is_led_change_supported; + bool flag_is_link_change_supported; + + struct intf_info_st { + std::string pci_addr; + std::string description; + int numa_node; + }intf_info_st; + +}; + +class DpdkTRexPortAttr : public TRexPortAttr { +public: + + DpdkTRexPortAttr(uint8_t port_id, bool is_virtual, bool fc_change_allowed) { + m_port_id = port_id; + flag_is_virtual = is_virtual; + int tmp; + flag_is_fc_change_supported = fc_change_allowed && (get_flow_ctrl(tmp) != -ENOTSUP); + flag_is_led_change_supported = (set_led(true) != -ENOTSUP); + flag_is_link_change_supported = (set_link_up(true) != -ENOTSUP); + update_description(); + update_device_info(); + } + +/* UPDATES */ + virtual void update_link_status(); + virtual bool update_link_status_nowait(); // returns true if the status was changed + virtual void update_device_info(); + virtual void reset_xstats(); + virtual void update_description(); + +/* GETTERS */ + virtual bool get_promiscuous(); + virtual void macaddr_get(struct ether_addr *mac_addr); + virtual int get_xstats_values(xstats_values_t &xstats_values); + virtual int get_xstats_names(xstats_names_t &xstats_names); + virtual int get_flow_ctrl(int &mode); + virtual void get_supported_speeds(supp_speeds_t &supp_speeds); + +/* SETTERS */ + virtual int set_promiscuous(bool enabled); + virtual int add_mac(char * mac); + virtual int set_link_up(bool up); + virtual int set_flow_ctrl(int mode); + virtual int set_led(bool on); + + +/* DUMPS */ + virtual void dump_link(FILE *fd); + +private: + rte_eth_fc_conf fc_conf_tmp; + std::vector <struct rte_eth_xstat> xstats_values_tmp; + std::vector <struct rte_eth_xstat_name> xstats_names_tmp; + +}; + + +class SimTRexPortAttr : public TRexPortAttr { +public: + SimTRexPortAttr() { + m_link.link_speed = 10000; + m_link.link_duplex = 1; + m_link.link_autoneg = 0; + m_link.link_status = 1; + flag_is_virtual = true; + flag_is_fc_change_supported = false; + flag_is_led_change_supported = false; + flag_is_link_change_supported = false; + } + + /* DUMMY */ + void update_link_status() {} + bool update_link_status_nowait() { return false; } + void update_device_info() {} + void reset_xstats() {} + void update_description() {} + bool get_promiscuous() { return false; } + void macaddr_get(struct ether_addr *mac_addr) {} + int get_xstats_values(xstats_values_t &xstats_values) { return -ENOTSUP; } + int get_xstats_names(xstats_names_t &xstats_names) { return -ENOTSUP; } + int get_flow_ctrl(int &mode) { return -ENOTSUP; } + void get_description(std::string &description) {} + void get_supported_speeds(supp_speeds_t &supp_speeds) {} + int set_promiscuous(bool enabled) { return -ENOTSUP; } + int add_mac(char * mac) { return -ENOTSUP; } + int set_link_up(bool up) { return -ENOTSUP; } + int set_flow_ctrl(int mode) { return -ENOTSUP; } + int set_led(bool on) { return -ENOTSUP; } + void dump_link(FILE *fd) {} +}; + + +#endif /* __TREX_PORT_ATTR_H__ */ diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp index 864c86f8..094a3de8 100755 --- a/src/utl_yaml.cpp +++ b/src/utl_yaml.cpp @@ -27,44 +27,8 @@ limitations under the License. #define INADDRSZ 4 -static int my_inet_pton4(const char *src, unsigned char *dst) -{ - static const char digits[] = "0123456789"; - int saw_digit, octets, ch; - unsigned char tmp[INADDRSZ], *tp; - - saw_digit = 0; - octets = 0; - *(tp = tmp) = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - if ((pch = strchr(digits, ch)) != NULL) { - unsigned int _new = *tp * 10 + (pch - digits); - - if (_new > 255) - return (0); - if (! saw_digit) { - if (++octets > 4) - return (0); - saw_digit = 1; - } - *tp = (unsigned char)_new; - } else if (ch == '.' && saw_digit) { - if (octets == 4) - return (0); - *++tp = 0; - saw_digit = 0; - } else - return (0); - } - if (octets < 4) - return (0); - - memcpy(dst, tmp, INADDRSZ); - return (1); -} - +extern int my_inet_pton4(const char *src, unsigned char *dst); +extern int my_inet_pton6(const char *src, unsigned char *dst); bool utl_yaml_read_ip_addr(const YAML::Node& node, const std::string &name, @@ -270,8 +234,6 @@ YAMLParserWrapper::parse_map(const YAML::Node &node, const std::string &name) { uint32_t YAMLParserWrapper::parse_ip(const YAML::Node &node, const std::string &name) { - - try { std::string ip_str; uint32_t ip_num; |