summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xVERSION2
-rwxr-xr-xdoc/release_notes.asciidoc11
-rwxr-xr-xdoc/trex_book.asciidoc1
-rw-r--r--scripts/automation/regression/setups/kiwi02/benchmark.yaml12
-rw-r--r--scripts/automation/regression/setups/trex21/benchmark.yaml155
-rw-r--r--scripts/automation/regression/setups/trex21/config.yaml40
-rwxr-xr-xscripts/automation/regression/stateful_tests/trex_general_test.py4
-rwxr-xr-xscripts/automation/regression/stateful_tests/trex_imix_test.py2
-rw-r--r--scripts/automation/regression/stateless_tests/stl_rx_test.py40
-rwxr-xr-xscripts/automation/trex_control_plane/stf/trex_stf_lib/trex_client.py9
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py2
-rw-r--r--scripts/ko/3.10.0-514.el7.x86_64/igb_uio.kobin0 -> 241456 bytes
-rwxr-xr-xscripts/trex-cfg15
-rwxr-xr-xscripts/trex_show_threads.py6
-rwxr-xr-xsrc/bp_sim.h8
-rw-r--r--src/main_dpdk.cpp293
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp4
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp24
18 files changed, 444 insertions, 184 deletions
diff --git a/VERSION b/VERSION
index 22e6ffa6..287b66a7 100755
--- a/VERSION
+++ b/VERSION
@@ -1,4 +1,4 @@
-v2.14
+v2.15
diff --git a/doc/release_notes.asciidoc b/doc/release_notes.asciidoc
index a3bf54cc..7bf6fd12 100755
--- a/doc/release_notes.asciidoc
+++ b/doc/release_notes.asciidoc
@@ -23,6 +23,17 @@ ifdef::backend-docbook[]
endif::backend-docbook[]
+== Release 2.15 ==
+
+* XL710/X710 VF mode work (SR-IOV) works better now
+* 599 VF mode work (SR-IOV) is not supported due to issues
+
+=== fix issues: ===
+
+* link:https://trex-tgn.cisco.com/youtrack/issue/trex-333[trex-333]
+* link:https://trex-tgn.cisco.com/youtrack/issue/trex-331[trex-331]
+
+
== Release 2.14 ==
* Another performance improvement in Stateful case with high active flows. There is less burstiness.
diff --git a/doc/trex_book.asciidoc b/doc/trex_book.asciidoc
index 16f9248d..aba11609 100755
--- a/doc/trex_book.asciidoc
+++ b/doc/trex_book.asciidoc
@@ -2551,7 +2551,6 @@ NIC with two ports will work better from performance prospective, so it is bette
==== Limitation/Issues
* Stateless mode ``per stream statistics'' feature is handled in software (No hardware support like in X710 card).
-* link:https://trex-tgn.cisco.com/youtrack/issue/trex-260[64B performance issue]
* link:https://trex-tgn.cisco.com/youtrack/issue/trex-261[Latency issue]
* link:https://trex-tgn.cisco.com/youtrack/issue/trex-262[Statful RX out of order]
* link:https://trex-tgn.cisco.com/youtrack/issue/trex-273[Fedora 21 & OFED 3.4.1]
diff --git a/scripts/automation/regression/setups/kiwi02/benchmark.yaml b/scripts/automation/regression/setups/kiwi02/benchmark.yaml
index 1eefccaf..b6055366 100644
--- a/scripts/automation/regression/setups/kiwi02/benchmark.yaml
+++ b/scripts/automation/regression/setups/kiwi02/benchmark.yaml
@@ -272,7 +272,7 @@ test_performance_vm_single_cpu:
cfg:
mult : "90%"
mpps_per_core_golden :
- min: 11.2
+ min: 10.0
max: 13.1
@@ -280,7 +280,7 @@ test_performance_vm_single_cpu_cached:
cfg:
mult : "90%"
mpps_per_core_golden :
- min: 20.5
+ min: 18.0
max: 25.0
@@ -289,7 +289,7 @@ test_performance_syn_attack_single_cpu:
cfg:
mult : "90%"
mpps_per_core_golden :
- min: 9.3
+ min: 8.0
max: 11.5
test_performance_vm_multi_cpus:
@@ -297,7 +297,7 @@ test_performance_vm_multi_cpus:
core_count : 4
mult : "90%"
mpps_per_core_golden :
- min: 9.7
+ min: 8.0
max: 12.5
@@ -306,7 +306,7 @@ test_performance_vm_multi_cpus_cached:
core_count : 4
mult : "90%"
mpps_per_core_golden :
- min: 19.0
+ min: 18.0
max: 22.0
test_performance_syn_attack_multi_cpus:
@@ -314,6 +314,6 @@ test_performance_syn_attack_multi_cpus:
core_count : 4
mult : "90%"
mpps_per_core_golden :
- min: 8.4
+ min: 8.0
max: 10.5
diff --git a/scripts/automation/regression/setups/trex21/benchmark.yaml b/scripts/automation/regression/setups/trex21/benchmark.yaml
new file mode 100644
index 00000000..b366b3fb
--- /dev/null
+++ b/scripts/automation/regression/setups/trex21/benchmark.yaml
@@ -0,0 +1,155 @@
+################################################################
+#### TRex benchmark configuration file ####
+################################################################
+
+### stateful ###
+
+test_jumbo:
+ multiplier : 2.8
+ cores : 1
+ bw_per_core : 106.652
+
+
+test_routing_imix:
+ multiplier : 0.5
+ cores : 1
+ bw_per_core : 11.577
+
+
+test_routing_imix_64:
+ multiplier : 28
+ cores : 1
+ bw_per_core : 2.030
+
+
+test_static_routing_imix_asymmetric:
+ multiplier : 0.8
+ cores : 1
+ bw_per_core : 13.742
+
+
+
+### stateless ###
+
+test_CPU_benchmark:
+ profiles:
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 64}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 64, stream_count: 10}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 64, stream_count: 100}
+ cpu_util : 1
+ bw_per_core : 1
+
+# causes queue full
+# - name : stl/udp_for_benchmarks.py
+# kwargs : {packet_len: 64, stream_count: 1000}
+# cpu_util : 1
+# bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 128}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 256}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 512}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 1500}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 4000}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 9000}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 9000, stream_count: 10}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_for_benchmarks.py
+ kwargs : {packet_len: 9000, stream_count: 100}
+ cpu_util : 1
+ bw_per_core : 1
+
+# not enough memory + queue full if memory increase
+# - name : stl/udp_for_benchmarks.py
+# kwargs : {packet_len: 9000, stream_count: 1000}
+# cpu_util : 1
+# bw_per_core : 1
+
+ - name : stl/imix.py
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 64}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 128}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 256}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 512}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 1500}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 4000}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_1pkt_tuple_gen.py
+ kwargs : {packet_len: 9000}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/pcap.py
+ kwargs : {ipg_usec: 4, loop_count: 0}
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/udp_rand_len_9k.py
+ cpu_util : 1
+ bw_per_core : 1
+
+ - name : stl/hlt/hlt_udp_rand_len_9k.py
+ cpu_util : 1
+ bw_per_core : 1
+
+
diff --git a/scripts/automation/regression/setups/trex21/config.yaml b/scripts/automation/regression/setups/trex21/config.yaml
new file mode 100644
index 00000000..3cf135c3
--- /dev/null
+++ b/scripts/automation/regression/setups/trex21/config.yaml
@@ -0,0 +1,40 @@
+################################################################
+#### TRex nightly test configuration file ####
+################################################################
+
+
+### TRex configuration:
+# hostname - can be DNS name or IP for the TRex machine for ssh to the box
+# password - root password for TRex machine
+# is_dual - should the TRex inject with -p ?
+# version_path - path to the TRex version and executable
+# cores - how many cores should be used
+# latency - rate of latency packets injected by the TRex
+# modes - list of modes (tagging) of this setup (loopback etc.)
+# * loopback - Trex works via loopback. Router and TFTP configurations may be skipped.
+# * VM - Virtual OS (accept low CPU utilization in tests, latency can get spikes)
+# * virt_nics - NICs are virtual (VMXNET3 etc.)
+
+### Router configuration:
+# hostname - the router hostname as apears in ______# cli prefix
+# ip_address - the router's ip that can be used to communicate with
+# image - the desired imaged wished to be loaded as the router's running config
+# line_password - router password when access via Telent
+# en_password - router password when changing to "enable" mode
+# interfaces - an array of client-server pairs, representing the interfaces configurations of the router
+# configurations - an array of configurations that could possibly loaded into the router during the test.
+# The "clean" configuration is a mandatory configuration the router will load with to run the basic test bench
+
+### TFTP configuration:
+# hostname - the tftp hostname
+# ip_address - the tftp's ip address
+# images_path - the tftp's relative path in which the router's images are located
+
+### Test_misc configuration:
+# expected_bw - the "golden" bandwidth (in Gbps) results planned on receiving from the test
+
+trex:
+ hostname : csi-trex-21
+ cores : 1
+ modes : ['loopback', 'virt_nics']
+
diff --git a/scripts/automation/regression/stateful_tests/trex_general_test.py b/scripts/automation/regression/stateful_tests/trex_general_test.py
index 4453fd94..dc3f9943 100755
--- a/scripts/automation/regression/stateful_tests/trex_general_test.py
+++ b/scripts/automation/regression/stateful_tests/trex_general_test.py
@@ -313,7 +313,7 @@ class CTRexGeneral_Test(unittest.TestCase):
# check that max latency does not exceed 1 msec
if self.configuration.trex['trex_name'] == '10.56.217.210': # temporary workaround for latency issue in kiwi02, remove it ASAP. http://trex-tgn.cisco.com/youtrack/issue/trex-194
allowed_latency = 8000
- elif self.is_VM:
+ elif self.is_VM or self.is_virt_nics:
allowed_latency = 9999999
else: # no excuses, check 1ms
allowed_latency = 1000
@@ -321,7 +321,7 @@ class CTRexGeneral_Test(unittest.TestCase):
self.fail('LatencyError: Maximal latency exceeds %s (usec)' % allowed_latency)
# check that avg latency does not exceed 1 msec
- if self.is_VM:
+ if self.is_VM or self.is_virt_nics:
allowed_latency = 9999999
else: # no excuses, check 1ms
allowed_latency = 1000
diff --git a/scripts/automation/regression/stateful_tests/trex_imix_test.py b/scripts/automation/regression/stateful_tests/trex_imix_test.py
index 5f52fab7..4cb01db3 100755
--- a/scripts/automation/regression/stateful_tests/trex_imix_test.py
+++ b/scripts/automation/regression/stateful_tests/trex_imix_test.py
@@ -141,6 +141,8 @@ class CTRexIMIX_Test(CTRexGeneral_Test):
self.check_general_scenario_results(trex_res)
self.check_CPU_benchmark(trex_res)
+
+
# the name intentionally not matches nose default pattern, including the test should be specified explicitly
def dummy(self):
ret = self.trex.start_trex(
diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py
index 8812ac48..3d4ed977 100644
--- a/scripts/automation/regression/stateless_tests/stl_rx_test.py
+++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py
@@ -32,6 +32,12 @@ class STLRX_Test(CStlGeneral_Test):
'latency_9k_max_average': 100,
'latency_9k_max_latency': 250,
},
+ 'rte_i40evf_pmd': {
+ 'rate_percent': 80,
+ 'total_pkts': 1000,
+ 'rate_latency': 1,
+ 'latency_9k_enable': False,
+ },
'rte_igb_pmd': {
'rate_percent': 80,
'total_pkts': 500,
@@ -526,19 +532,37 @@ class STLRX_Test(CStlGeneral_Test):
except STLError as e:
assert False , '{0}'.format(e)
+ def _run_fcs_stream (self,is_vm):
+ """ this test send 1 64 byte packet with latency and check that all counters are reported as 64 bytes"""
+ res=True
+ try:
+ all_ports=list(CTRexScenario.stl_ports_map['map'].keys());
+ for port in all_ports:
+ for l in [True,False]:
+ print(" test port {0} latency : {1} ".format(port,l))
+ self.send_1_burst(port,l,100)
+ except Exception as e:
+ if is_vm :
+ res=False
+ else:
+ raise e
+ return(res);
+
+
def test_fcs_stream(self):
""" this test send 1 64 byte packet with latency and check that all counters are reported as 64 bytes"""
- if self.is_virt_nics:
- self.skip('Skip this for virtual NICs')
-
- all_ports=list(CTRexScenario.stl_ports_map['map'].keys());
- for port in all_ports:
- for l in [True,False]:
- print(" test port {0} latency : {1} ".format(port,l))
- self.send_1_burst(port,l,100)
+ is_vm=self.is_virt_nics # in case of VM and vSwitch there are drop of packets in some cases, let retry number of times
+ # in this case we just want to check functionality that packet of 64 is reported as 64 in all levels
+ retry=1
+ if is_vm:
+ retry=4
+ for i in range(0,retry):
+ if self._run_fcs_stream (is_vm):
+ break;
+ print("==> retry %d .." %(i));
# this test adds more and more latency streams and re-test with incremental
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 4e7deb93..490e3b7a 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
@@ -1110,6 +1110,13 @@ class CTRexResult(object):
self.clear_results()
self.latency_checked = True
self.filtered_latency_amount = filtered_latency_amount
+ self.set_warmup_default()
+
+ def set_warmup_default (self):
+ self.set_warmup(0.96)
+
+ def set_warmup (self,new_warmup_max):
+ self.warmup_max = new_warmup_max
def __repr__(self):
return ("Is valid history? {arg}\n".format( arg = self.is_valid_hist() ) +
@@ -1414,7 +1421,7 @@ class CTRexResult(object):
self._current_tx_rate = CTRexResult.__get_value_by_path(latest_dump, "trex-global.data", "m_tx_(?!expected_)\w+")
if not self._done_warmup and self._expected_tx_rate is not None:
# check for up to 4% change between expected and actual
- if (self._current_tx_rate['m_tx_bps'] > 0.96 * self._expected_tx_rate['m_tx_expected_bps']):
+ if (self._current_tx_rate['m_tx_bps'] > self.warmup_max * self._expected_tx_rate['m_tx_expected_bps']):
self._done_warmup = True
latest_dump['warmup_barrier'] = True
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
index cf594948..30a699c5 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_hltapi.py
@@ -1536,7 +1536,7 @@ def get_TOS(user_kwargs, kwargs):
if user_args & (TOS2 - TOS1) and user_args & (TOS1 - TOS2):
raise STLError('You have mixed %s and %s TOS parameters' % (TOS1, TOS2))
if user_args & (TOS0 - TOS1 - TOS2):
- return (kwargs['ip_precedence'] << 5) + (kwargs['ip_tos_field'] << 2) + kwargs['ip_mbz']
+ return (kwargs['ip_precedence'] << 5) + (kwargs['ip_tos_field'] << 1) + kwargs['ip_mbz']
if user_args & (TOS1 - TOS2):
return (kwargs['ip_precedence'] << 5) + (kwargs['ip_delay'] << 4) + (kwargs['ip_throughput'] << 3) + (kwargs['ip_reliability'] << 2) + (kwargs['ip_cost'] << 1) + kwargs['ip_reserved']
return (kwargs['ip_dscp'] << 2) + kwargs['ip_cu']
diff --git a/scripts/ko/3.10.0-514.el7.x86_64/igb_uio.ko b/scripts/ko/3.10.0-514.el7.x86_64/igb_uio.ko
new file mode 100644
index 00000000..b23189d0
--- /dev/null
+++ b/scripts/ko/3.10.0-514.el7.x86_64/igb_uio.ko
Binary files differ
diff --git a/scripts/trex-cfg b/scripts/trex-cfg
index 08e1110f..02d50eb6 100755
--- a/scripts/trex-cfg
+++ b/scripts/trex-cfg
@@ -47,13 +47,7 @@ if ! lsmod | grep -q igb_uio ; then
exit 1
fi
km=ko/$SYS/igb_uio.ko
- if [ -e $km ] ; then
- insmod $km
- if [ $? -ne 0 ]; then
- echo "Failed inserting igb_uio module"
- exit 1
- fi
- else
+ if [ ! -e $km ]; then
echo "ERROR: We don't have precompiled igb_uio.ko module for your kernel version"
echo Will try compiling automatically.
{
@@ -73,6 +67,13 @@ if ! lsmod | grep -q igb_uio ; then
}
echo Success.
fi
+ if [ -e $km ]; then
+ insmod $km
+ if [ $? -ne 0 ]; then
+ echo "Failed inserting igb_uio module"
+ exit 1
+ fi
+ fi
fi
# try to bind the ports from the configuration file (new DPDK)
diff --git a/scripts/trex_show_threads.py b/scripts/trex_show_threads.py
index 1824d073..d0e34fe9 100755
--- a/scripts/trex_show_threads.py
+++ b/scripts/trex_show_threads.py
@@ -17,7 +17,8 @@ def read_task_stats (task_path):
stat_data = open(stat, 'r').readline().split()
stats_dict['last_sched_cpu'] = stat_data[-14]
-
+ stats_dict['priority'] = stat_data[17] if stat_data[43] == '0' else 'RT'
+
return stats_dict
@@ -26,7 +27,7 @@ def show_threads (pid):
task_paths = ["{0}/{1}".format(process_dir, task) for task in os.listdir(process_dir)]
- header = [ 'Task Name', 'PID', 'Allowed CPU', 'Last Sched CPU', 'Asked Ctx Switch', 'Forced Ctx Switch']
+ header = [ 'Task Name', 'PID', 'Priority', 'Allowed CPU', 'Last Sched CPU', 'Asked Ctx Switch', 'Forced Ctx Switch']
for x in header:
print('{:^20}'.format(x)),
print("")
@@ -41,6 +42,7 @@ def show_threads (pid):
# name
print("{:<20}".format(task['name'])),
print("{:^20}".format(task['pid'])),
+ print("{:^20}".format(task['priority'])),
print("{:^20}".format(task['cpus_allowed_list'])),
print("{:^20}".format(task['last_sched_cpu'])),
print("{:^20}".format(task['voluntary_ctxt_switches'])),
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 282e7fe4..217446ed 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -628,6 +628,14 @@ public:
return (btGetMaskBit32(m_flags1, 9, 9) ? true : false);
}
+ void set_rt_prio_mode(bool enable) {
+ btSetMaskBit32(m_flags1, 10, 10, (enable ? 1 : 0) );
+ }
+
+ bool get_rt_prio_mode() {
+ return (btGetMaskBit32(m_flags1, 10, 10) ? true : false);
+ }
+
public:
void Dump(FILE *fd);
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 1d315fa7..ebad39df 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -133,7 +133,6 @@ static char global_master_id_str[10];
class CTRexExtendedDriverBase {
public:
-
/* by default NIC driver adds CRC */
virtual bool has_crc_added() {
return true;
@@ -154,6 +153,7 @@ public:
}
virtual int stop_queue(CPhyEthIF * _if, uint16_t q_num);
+ void get_extended_stats_fixed(CPhyEthIF * _if, CPhyEthIFStats *stats, int fix_i, int fix_o);
virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats)=0;
virtual void clear_extended_stats(CPhyEthIF * _if)=0;
virtual int wait_for_stable_link();
@@ -237,10 +237,10 @@ public:
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on);
};
-class CTRexExtendedDriverBase1GVm : public CTRexExtendedDriverBase {
+class CTRexExtendedDriverVirtio : public CTRexExtendedDriverBase {
public:
- CTRexExtendedDriverBase1GVm(){
+ CTRexExtendedDriverVirtio() {
/* we are working in mode that we have 1 queue for rx and one queue for tx*/
CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
}
@@ -254,12 +254,10 @@ public:
}
static CTRexExtendedDriverBase * create(){
- return ( new CTRexExtendedDriverBase1GVm() );
+ return ( new CTRexExtendedDriverVirtio() );
}
- virtual void update_global_config_fdir(port_cfg_t * cfg){
-
- }
+ virtual void update_global_config_fdir(port_cfg_t * cfg) {}
virtual int get_min_sample_rate(void){
return ( RX_CHECK_MIX_SAMPLE_RATE_1G);
@@ -288,28 +286,53 @@ public:
virtual int set_rcv_all(CPhyEthIF * _if, bool set_on) {return 0;}
};
-class CTRexExtendedDriverVf : public CTRexExtendedDriverBase1GVm {
+class CTRexExtendedDriverVmxnet3 : public CTRexExtendedDriverVirtio {
+public:
+ CTRexExtendedDriverVmxnet3(){
+ /* we are working in mode in which we have 1 queue for rx and one queue for tx*/
+ CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
+ }
+
+ static CTRexExtendedDriverBase * create() {
+ return ( new CTRexExtendedDriverVmxnet3() );
+ }
+
+ virtual void update_configuration(port_cfg_t * cfg);
+};
+class CTRexExtendedDriverI40evf : public CTRexExtendedDriverVirtio {
public:
- CTRexExtendedDriverVf(){
- /* we are working in mode in which we have we have 1 queue for rx and one queue for tx*/
+ CTRexExtendedDriverI40evf(){
+ /* we are working in mode in which we have 1 queue for rx and one queue for tx*/
CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
}
virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) {
- uint64_t prev_ipackets = stats->ipackets;
- uint64_t prev_opackets = stats->opackets;
+ get_extended_stats_fixed(_if, stats, 0, 4);
+ }
- CTRexExtendedDriverBase1GVm::get_extended_stats(_if, stats);
- // Since this driver report byte counts without Ethernet FCS (4 bytes), we need to fix the reported numbers
- stats->ibytes += (stats->ipackets - prev_ipackets) * 4;
- stats->obytes += (stats->opackets - prev_opackets) * 4;
+ virtual void update_configuration(port_cfg_t * cfg);
+ static CTRexExtendedDriverBase * create() {
+ return ( new CTRexExtendedDriverI40evf() );
}
- static CTRexExtendedDriverBase * create(){
- return ( new CTRexExtendedDriverVf() );
+};
+
+class CTRexExtendedDriverIxgbevf : public CTRexExtendedDriverI40evf {
+
+public:
+ CTRexExtendedDriverIxgbevf(){
+ /* we are working in mode in which we have 1 queue for rx and one queue for tx*/
+ CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
+ }
+ virtual void get_extended_stats(CPhyEthIF * _if, CPhyEthIFStats *stats) {
+ get_extended_stats_fixed(_if, stats, 4, 4);
+ }
+
+ static CTRexExtendedDriverBase * create() {
+ return ( new CTRexExtendedDriverIxgbevf() );
}
};
-class CTRexExtendedDriverBaseE1000 : public CTRexExtendedDriverBase1GVm {
+class CTRexExtendedDriverBaseE1000 : public CTRexExtendedDriverVirtio {
CTRexExtendedDriverBaseE1000() {
// E1000 driver is only relevant in VM in our case
CGlobalInfo::m_options.preview.set_vm_one_queue_enable(true);
@@ -320,6 +343,9 @@ public:
}
// e1000 driver handing us packets with ethernet CRC, so we need to chop them
virtual uint8_t get_num_crc_fix_bytes() {return 4;}
+
+ virtual void get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats);
+
};
class CTRexExtendedDriverBase10G : public CTRexExtendedDriverBase {
@@ -593,11 +619,11 @@ private:
register_driver(std::string("net_mlx5"),CTRexExtendedDriverBaseMlnx5G::create);
/* virtual devices */
- register_driver(std::string("rte_em_pmd"),CTRexExtendedDriverBaseE1000::create);
- register_driver(std::string("rte_vmxnet3_pmd"),CTRexExtendedDriverBase1GVm::create);
- register_driver(std::string("rte_virtio_pmd"),CTRexExtendedDriverBase1GVm::create);
- register_driver(std::string("rte_ixgbevf_pmd"),CTRexExtendedDriverVf::create);
- register_driver(std::string("rte_i40evf_pmd"),CTRexExtendedDriverVf::create);
+ register_driver(std::string("rte_em_pmd"), CTRexExtendedDriverBaseE1000::create);
+ register_driver(std::string("rte_vmxnet3_pmd"), CTRexExtendedDriverVmxnet3::create);
+ register_driver(std::string("rte_virtio_pmd"), CTRexExtendedDriverVirtio::create);
+ register_driver(std::string("rte_i40evf_pmd"), CTRexExtendedDriverI40evf::create);
+ register_driver(std::string("rte_ixgbevf_pmd"), CTRexExtendedDriverIxgbevf::create);
m_driver_was_set=false;
m_drv=0;
@@ -713,7 +739,8 @@ enum { OPT_HELP,
OPT_ARP_REF_PER,
OPT_NO_OFED_CHECK,
OPT_NO_SCAPY_SERVER,
- OPT_ACTIVE_FLOW
+ OPT_ACTIVE_FLOW,
+ OPT_RT
};
/* these are the argument types:
@@ -774,6 +801,7 @@ static CSimpleOpt::SOption parser_options[] =
{ OPT_ARP_REF_PER, "--arp-refresh-period", SO_REQ_SEP },
{ OPT_NO_OFED_CHECK, "--no-ofed-check", SO_NONE },
{ OPT_NO_SCAPY_SERVER, "--no-scapy-server", SO_NONE },
+ { OPT_RT, "--rt", SO_NONE },
SO_END_OF_OPTIONS
};
@@ -828,6 +856,7 @@ static int usage(){
printf(" --no-ofed-check : Disable the check of OFED version \n");
printf(" --no-scapy-server : Disable Scapy server implicit start at stateless \n");
printf(" --no-watchdog : Disable watchdog \n");
+ printf(" --rt : Run TRex DP/RX cores in realtime priority \n");
printf(" -p : Send all flow packets from the same interface (choosed randomly between client ad server ports) without changing their src/dst IP \n");
printf(" -pm : Platform factor. If you have splitter in the setup, you can multiply the total results by this factor \n");
printf(" e.g --pm 2.0 will multiply all the results bps in this factor \n");
@@ -956,6 +985,9 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->preview.set_ipv6_mode_enable(true);
break;
+ case OPT_RT:
+ po->preview.set_rt_prio_mode(true);
+ break;
case OPT_LEARN :
po->m_learn_mode = CParserOption::LEARN_MODE_IP_OPTION;
@@ -1223,6 +1255,7 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
po->set_tw_levels(lp->m_levels);
}
}
+
return 0;
}
@@ -3685,6 +3718,7 @@ void CGlobalTRex::rx_sl_configure(void) {
int CGlobalTRex::ixgbe_start(void){
int i;
+
for (i=0; i<m_max_ports; i++) {
socket_id_t socket_id = CGlobalInfo::m_socket.port_to_socket((port_id_t)i);
assert(CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
@@ -3693,14 +3727,14 @@ int CGlobalTRex::ixgbe_start(void){
uint16_t rx_rss = get_ex_drv()->enable_rss_drop_workaround();
if ( get_vm_one_queue_enable() ) {
- /* VMXNET3 does claim to support 16K but somehow does not work */
- /* reduce to 2000 */
m_port_cfg.m_port_conf.rxmode.max_rx_pkt_len = 2000;
/* In VM case, there is one tx q and one rx q */
_if->configure(1, 1, &m_port_cfg.m_port_conf);
// Only 1 rx queue, so use it for everything
m_rx_core_tx_q_id = 0;
_if->set_rx_queue(0);
+ // We usually have less memory in VM, so don't use the 9k pool. This means that large packets will
+ // be received in chain of few mbufs
_if->rx_queue_setup(0, RTE_TEST_RX_DESC_VM_DEFAULT, socket_id, &m_port_cfg.m_rx_conf,
CGlobalInfo::m_mem_pool[socket_id].m_mbuf_pool_2048);
// 1 TX queue in VM case
@@ -4846,8 +4880,20 @@ int CGlobalTRex::run_in_master() {
int CGlobalTRex::run_in_rx_core(void){
+ CPreviewMode *lp = &CGlobalInfo::m_options.preview;
+
rte_thread_setname(pthread_self(), "TRex RX");
-
+
+ /* set RT mode if set */
+ if (lp->get_rt_prio_mode()) {
+ struct sched_param param;
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
+ perror("setting RT priroity mode on RX core failed with error");
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (get_is_stateless()) {
m_sl_rx_running = true;
m_rx_sl.start();
@@ -4864,11 +4910,22 @@ int CGlobalTRex::run_in_rx_core(void){
int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){
std::stringstream ss;
-
+ CPreviewMode *lp = &CGlobalInfo::m_options.preview;
+
ss << "Trex DP core " << int(virt_core_id);
rte_thread_setname(pthread_self(), ss.str().c_str());
+
+ /* set RT mode if set */
+ if (lp->get_rt_prio_mode()) {
+ struct sched_param param;
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) != 0) {
+ perror("setting RT priroity mode on DP core failed with error");
+ exit(EXIT_FAILURE);
+ }
+ }
- CPreviewMode *lp=&CGlobalInfo::m_options.preview;
+
if ( lp->getSingleCore() &&
(virt_core_id==2 ) &&
(lp-> getCores() ==1) ){
@@ -5868,6 +5925,35 @@ CFlowStatParser *CTRexExtendedDriverBase::get_flow_stat_parser() {
return parser;
}
+void CTRexExtendedDriverBase::get_extended_stats_fixed(CPhyEthIF * _if, CPhyEthIFStats *stats, int fix_i, int fix_o) {
+ struct rte_eth_stats stats1;
+ struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
+ rte_eth_stats_get(_if->get_port_id(), &stats1);
+
+ stats->ipackets += stats1.ipackets - prev_stats->ipackets;
+ // Some drivers report input byte counts without Ethernet FCS (4 bytes), we need to fix the reported numbers
+ stats->ibytes += stats1.ibytes - prev_stats->ibytes + (stats1.ipackets - prev_stats->ipackets) * fix_i;
+ stats->opackets += stats1.opackets - prev_stats->opackets;
+ // Some drivers report output byte counts without Ethernet FCS (4 bytes), we need to fix the reported numbers
+ stats->obytes += stats1.obytes - prev_stats->obytes + (stats1.opackets - prev_stats->opackets) * fix_o;
+ stats->f_ipackets += 0;
+ stats->f_ibytes += 0;
+ stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
+ - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
+ stats->oerrors += stats1.oerrors - prev_stats->oerrors;
+ stats->imcasts += 0;
+ stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
+
+ prev_stats->ipackets = stats1.ipackets;
+ prev_stats->ibytes = stats1.ibytes;
+ prev_stats->opackets = stats1.opackets;
+ prev_stats->obytes = stats1.obytes;
+ prev_stats->imissed = stats1.imissed;
+ prev_stats->oerrors = stats1.oerrors;
+ prev_stats->ierrors = stats1.ierrors;
+ prev_stats->rx_nombuf = stats1.rx_nombuf;
+}
+
// in 1G we need to wait if links became ready to soon
void CTRexExtendedDriverBase1G::wait_after_link_up(){
wait_x_sec(6 + CGlobalInfo::m_options.m_wait_before_traffic);
@@ -6648,31 +6734,7 @@ int CTRexExtendedDriverBase40G::dump_fdir_global_stats(CPhyEthIF * _if, FILE *fd
}
void CTRexExtendedDriverBase40G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) {
- struct rte_eth_stats stats1;
- struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
- rte_eth_stats_get(_if->get_port_id(), &stats1);
-
- stats->ipackets += stats1.ipackets - prev_stats->ipackets;
- stats->ibytes += stats1.ibytes - prev_stats->ibytes;
- stats->opackets += stats1.opackets - prev_stats->opackets;
- // Since this driver report obytes count without Ethernet FCS (4 bytes), we need to fix the reported numbers
- stats->obytes += stats1.obytes - prev_stats->obytes + (stats1.opackets - prev_stats->opackets) * 4;
- stats->f_ipackets += 0;
- stats->f_ibytes += 0;
- stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
- - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
- stats->oerrors += stats1.oerrors - prev_stats->oerrors;
- stats->imcasts += 0;
- stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
-
- prev_stats->ipackets = stats1.ipackets;
- prev_stats->ibytes = stats1.ibytes;
- prev_stats->opackets = stats1.opackets;
- prev_stats->obytes = stats1.obytes;
- prev_stats->imissed = stats1.imissed;
- prev_stats->oerrors = stats1.oerrors;
- prev_stats->ierrors = stats1.ierrors;
- prev_stats->rx_nombuf = stats1.rx_nombuf;
+ get_extended_stats_fixed(_if, stats, 0, 4);
}
int CTRexExtendedDriverBase40G::wait_for_stable_link(){
@@ -6892,33 +6954,7 @@ int CTRexExtendedDriverBaseMlnx5G::dump_fdir_global_stats(CPhyEthIF * _if, FILE
}
void CTRexExtendedDriverBaseMlnx5G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
-
- struct rte_eth_stats stats1;
- struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
- rte_eth_stats_get(_if->get_port_id(), &stats1);
-
- stats->ipackets += stats1.ipackets - prev_stats->ipackets;
- stats->ibytes += stats1.ibytes - prev_stats->ibytes +
- + (stats1.ipackets << 2) - (prev_stats->ipackets << 2);
- stats->opackets += stats1.opackets - prev_stats->opackets;
- stats->obytes += stats1.obytes - prev_stats->obytes
- + (stats1.opackets << 2) - (prev_stats->opackets << 2);
- stats->f_ipackets += 0;
- stats->f_ibytes += 0;
- stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
- - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
- stats->oerrors += stats1.oerrors - prev_stats->oerrors;
- stats->imcasts += 0;
- stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
-
- prev_stats->ipackets = stats1.ipackets;
- prev_stats->ibytes = stats1.ibytes;
- prev_stats->opackets = stats1.opackets;
- prev_stats->obytes = stats1.obytes;
- prev_stats->imissed = stats1.imissed;
- prev_stats->oerrors = stats1.oerrors;
- prev_stats->ierrors = stats1.ierrors;
- prev_stats->rx_nombuf = stats1.rx_nombuf;
+ get_extended_stats_fixed(_if, stats, 4, 4);
}
int CTRexExtendedDriverBaseMlnx5G::wait_for_stable_link(){
@@ -7055,31 +7091,8 @@ void CTRexExtendedDriverBaseVIC::clear_extended_stats(CPhyEthIF * _if){
}
void CTRexExtendedDriverBaseVIC::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) {
- struct rte_eth_stats stats1;
- struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
- rte_eth_stats_get(_if->get_port_id(), &stats1);
-
- stats->ipackets += stats1.ipackets - prev_stats->ipackets;
- stats->ibytes += stats1.ibytes - prev_stats->ibytes
- - ((stats1.ipackets << 2) - (prev_stats->ipackets << 2));
- stats->opackets += stats1.opackets - prev_stats->opackets;
- stats->obytes += stats1.obytes - prev_stats->obytes;
- stats->f_ipackets += 0;
- stats->f_ibytes += 0;
- stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
- - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
- stats->oerrors += stats1.oerrors - prev_stats->oerrors;
- stats->imcasts += 0;
- stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
-
- prev_stats->ipackets = stats1.ipackets;
- prev_stats->ibytes = stats1.ibytes;
- prev_stats->opackets = stats1.opackets;
- prev_stats->obytes = stats1.obytes;
- prev_stats->imissed = stats1.imissed;
- prev_stats->oerrors = stats1.oerrors;
- prev_stats->ierrors = stats1.ierrors;
- prev_stats->rx_nombuf = stats1.rx_nombuf;
+ // In VIC, we need to reduce 4 bytes from the amount reported for each incoming packet
+ get_extended_stats_fixed(_if, stats, -4, 0);
}
int CTRexExtendedDriverBaseVIC::verify_fw_ver(int port_id) {
@@ -7137,66 +7150,54 @@ CFlowStatParser *CTRexExtendedDriverBaseVIC::get_flow_stat_parser() {
/////////////////////////////////////////////////////////////////////////////////////
-
-
-void CTRexExtendedDriverBase1GVm::update_configuration(port_cfg_t * cfg){
- struct rte_eth_dev_info dev_info;
- rte_eth_dev_info_get((uint8_t) 0,&dev_info);
-
+void CTRexExtendedDriverVirtio::update_configuration(port_cfg_t * cfg){
cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G;
cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
cfg->m_tx_conf.tx_thresh.wthresh = 0;
- cfg->m_tx_conf.txq_flags=dev_info.default_txconf.txq_flags;
-
+ // must have this, otherwise the driver fail at init
+ cfg->m_tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOXSUMS;
}
-
-int CTRexExtendedDriverBase1GVm::configure_rx_filter_rules(CPhyEthIF * _if){
+int CTRexExtendedDriverVirtio::configure_rx_filter_rules(CPhyEthIF * _if){
return (0);
}
-void CTRexExtendedDriverBase1GVm::clear_extended_stats(CPhyEthIF * _if){
-
+void CTRexExtendedDriverVirtio::clear_extended_stats(CPhyEthIF * _if){
rte_eth_stats_reset(_if->get_port_id());
-
}
-int CTRexExtendedDriverBase1GVm::stop_queue(CPhyEthIF * _if, uint16_t q_num) {
+int CTRexExtendedDriverVirtio::stop_queue(CPhyEthIF * _if, uint16_t q_num) {
return (0);
}
-void CTRexExtendedDriverBase1GVm::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
- struct rte_eth_stats stats1;
- struct rte_eth_stats *prev_stats = &stats->m_prev_stats;
- rte_eth_stats_get(_if->get_port_id(), &stats1);
-
- stats->ipackets += stats1.ipackets - prev_stats->ipackets;
- stats->ibytes += stats1.ibytes - prev_stats->ibytes;
- stats->opackets += stats1.opackets - prev_stats->opackets;
- stats->obytes += stats1.obytes - prev_stats->obytes;
- stats->f_ipackets += 0;
- stats->f_ibytes += 0;
- stats->ierrors += stats1.imissed + stats1.ierrors + stats1.rx_nombuf
- - prev_stats->imissed - prev_stats->ierrors - prev_stats->rx_nombuf;
- stats->oerrors += stats1.oerrors - prev_stats->oerrors;
- stats->imcasts += 0;
- stats->rx_nombuf += stats1.rx_nombuf - prev_stats->rx_nombuf;
+void CTRexExtendedDriverBaseE1000::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){
+ get_extended_stats_fixed(_if, stats, 0, 4);
+}
- prev_stats->ipackets = stats1.ipackets;
- prev_stats->ibytes = stats1.ibytes;
- prev_stats->opackets = stats1.opackets;
- prev_stats->obytes = stats1.obytes;
- prev_stats->imissed = stats1.imissed;
- prev_stats->oerrors = stats1.oerrors;
- prev_stats->ierrors = stats1.ierrors;
- prev_stats->rx_nombuf = stats1.rx_nombuf;
+void CTRexExtendedDriverVirtio::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats) {
+ get_extended_stats_fixed(_if, stats, 4, 4);
}
-int CTRexExtendedDriverBase1GVm::wait_for_stable_link(){
+int CTRexExtendedDriverVirtio::wait_for_stable_link(){
wait_x_sec(CGlobalInfo::m_options.m_wait_before_traffic);
return (0);
}
+/////////////////////////////////////////////////////////// VMxnet3
+void CTRexExtendedDriverVmxnet3::update_configuration(port_cfg_t * cfg){
+ cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH_1G;
+ cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
+ cfg->m_tx_conf.tx_thresh.wthresh = 0;
+ // must have this, otherwise the driver fail at init
+ cfg->m_tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOXSUMSCTP;
+}
+
+///////////////////////////////////////////////////////// VF
+void CTRexExtendedDriverI40evf::update_configuration(port_cfg_t * cfg) {
+ cfg->m_tx_conf.tx_thresh.pthresh = TX_PTHRESH;
+ cfg->m_tx_conf.tx_thresh.hthresh = TX_HTHRESH;
+ cfg->m_tx_conf.tx_thresh.wthresh = TX_WTHRESH;
+}
/**
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index 3f73a5d7..836dc5de 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -853,13 +853,13 @@ TrexRpcCmdValidate::_run(const Json::Value &params, Json::Value &result) {
result["result"]["rate"]["max_bps_l2"] = graph->get_max_bps_l2();
result["result"]["rate"]["max_bps_l1"] = graph->get_max_bps_l1();
result["result"]["rate"]["max_pps"] = graph->get_max_pps();
- result["result"]["rate"]["max_line_util"] = (graph->get_max_bps_l1() / port->get_port_speed_bps()) * 100.0;
+ result["result"]["rate"]["max_line_util"] = (graph->get_max_bps_l1() / port->get_port_speed_bps()) * 100.01;
/* min values */
result["result"]["rate"]["min_bps_l2"] = graph->get_max_bps_l2(0);
result["result"]["rate"]["min_bps_l1"] = graph->get_max_bps_l1(0);
result["result"]["rate"]["min_pps"] = graph->get_max_pps(0);
- result["result"]["rate"]["min_line_util"] = (graph->get_max_bps_l1(0) / port->get_port_speed_bps()) * 100.0;
+ result["result"]["rate"]["min_line_util"] = (graph->get_max_bps_l1(0) / port->get_port_speed_bps()) * 100.01;
result["result"]["graph"]["expected_duration"] = graph->get_duration();
result["result"]["graph"]["events_count"] = (int)graph->get_events().size();
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index bfc7dce4..b88ac715 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -696,12 +696,6 @@ TrexStatelessPort::calculate_effective_factor(const TrexPortMultiplier &mul, boo
/* did we exceeded the max L1 line rate ? */
double expected_l1_rate = m_graph_obj->get_max_bps_l1(factor);
- /* if not force and exceeded - throw exception */
- if ( (!force) && (expected_l1_rate > get_port_speed_bps()) ) {
- stringstream ss;
- ss << "Expected L1 B/W: '" << bps_to_gbps(expected_l1_rate) << " Gbps' exceeds port line rate: '" << bps_to_gbps(get_port_speed_bps()) << " Gbps'";
- throw TrexException(ss.str());
- }
/* L1 BW must be positive */
if (expected_l1_rate <= 0){
@@ -717,7 +711,23 @@ TrexStatelessPort::calculate_effective_factor(const TrexPortMultiplier &mul, boo
throw TrexException(ss.str());
}
- return factor;
+ /* if force simply return the value */
+ if (force) {
+ return factor;
+ } else {
+
+ /* due to float calculations we allow 0.1% roundup */
+ if ( (expected_l1_rate / get_port_speed_bps()) > 1.0001 ) {
+ stringstream ss;
+ ss << "Expected L1 B/W: '" << bps_to_gbps(expected_l1_rate) << " Gbps' exceeds port line rate: '" << bps_to_gbps(get_port_speed_bps()) << " Gbps'";
+ throw TrexException(ss.str());
+ }
+
+ /* in any case, without force, do not return any value higher than the max factor */
+ double max_factor = m_graph_obj->get_factor_bps_l1(get_port_speed_bps());
+ return std::min(max_factor, factor);
+ }
+
}
double