diff options
14 files changed, 133 insertions, 53 deletions
diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index e769b9b2..c020f532 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -1000,7 +1000,7 @@ class AsyncKeysEngineConsole: for x in os.listdir(d): if os.path.isdir(os.path.join(d, x)): files.append(x + '/') - elif x.endswith('.py') or x.endswith('yaml') or x.endswith('pcap') or x.endswith('cap'): + elif x.endswith( ('.py', 'yaml', 'pcap', 'cap', 'erf') ): files.append(x) # dir might not have the files 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 7101b8a2..2c1fa5e9 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 @@ -743,13 +743,17 @@ class STLClient(object): return rc - def __push_remote (self, pcap_filename, port_id_list, ipg_usec, speedup, count, duration): + def __push_remote (self, pcap_filename, port_id_list, ipg_usec, speedup, count, duration, is_dual): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: - rc.add(self.ports[port_id].push_remote(pcap_filename, ipg_usec, speedup, count, duration)) + + # for dual, provide the slave handler as well + slave_handler = self.ports[port_id ^ 0x1].handler if is_dual else "" + + rc.add(self.ports[port_id].push_remote(pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler)) return rc @@ -2183,7 +2187,8 @@ class STLClient(object): ipg_usec = None, speedup = 1.0, count = 1, - duration = -1): + duration = -1, + is_dual = False): """ Push a remote server-reachable PCAP file the path must be fullpath accessible to the server @@ -2206,6 +2211,13 @@ class STLClient(object): duration: float Limit runtime by duration in seconds + + is_dual: bool + Inject from both directions. + requires ERF file with meta data for direction. + also requires that all the ports will be in master mode + with their adjacent ports as slaves + :raises: + :exc:`STLError` @@ -2218,9 +2230,23 @@ class STLClient(object): validate_type('speedup', speedup, (float, int)) validate_type('count', count, int) validate_type('duration', duration, (float, int)) + validate_type('is_dual', is_dual, bool) + + # for dual mode check that all are masters + if is_dual: + for port in ports: + master = port + slave = port ^ 0x1 + + if slave in ports: + raise STLError("dual mode: cannot provide adjacent ports ({0}, {1}) in a batch".format(master, slave)) + + if not slave in self.get_acquired_ports(): + raise STLError("dual mode: port {0} must be owned as well".format(slave)) + self.logger.pre_cmd("Pushing remote PCAP on port(s) {0}:".format(ports)) - rc = self.__push_remote(pcap_filename, ports, ipg_usec, speedup, count, duration) + rc = self.__push_remote(pcap_filename, ports, ipg_usec, speedup, count, duration, is_dual) self.logger.post_cmd(rc) if not rc: @@ -3023,7 +3049,8 @@ class STLClient(object): parsing_opts.DURATION, parsing_opts.IPG, parsing_opts.SPEEDUP, - parsing_opts.FORCE) + parsing_opts.FORCE, + parsing_opts.DUAL) opts = parser.parse_args(line.split()) if not opts: @@ -3046,7 +3073,8 @@ class STLClient(object): ipg_usec = opts.ipg_usec, speedup = opts.speedup, count = opts.count, - duration = opts.duration) + duration = opts.duration, + is_dual = opts.dual) else: self.push_pcap(opts.file[0], 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 890ce7de..f0e3b109 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 @@ -582,7 +582,7 @@ class Port(object): return self.ok() @writeable - def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration): + def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler): params = {"handler": self.handler, "port_id": self.port_id, @@ -590,7 +590,9 @@ class Port(object): "ipg_usec": ipg_usec if ipg_usec is not None else -1, "speedup": speedup, "count": count, - "duration": duration} + "duration": duration, + "is_dual": is_dual, + "slave_handler": slave_handler} rc = self.transmit("push_remote", params) if rc.bad(): 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 afb01791..4586f647 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 @@ -1008,7 +1008,7 @@ class CPortStats(CTRexStats): bps_L1 = calc_bps_L1(bps, pps) bps_rx_L1 = calc_bps_L1(rx_bps, rx_pps) snapshot['m_total_tx_bps_L1'] = bps_L1 - snapshot['m_percentage'] = (bps_L1 / self._port_obj.get_speed_bps()) * 100 + snapshot['m_percentage'] = (bps_L1 / self._port_obj.get_speed_bps()) * 100.0 # TX line util not smoothed diff_tx_pkts = snapshot.get('opackets', 0) - self.latest_stats.get('opackets', 0) 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 9ed6c0f8..4e57aae3 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 @@ -39,6 +39,7 @@ REMOTE_FILE = 23 LOCKED = 24 PIN_CORES = 25 CORE_MASK = 26 +DUAL = 28 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -313,6 +314,11 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': False, 'help': "file path should be interpeted by the server (remote file)"}), + DUAL: ArgumentPack(['--dual'], + {"action": "store_true", + 'default': False, + 'help': "Transmit in a dual mode - requires a slave attached to the port"}), + FILE_PATH: ArgumentPack(['-f'], {'metavar': 'FILE', 'dest': 'file', diff --git a/src/common/erf.cpp b/src/common/erf.cpp index 304f758b..c4c14998 100755 --- a/src/common/erf.cpp +++ b/src/common/erf.cpp @@ -108,7 +108,7 @@ int erf_open(wtap *wth, int *err) memset(&prevts, 0, sizeof(prevts)); - int records_for_erf_check = 10; + long records_for_erf_check = 10; /* ERF is a little hard because there's no magic number */ @@ -166,7 +166,7 @@ int erf_open(wtap *wth, int *err) } -int erf_read(wtap *wth,char *p,uint32_t *sec,uint32_t *nsec) +int erf_read(wtap *wth,char *p,uint32_t *sec,uint32_t *nsec, uint8_t *interface) { erf_header_t header; int common_type = 0; @@ -214,6 +214,7 @@ int erf_read(wtap *wth,char *p,uint32_t *sec,uint32_t *nsec) uint32_t frac =(ts &0xffffffff); double usec_frac =(double)frac*(1000000000.0/(4294967296.0)); *nsec = (uint32_t) (usec_frac); + *interface = header.flags & 0x3; return (g_ntohs(header.wlen)); }else{ return (-1); @@ -438,15 +439,19 @@ void CErfFileReader::Delete(){ bool CErfFileReader::ReadPacket(CCapPktRaw * lpPacket){ + uint8_t interface; wtap wth; + wth.fh = m_handle; - int length; - length=erf_read(&wth,lpPacket->raw,&lpPacket->time_sec, - &lpPacket->time_nsec - ); + int length = erf_read(&wth, + lpPacket->raw, + &lpPacket->time_sec, + &lpPacket->time_nsec, + &interface); if ( length >0 ) { lpPacket->pkt_len =(uint16_t)length; lpPacket->pkt_cnt++; + lpPacket->setInterface(interface); return (true); } return (false); diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index cd845fca..ba3c1658 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -509,16 +509,26 @@ trex_rpc_cmd_rc_e TrexRpcCmdPushRemote::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_port(params, result); - std::string pcap_filename = parse_string(params, "pcap_filename", result); - double ipg_usec = parse_double(params, "ipg_usec", result); - double speedup = parse_double(params, "speedup", result); - uint32_t count = parse_uint32(params, "count", result); - double duration = parse_double(params, "duration", result); + std::string pcap_filename = parse_string(params, "pcap_filename", result); + double ipg_usec = parse_double(params, "ipg_usec", result); + double speedup = parse_double(params, "speedup", result); + uint32_t count = parse_uint32(params, "count", result); + double duration = parse_double(params, "duration", result); + bool is_dual = parse_bool(params, "is_dual", result, false); + std::string slave_handler = parse_string(params, "slave_handler", result, ""); TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + if (is_dual) { + TrexStatelessPort *slave = get_stateless_obj()->get_port_by_id(port_id ^ 0x1); + + if (!slave->get_owner().verify(slave_handler)) { + generate_execute_err(result, "incorrect or missing slave port handler"); + } + } + try { - port->push_remote(pcap_filename, ipg_usec, speedup, count, duration); + port->push_remote(pcap_filename, ipg_usec, speedup, count, duration, is_dual); } catch (const TrexException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 2a545c5f..df50d3e2 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -244,7 +244,7 @@ void TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration, bool force, uint64_t core_mask) { /* command allowed only on state stream */ - verify_state(PORT_STATE_STREAMS); + verify_state(PORT_STATE_STREAMS, "start"); /* just making sure no leftovers... */ delete_streams_graph(); @@ -370,7 +370,7 @@ TrexStatelessPort::stop_traffic(void) { void TrexStatelessPort::remove_rx_filters(void) { /* only valid when IDLE or with streams and not TXing */ - verify_state(PORT_STATE_STREAMS); + verify_state(PORT_STATE_STREAMS, "remove_rx_filters"); for (auto entry : m_stream_table) { get_stateless_obj()->m_rx_flow_stat.stop_stream(entry.second); @@ -410,7 +410,7 @@ TrexStatelessPort::is_core_active(int core_id) { void TrexStatelessPort::pause_traffic(void) { - verify_state(PORT_STATE_TX); + verify_state(PORT_STATE_TX, "pause"); if (m_last_all_streams_continues == false) { throw TrexException(" pause is supported when all streams are in continues mode "); @@ -441,7 +441,7 @@ TrexStatelessPort::pause_traffic(void) { void TrexStatelessPort::resume_traffic(void) { - verify_state(PORT_STATE_PAUSE); + verify_state(PORT_STATE_PAUSE, "resume"); /* generate a message to all the relevant DP cores to start transmitting */ TrexStatelessCpToDpMsgBase *resume_msg = new TrexStatelessDpResume(m_port_id); @@ -459,7 +459,7 @@ TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul, bool force) { double factor; - verify_state(PORT_STATE_TX | PORT_STATE_PAUSE); + verify_state(PORT_STATE_TX | PORT_STATE_PAUSE, "update"); /* generate a message to all the relevant DP cores to start transmitting */ double new_factor = calculate_effective_factor(mul, force); @@ -497,10 +497,11 @@ TrexStatelessPort::push_remote(const std::string &pcap_filename, double ipg_usec, double speedup, uint32_t count, - double duration) { + double duration, + bool is_dual) { /* command allowed only on state stream */ - verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS); + verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "push_remote"); /* check that file exists */ CCapReaderBase *reader; @@ -532,7 +533,8 @@ TrexStatelessPort::push_remote(const std::string &pcap_filename, ipg_usec, speedup, count, - duration); + duration, + is_dual); send_message_to_dp(tx_core, push_msg); /* update subscribers */ @@ -580,10 +582,12 @@ TrexStatelessPort::get_properties(std::string &driver, uint32_t &speed) { } bool -TrexStatelessPort::verify_state(int state, bool should_throw) const { +TrexStatelessPort::verify_state(int state, const char *cmd_name, bool should_throw) const { if ( (state & m_port_state) == 0 ) { if (should_throw) { - throw TrexException("command cannot be executed on current state: '" + get_state_as_string() + "'"); + std::stringstream ss; + ss << "command '" << cmd_name << "' cannot be executed on current state: '" << get_state_as_string() << "'"; + throw TrexException(ss.str()); } else { return false; } @@ -893,7 +897,7 @@ TrexStatelessPort::get_pci_info(std::string &pci_addr, int &numa_node) { void TrexStatelessPort::add_stream(TrexStream *stream) { - verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS); + verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "add_stream"); get_stateless_obj()->m_rx_flow_stat.add_stream(stream); @@ -906,7 +910,7 @@ TrexStatelessPort::add_stream(TrexStream *stream) { void TrexStatelessPort::remove_stream(TrexStream *stream) { - verify_state(PORT_STATE_STREAMS); + verify_state(PORT_STATE_STREAMS, "remove_stream"); get_stateless_obj()->m_rx_flow_stat.del_stream(stream); @@ -920,7 +924,7 @@ TrexStatelessPort::remove_stream(TrexStream *stream) { void TrexStatelessPort::remove_and_delete_all_streams() { - verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS); + verify_state(PORT_STATE_IDLE | PORT_STATE_STREAMS, "remove_and_delete_all_streams"); vector<TrexStream *> streams; get_object_list(streams); diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index ba86a279..147efc70 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -217,10 +217,11 @@ public: * */ void push_remote(const std::string &pcap_filename, - double ipg_usec, - double speedup, - uint32_t count, - double duration); + double ipg_usec, + double speedup, + uint32_t count, + double duration, + bool is_dual); /** * get the port state @@ -385,7 +386,7 @@ private: return m_cores_id_list; } - bool verify_state(int state, bool should_throw = true) const; + bool verify_state(int state, const char *cmd_name, bool should_throw = true) const; void change_state(port_state_e new_state); diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 4d9137f1..e5679590 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -478,7 +478,8 @@ bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id, const std::string &pcap_filename, double ipg_usec, double speedup, - uint32_t count) { + uint32_t count, + bool is_dual) { /* push pcap can only happen on an idle port from the core prespective */ assert(m_state == TrexStatelessDpPerPort::ppSTATE_IDLE); @@ -501,7 +502,8 @@ bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id, pcap_filename, ipg_usec, speedup, - count); + count, + is_dual); if (!rc) { m_core->free_node((CGenNode *)pcap_node); return (false); @@ -1162,14 +1164,15 @@ TrexStatelessDpCore::push_pcap(uint8_t port_id, double ipg_usec, double speedup, uint32_t count, - double duration) { + double duration, + bool is_dual) { TrexStatelessDpPerPort * lp_port = get_port_db(port_id); lp_port->set_event_id(event_id); /* delegate the command to the port */ - bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, speedup, count); + bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, speedup, count, is_dual); if (!rc) { /* report back that we stopped */ CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id); @@ -1253,7 +1256,8 @@ bool CGenNodePCAP::create(uint8_t port_id, const std::string &pcap_filename, double ipg_usec, double speedup, - uint32_t count) { + uint32_t count, + bool is_dual) { std::stringstream ss; m_type = CGenNode::PCAP_PKT; @@ -1261,7 +1265,8 @@ bool CGenNodePCAP::create(uint8_t port_id, m_src_port = 0; m_port_id = port_id; m_count = count; - + m_is_dual = is_dual; + /* mark this node as slow path */ set_slow_path(true); diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 9babb172..b386daf7 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -75,7 +75,8 @@ public: const std::string &pcap_filename, double ipg_usec, double speedup, - uint32_t count); + uint32_t count, + bool is_dual); bool stop_traffic(uint8_t port_id, bool stop_on_id, @@ -184,7 +185,8 @@ public: double ipg_usec, double speedup, uint32_t count, - double duration); + double duration, + bool is_dual); /** diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index 8a68625c..b4910fce 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -468,7 +468,8 @@ public: const std::string &pcap_filename, double ipg_usec, double speedup, - uint32_t count); + uint32_t count, + bool is_dual); /** * destroy the node cleaning up any data @@ -476,6 +477,10 @@ public: */ void destroy(); + bool is_dual() const { + return m_is_dual; + } + /** * advance - will read the next packet * @@ -505,6 +510,10 @@ public: } } + if (is_dual()) { + uint8_t dir = m_raw_packet->getInterface() & 0x1; + set_mbuf_dir(dir); + } } /** @@ -615,8 +624,10 @@ private: uint8_t m_port_id; + bool m_is_dual; + /* pad to match the size of CGenNode */ - uint8_t m_pad_end[33]; + uint8_t m_pad_end[32]; } __rte_cache_aligned; diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 1cbacb6f..95613b41 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -193,7 +193,8 @@ TrexStatelessDpPushPCAP::handle(TrexStatelessDpCore *dp_core) { m_ipg_usec, m_speedup, m_count, - m_duration); + m_duration, + m_is_dual); return true; } @@ -205,7 +206,8 @@ TrexStatelessDpPushPCAP::clone() { m_ipg_usec, m_speedup, m_count, - m_duration); + m_duration, + m_is_dual); return new_msg; } diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 9b1f2e31..fb2c27ab 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -259,13 +259,16 @@ public: double ipg_usec, double speedup, uint32_t count, - double duration) : m_pcap_filename(pcap_filename) { + double duration, + bool is_dual) : m_pcap_filename(pcap_filename) { + m_port_id = port_id; m_event_id = event_id; m_ipg_usec = ipg_usec; m_speedup = speedup; m_count = count; m_duration = duration; + m_is_dual = is_dual; } virtual bool handle(TrexStatelessDpCore *dp_core); @@ -280,6 +283,7 @@ private: double m_duration; uint32_t m_count; uint8_t m_port_id; + bool m_is_dual; }; |