summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xlinux/ws_main.py1
-rwxr-xr-xlinux_dpdk/ws_main.py3
-rwxr-xr-xscripts/automation/regression/CPlatform.py8
-rw-r--r--scripts/automation/regression/functional_tests/cpp_gtests_test.py46
-rwxr-xr-xscripts/automation/regression/functional_tests/platform_dual_if_obj_test.py10
-rwxr-xr-xscripts/automation/regression/functional_tests/platform_if_obj_test.py4
-rwxr-xr-xscripts/automation/regression/platform_cmd_link.py19
-rw-r--r--scripts/automation/regression/setups/trex-dan/config.yaml4
-rw-r--r--scripts/automation/regression/setups/trex25/config.yaml16
-rwxr-xr-xscripts/automation/regression/stateful_tests/trex_general_test.py9
-rwxr-xr-xscripts/automation/regression/stateful_tests/trex_ipv6_test.py2
-rwxr-xr-xscripts/automation/regression/stateful_tests/trex_rx_test.py2
-rwxr-xr-xscripts/automation/regression/stateless_tests/stl_benchmark_test.py13
-rw-r--r--scripts/automation/regression/stateless_tests/stl_general_test.py27
-rw-r--r--scripts/automation/regression/stateless_tests/stl_performance_test.py20
-rw-r--r--scripts/automation/regression/trex.py1
-rwxr-xr-xscripts/automation/regression/trex_unit_test.py30
-rwxr-xr-xscripts/automation/trex_control_plane/server/singleton_daemon.py1
-rwxr-xr-xscripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py4
-rwxr-xr-xscripts/automation/trex_control_plane/stf/trex_stf_lib/trex_exceptions.py5
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py37
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py127
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py2
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py2
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py60
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py187
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py113
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/common.py19
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/constants.py26
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py61
-rwxr-xr-xscripts/dpdk_nic_bind.py11
-rwxr-xr-xscripts/dpdk_setup_ports.py27
-rwxr-xr-xscripts/t-rex-6425
-rwxr-xr-xsignedoff/yarslavbrustinov4
-rw-r--r--src/debug.cpp7
-rw-r--r--src/dpdk/drivers/net/virtio/virtio_ethdev.c2
-rw-r--r--src/dpdk/drivers/net/vmxnet3/vmxnet3_ethdev.c2
-rw-r--r--src/inet_pton.cpp172
-rw-r--r--src/internal_api/trex_platform_api.h34
-rw-r--r--src/main_dpdk.cpp293
-rw-r--r--src/main_dpdk.h16
-rw-r--r--src/pal/linux/rte_ethdev_includes.h27
-rw-r--r--src/pal/linux_dpdk/rte_ethdev_includes.h6
-rw-r--r--src/publisher/trex_publisher.h1
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp113
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h8
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp2
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp2
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp4
-rw-r--r--src/stateless/cp/trex_stateless.cpp4
-rw-r--r--src/stateless/cp/trex_stateless.h12
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp42
-rw-r--r--src/stateless/cp/trex_stateless_port.h9
-rw-r--r--src/stateless/cp/trex_streams_compiler.h6
-rw-r--r--src/trex_defs.h4
-rwxr-xr-xsrc/trex_port_attr.h164
-rwxr-xr-xsrc/utl_yaml.cpp42
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 &params, 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 &params, 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 &params, 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 &params, 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 &params, Json::Value &result) {
}
/**
+ * get port extended stats names (keys of dict)
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetPortXStatsNames::_run(const Json::Value &params, 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 &params, 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 &params, 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 &params, 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;