DUAL mode - phase #1
authorimarom <[email protected]>
Sun, 4 Sep 2016 12:25:42 +0000 (15:25 +0300)
committerimarom <[email protected]>
Wed, 7 Sep 2016 11:02:55 +0000 (14:02 +0300)
14 files changed:
scripts/automation/trex_control_plane/stl/console/trex_tui.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
src/common/erf.cpp
src/rpc-server/commands/trex_rpc_cmd_general.cpp
src/stateless/cp/trex_stateless_port.cpp
src/stateless/cp/trex_stateless_port.h
src/stateless/dp/trex_stateless_dp_core.cpp
src/stateless/dp/trex_stateless_dp_core.h
src/stateless/dp/trex_stream_node.h
src/stateless/messaging/trex_stateless_messaging.cpp
src/stateless/messaging/trex_stateless_messaging.h

index e769b9b..c020f53 100644 (file)
@@ -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
index 7101b8a..2c1fa5e 100755 (executable)
@@ -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],
index 890ce7d..f0e3b10 100644 (file)
@@ -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():
index afb0179..4586f64 100644 (file)
@@ -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)
index 9ed6c0f..4e57aae 100755 (executable)
@@ -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',
index 304f758..c4c1499 100755 (executable)
@@ -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);
index cd845fc..ba3c165 100644 (file)
@@ -509,16 +509,26 @@ trex_rpc_cmd_rc_e
 TrexRpcCmdPushRemote::_run(const Json::Value &params, 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());
     }
index 2a545c5..df50d3e 100644 (file)
@@ -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);
index ba86a27..147efc7 100644 (file)
@@ -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);
 
index 4d9137f..e567959 100644 (file)
@@ -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);
 
index 9babb17..b386daf 100644 (file)
@@ -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);
 
 
     /**
index 8a68625..b4910fc 100644 (file)
@@ -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;
 
index 1cbacb6..95613b4 100644 (file)
@@ -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;
 }
index 9b1f2e3..fb2c27a 100644 (file)
@@ -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;
 };