diff options
author | 2016-11-06 17:20:17 +0200 | |
---|---|---|
committer | 2016-11-06 17:20:17 +0200 | |
commit | a1ade6fd8e044b9866a8644db3519305539cfc61 (patch) | |
tree | 08b4d0e2db80c4d1e5cb759512c5e3631c19fd95 | |
parent | 234779fd32e747f4ac918f3c39e59618dde0f2d7 (diff) |
RX features - RX sniffer
Signed-off-by: imarom <imarom@cisco.com>
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 ¶ms, 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); } |