summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py7
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py108
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py37
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py2
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py28
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp3
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp16
-rw-r--r--src/stateless/cp/trex_stateless_port.h9
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.cpp2
-rw-r--r--src/stateless/messaging/trex_stateless_messaging.h7
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.cpp4
-rw-r--r--src/stateless/rx/trex_stateless_rx_core.h2
-rw-r--r--src/stateless/rx/trex_stateless_rx_defs.h27
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.cpp7
-rw-r--r--src/stateless/rx/trex_stateless_rx_port_mngr.h9
15 files changed, 231 insertions, 37 deletions
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 b23b5f1f..92c04a7f 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -327,6 +327,13 @@ class TRexConsole(TRexGeneralCmd):
def help_portattr (self):
self.do_portattr("-h")
+ def do_set_rx_sniffer (self, line):
+ '''Sets a port sniffer on RX channel as PCAP recorder'''
+ self.stateless_client.set_rx_sniffer_line(line)
+
+ def help_sniffer (self):
+ self.do_set_rx_sniffer("-h")
+
@verify_connected
def do_map (self, line):
'''Maps ports topology\n'''
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 907e405a..b9143896 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
@@ -24,6 +24,8 @@ import re
import random
import json
import traceback
+import os.path
+
############################ logger #############################
############################ #############################
@@ -322,26 +324,28 @@ class EventsHandler(object):
# port attr changed
elif (event_type == 8):
+ return
- 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_formatted_info()
- self.__async_event_port_attr_changed(port_id, data['attr'])
-
- new_info = self.client.ports[port_id].get_formatted_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
+ # 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_formatted_info()
+ # self.__async_event_port_attr_changed(port_id, data['attr'])
+ #
+ # new_info = self.client.ports[port_id].get_formatted_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 (event_type == 100):
ev = "Server has stopped"
@@ -814,6 +818,17 @@ class STLClient(object):
return rc
+ def __set_rx_sniffer (self, port_id_list, base_filename, limit):
+ port_id_list = self.__ports(port_id_list)
+ rc = RC()
+
+ for port_id in port_id_list:
+ head, tail = os.path.splitext(base_filename)
+ filename = "{0}-{1}{2}".format(head, port_id, tail)
+ rc.add(self.ports[port_id].set_rx_sniffer(filename, limit))
+
+ return rc
+
# connect to server
def __connect(self):
@@ -2685,6 +2700,39 @@ class STLClient(object):
if not rc:
raise STLError(rc)
+
+
+ @__api_check(True)
+ def set_rx_sniffer (self, ports = None, base_filename = 'rx_capture', limit = 1000):
+ """
+ Sets RX sniffer for port(s) written to a PCAP file
+
+ :parameters:
+ ports - for which ports to apply a unique sniffer (each port gets a unique file)
+ base_filename - filename will be appended with '-<port_number>'
+ limit - limit how many packets will be written
+ :raises:
+ + :exe:'STLError'
+
+ """
+ ports = ports if ports is not None else self.get_acquired_ports()
+ ports = self._validate_port_list(ports)
+
+ # check arguments
+ validate_type('base_filename', base_filename, basestring)
+ validate_type('limit', limit, (int))
+
+
+ self.logger.pre_cmd("Setting RX sniffers on port(s) {0}:".format(ports))
+ rc = self.__set_rx_sniffer(ports, base_filename, limit)
+ self.logger.post_cmd(rc)
+
+
+ if not rc:
+ raise STLError(rc)
+
+
+
def clear_events (self):
"""
Clear all events
@@ -3281,7 +3329,29 @@ class STLClient(object):
return self.set_port_attr(opts.ports, opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.rx_filter_mode)
-
+
+ @__console
+ def set_rx_sniffer_line (self, line):
+ '''Sets a port sniffer on RX channel in form of a PCAP file'''
+
+ parser = parsing_opts.gen_parser(self,
+ "set_rx_sniffer",
+ self.set_rx_sniffer_line.__doc__,
+ parsing_opts.PORT_LIST_WITH_ALL,
+ parsing_opts.OUTPUT_FILENAME,
+ parsing_opts.LIMIT,
+ parsing_opts.ALL_FILES)
+
+ opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True)
+ if not opts:
+ return opts
+
+ if parsing_opts.ALL_FILES:
+ self.set_port_attr(ports = opts.ports, rx_filter_mode = 'all')
+
+ self.set_rx_sniffer(opts.ports, opts.output_filename, opts.limit)
+
+
@__console
def show_profile_line (self, line):
'''Shows profile information'''
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 59793495..571a6e16 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
@@ -252,6 +252,10 @@ class Port(object):
# attributes
self.attr = rc.data()['attr']
+
+ # rx info
+ self.rx_info = rc.data()['rx_info']
+
return self.ok()
@@ -484,18 +488,15 @@ class Port(object):
return self.ok()
- #
+
@writeable
- def start_rx_capture (self, pcap_filename, limit):
-
- prefix, suffix = pcap_filename.split('.')
- filename = "{0}-{1}.{2}".format(prefix, self.port_id, suffix)
+ def set_rx_sniffer (self, pcap_filename, limit):
params = {"handler": self.handler,
"port_id": self.port_id,
"type": "capture",
"enabled": True,
- "pcap_filename": filename,
+ "pcap_filename": pcap_filename,
"limit": limit}
rc = self.transmit("set_rx_feature", params)
@@ -679,6 +680,10 @@ class Port(object):
# generate formatted (console friendly) port info
def get_formatted_info (self):
+
+ # sync the attributes
+ self.sync()
+
info = dict(self.info)
info['status'] = self.get_port_state_name()
@@ -726,7 +731,22 @@ class Port(object):
else:
info['speed'] = 'N/A'
- info['rx_filter_mode'] = self.attr.get('rx_filter_mode', 'N/A')
+
+ # RX info
+ if 'rx_filter_mode' in self.attr:
+ info['rx_filter_mode'] = 'Hardware Match' if self.attr['rx_filter_mode'] == 'hw' else 'Fetch All'
+ else:
+ info['rx_filter_mode'] = 'N/A'
+
+ if 'sniffer' in self.rx_info:
+ sniffer = self.rx_info['sniffer']
+ if sniffer['is_active']:
+ info['rx_sniffer'] = '{0}\n[{1} / {2}]'.format(sniffer['pcap_filename'], sniffer['count'], sniffer['limit'])
+ else:
+ info['rx_sniffer'] = 'off'
+ else:
+ info['rx_sniffer'] = 'N/A'
+
return info
@@ -759,6 +779,9 @@ class Port(object):
"flow ctrl" : info['fc'],
"RX Filter Mode": info['rx_filter_mode'],
+ "RX Queueing": 'off',
+ "RX sniffer": info['rx_sniffer'],
+
}
def clear_stats(self):
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 7e47eb61..5e71b7f2 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
@@ -678,6 +678,8 @@ class CTRexInfoGenerator(object):
("NUMA Node", []),
("----", []),
("RX Filter Mode", []),
+ ("RX Queueing", []),
+ ("RX sniffer", []),
]
)
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 0d316c9e..715a741e 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
@@ -45,6 +45,10 @@ FLOW_CTRL = 28
SUPPORTED = 29
RX_FILTER_MODE = 30
+OUTPUT_FILENAME = 31
+ALL_FILES = 32
+LIMIT = 33
+
GLOBAL_STATS = 50
PORT_STATS = 51
PORT_STATUS = 52
@@ -310,6 +314,29 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
'choices': ['hw', 'all']}),
+ OUTPUT_FILENAME: ArgumentPack(['-o', '--output'],
+ {'help': 'Output PCAP filename',
+ 'dest': 'output_filename',
+ 'default': None,
+ 'required': True,
+ 'type': str}),
+
+
+
+ ALL_FILES: ArgumentPack(['--all'],
+ {'help': 'change RX port filter to fetch all packets',
+ 'dest': 'all',
+ 'default': False,
+ 'action': "store_true"}),
+
+
+ LIMIT: ArgumentPack(['-l', '--limit'],
+ {'help': 'Limit the packet count to be written to the file',
+ 'dest': 'limit',
+ 'default': 1000,
+ 'type': int}),
+
+
SUPPORTED: ArgumentPack(['--supp'],
{'help': 'Show which attributes are supported by current NICs',
'default': None,
@@ -459,6 +486,7 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
ALL_PORTS],
{'required': False}),
+
STREAM_FROM_PATH_OR_FILE: ArgumentGroup(MUTEX, [FILE_PATH,
FILE_FROM_DB],
{'required': True}),
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 7baae899..a441fc33 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -615,6 +615,9 @@ TrexRpcCmdGetPortStatus::_run(const Json::Value &params, Json::Value &result) {
/* RX data */
result["result"]["attr"]["rx_filter_mode"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_rx_filter_mode();
+ /* RX sniffer */
+ port->get_rx_capture_info().to_json(result["result"]["rx_info"]["sniffer"]);
+
return (TREX_RPC_CMD_OK);
}
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index c0156c12..f93d7abd 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -946,7 +946,15 @@ TrexStatelessPort::remove_and_delete_all_streams() {
void
TrexStatelessPort::start_rx_capture(const std::string &pcap_filename, uint64_t limit) {
- TrexStatelessCpToRxMsgBase *msg = new TrexStatelessRxStartCapture(m_port_id, pcap_filename, limit);
+
+ m_rx_capture_info.m_is_active = true;
+ m_rx_capture_info.m_limit = limit;
+ m_rx_capture_info.m_pcap_filename = pcap_filename;
+
+ TrexStatelessCpToRxMsgBase *msg = new TrexStatelessRxStartCapture(m_port_id,
+ pcap_filename,
+ limit,
+ &m_rx_capture_info.m_shared_counter);
send_message_to_rx(msg);
}
@@ -956,6 +964,12 @@ TrexStatelessPort::stop_rx_capture() {
send_message_to_rx(msg);
}
+const RXCaptureInfo &
+TrexStatelessPort::get_rx_capture_info() {
+ return m_rx_capture_info;
+}
+
+
RxPacketBuffer *
TrexStatelessPort::get_rx_sw_pkts() {
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index 5a1935a1..973a95c6 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -33,6 +33,7 @@ class TrexStreamsGraphObj;
class TrexPortMultiplier;
class RxPacketBuffer;
+
/**
* TRex port owner can perform
* write commands
@@ -382,6 +383,12 @@ public:
void stop_rx_capture();
/**
+ * status of the RX capture
+ *
+ */
+ const RXCaptureInfo &get_rx_capture_info();
+
+ /**
* fetch the RX software packets from the queue
*
*/
@@ -473,6 +480,8 @@ private:
TrexPortOwner m_owner;
int m_pending_async_stop_event;
+
+ RXCaptureInfo m_rx_capture_info;
};
diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp
index 6e7bfee5..bd444dff 100644
--- a/src/stateless/messaging/trex_stateless_messaging.cpp
+++ b/src/stateless/messaging/trex_stateless_messaging.cpp
@@ -264,7 +264,7 @@ TrexStatelessRxSwGetPkts::TrexStatelessRxSwGetPkts(uint8_t port_id, TrexStateles
bool
TrexStatelessRxStartCapture::handle(CRxCoreStateless *rx_core) {
- rx_core->start_capture(m_port_id, m_pcap_filename, m_limit);
+ rx_core->start_capture(m_port_id, m_pcap_filename, m_limit, m_shared_counter);
return true;
}
diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h
index e96e83d6..f35d9da6 100644
--- a/src/stateless/messaging/trex_stateless_messaging.h
+++ b/src/stateless/messaging/trex_stateless_messaging.h
@@ -423,9 +423,13 @@ class TrexStatelessRxQuit : public TrexStatelessCpToRxMsgBase {
class TrexStatelessRxStartCapture : public TrexStatelessCpToRxMsgBase {
public:
- TrexStatelessRxStartCapture(uint8_t port_id, const std::string &pcap_filename, uint64_t limit) : m_pcap_filename(pcap_filename) {
+ TrexStatelessRxStartCapture(uint8_t port_id,
+ const std::string &pcap_filename,
+ uint64_t limit,
+ uint64_t *shared_counter) : m_pcap_filename(pcap_filename) {
m_port_id = port_id;
m_limit = limit;
+ m_shared_counter = shared_counter;
}
virtual bool handle(CRxCoreStateless *rx_core);
@@ -434,6 +438,7 @@ private:
uint8_t m_port_id;
std::string m_pcap_filename;
uint64_t m_limit;
+ uint64_t *m_shared_counter;
};
diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp
index ee9c64c4..3fe72f54 100644
--- a/src/stateless/rx/trex_stateless_rx_core.cpp
+++ b/src/stateless/rx/trex_stateless_rx_core.cpp
@@ -356,8 +356,8 @@ double CRxCoreStateless::get_cpu_util() {
void
-CRxCoreStateless::start_capture(uint8_t port_id, const std::string &pcap_filename, uint64_t limit) {
- m_rx_port_mngr[port_id].start_capture(pcap_filename, limit);
+CRxCoreStateless::start_capture(uint8_t port_id, const std::string &pcap_filename, uint64_t limit, uint64_t *shared_counter) {
+ m_rx_port_mngr[port_id].start_capture(pcap_filename, limit, shared_counter);
}
void
diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h
index 425c15ae..689b28ec 100644
--- a/src/stateless/rx/trex_stateless_rx_core.h
+++ b/src/stateless/rx/trex_stateless_rx_core.h
@@ -124,7 +124,7 @@ class CRxCoreStateless {
* @param pcap_filename
* @param limit
*/
- void start_capture(uint8_t port_id, const std::string &pcap_filename, uint64_t limit);
+ void start_capture(uint8_t port_id, const std::string &pcap_filename, uint64_t limit, uint64_t *shared_counter);
void stop_capture(uint8_t port_id);
/**
diff --git a/src/stateless/rx/trex_stateless_rx_defs.h b/src/stateless/rx/trex_stateless_rx_defs.h
index 9df6af67..0b7d1aa3 100644
--- a/src/stateless/rx/trex_stateless_rx_defs.h
+++ b/src/stateless/rx/trex_stateless_rx_defs.h
@@ -23,6 +23,7 @@
#define __TREX_STATELESS_RX_DEFS_H__
#include "trex_defs.h"
+#include <json/json.h>
class CPortLatencyHWBase;
@@ -54,4 +55,30 @@ typedef enum rx_filter_mode_ {
RX_FILTER_MODE_ALL
} rx_filter_mode_e;
+/**
+ * holds RX capture info
+ *
+ */
+struct RXCaptureInfo {
+ RXCaptureInfo() {
+ m_is_active = false;
+ m_limit = 0;
+ m_shared_counter = 0;
+ }
+
+ void to_json(Json::Value &output) const {
+ output["is_active"] = m_is_active;
+ if (m_is_active) {
+ output["pcap_filename"] = m_pcap_filename;
+ output["limit"] = Json::UInt64(m_limit);
+ output["count"] = Json::UInt64(m_shared_counter);
+ }
+ }
+
+ bool m_is_active;
+ std::string m_pcap_filename;
+ uint64_t m_limit;
+ uint64_t m_shared_counter;
+};
+
#endif /* __TREX_STATELESS_RX_DEFS_H__ */
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
index 35d331cf..7283f703 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp
@@ -139,6 +139,7 @@ RXLatency::reset_stats() {
RXPacketRecorder::RXPacketRecorder() {
m_writer = NULL;
+ m_shared_counter = NULL;
m_limit = 0;
m_epoch = -1;
}
@@ -148,7 +149,7 @@ RXPacketRecorder::~RXPacketRecorder() {
}
void
-RXPacketRecorder::start(const std::string &pcap, uint64_t limit) {
+RXPacketRecorder::start(const std::string &pcap, uint64_t limit, uint64_t *shared_counter) {
m_writer = CCapWriterFactory::CreateWriter(LIBPCAP, (char *)pcap.c_str());
if (m_writer == NULL) {
std::stringstream ss;
@@ -158,6 +159,8 @@ RXPacketRecorder::start(const std::string &pcap, uint64_t limit) {
assert(limit > 0);
m_limit = limit;
+ m_shared_counter = shared_counter;
+ (*m_shared_counter) = 0;
}
void
@@ -192,6 +195,8 @@ RXPacketRecorder::handle_pkt(const rte_mbuf_t *m) {
m_writer->write_packet(&m_pkt);
m_limit--;
+ (*m_shared_counter)++;
+
if (m_limit == 0) {
stop();
}
diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h
index 7cc527d8..90527f0c 100644
--- a/src/stateless/rx/trex_stateless_rx_port_mngr.h
+++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h
@@ -212,7 +212,7 @@ class RXPacketRecorder {
public:
RXPacketRecorder();
~RXPacketRecorder();
- void start(const std::string &pcap, uint64_t limit);
+ void start(const std::string &pcap, uint64_t limit, uint64_t *shared_counter);
void stop();
void handle_pkt(const rte_mbuf_t *m);
@@ -220,7 +220,8 @@ private:
CFileWriterBase *m_writer;
CCapPktRaw m_pkt;
dsec_t m_epoch;
- uint32_t m_limit;
+ uint64_t m_limit;
+ uint64_t *m_shared_counter;
};
@@ -279,8 +280,8 @@ public:
* @param pcap
* @param limit_pkts
*/
- void start_capture(const std::string &pcap, uint64_t limit_pkts) {
- m_recorder.start(pcap, limit_pkts);
+ void start_capture(const std::string &pcap, uint64_t limit_pkts, uint64_t *shared_counter) {
+ m_recorder.start(pcap, limit_pkts, shared_counter);
set_feature(CAPTURE);
}