diff options
-rwxr-xr-x | scripts/automation/trex_control_plane/stl/console/trex_console.py | 9 | ||||
-rwxr-xr-x | scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 93 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py | 37 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py | 35 | ||||
-rwxr-xr-x | scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py | 8 | ||||
-rwxr-xr-x | src/bp_sim.h | 1 | ||||
-rw-r--r-- | src/common/Network/Packet/Arp.h | 43 | ||||
-rwxr-xr-x | src/common/Network/Packet/EthernetHeader.h | 6 | ||||
-rw-r--r-- | src/common/Network/Packet/IcmpHeader.h | 5 | ||||
-rwxr-xr-x | src/common/Network/Packet/MacAddress.h | 5 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 6 | ||||
-rw-r--r-- | src/stateless/cp/trex_exception.h | 5 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_core.cpp | 4 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_port_mngr.cpp | 266 | ||||
-rw-r--r-- | src/stateless/rx/trex_stateless_rx_port_mngr.h | 30 | ||||
-rwxr-xr-x | src/trex_port_attr.h | 5 |
16 files changed, 510 insertions, 48 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 b33b0447..5ea959ac 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -488,7 +488,7 @@ class TRexConsole(TRexGeneralCmd): ############# update @verify_connected def do_update(self, line): - '''update speed of port(s)currently transmitting traffic\n''' + '''update speed of port(s) currently transmitting traffic\n''' self.stateless_client.update_line(line) @@ -549,6 +549,13 @@ class TRexConsole(TRexGeneralCmd): '''Clear cached local statistics\n''' self.stateless_client.clear_stats_line(line) + @verify_connected + def do_service (self, line): + '''Sets port(s) service mode state''' + self.stateless_client.service_line(line) + + def help_service (self, line): + self.do_service("-h") def help_clear(self): self.do_clear("-h") 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 cc20e088..fd41491e 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 @@ -878,6 +878,15 @@ class STLClient(object): return rc + def __set_service_mode (self, port_id_list, enabled): + port_id_list = self.__ports(port_id_list) + rc = RC() + + for port_id in port_id_list: + rc.add(self.ports[port_id].set_service_mode(enabled)) + + return rc + # connect to server def __connect(self): @@ -1387,6 +1396,12 @@ class STLClient(object): if port_obj.is_acquired() and port_obj.get_dst_addr()['ipv4'] is not None] + def get_service_enabled_ports(self): + return [port_id + for port_id, port_obj in self.ports.items() + if port_obj.is_acquired() and port_obj.is_service_mode_on()] + + # get paused ports def get_paused_ports (self, owned = True): if owned: @@ -1854,9 +1869,7 @@ class STLClient(object): raise STLError("pkt_size should be a value between 64 and 9216: '{0}'".format(pkt_size)) validate_type('count', count, int) - - - + self.logger.pre_cmd("Pinging {0} from port {1} with {2} bytes of data:".format(dst_ipv4, src_port, pkt_size)) @@ -2164,7 +2177,10 @@ class STLClient(object): unresolved_ports = [port_id for port_id in ports if not self.ports[port_id].is_resolved()] if unresolved_ports and not force: raise STLError("Port(s) {0} have unresolved destination addresses - please resolve them or specify 'force'".format(unresolved_ports)) - + + if self.get_service_enabled_ports() and not force: + raise STLError("Port(s) {0} are under service mode - please disable service mode or specify 'force'".format(self.get_service_enabled_ports())) + @__api_check(True) def start (self, @@ -2827,7 +2843,7 @@ class STLClient(object): validate_type('led_on', led_on, (bool, type(None))) validate_type('flow_ctrl', flow_ctrl, (int, type(None))) validate_choice('rxf', rxf, ['hw', 'all']) - + # common attributes for all ports cmn_attr_dict = {} @@ -2880,7 +2896,35 @@ class STLClient(object): self.resolve(ports = resolve_ports) + + @__api_check(True) + def set_service_mode (self, ports = None, enabled = True): + """ + Set service mode for port(s) + In service mode ports will respond to ARP, PING and etc. + + :parameters: + ports - for which ports to configure service mode on/off + enabled - True for activating service mode, False for disabling + :raises: + + :exe:'STLError' + + """ + # by default take all acquired ports + ports = ports if ports is not None else self.get_acquired_ports() + ports = self._validate_port_list(ports) + + if enabled: + self.logger.pre_cmd('Enabling service mode on port(s) {0}:'.format(ports)) + else: + self.logger.pre_cmd('Disabling service mode on port(s) {0}:'.format(ports)) + + rc = self.__set_service_mode(ports, enabled) + self.logger.post_cmd(rc) + if not rc: + raise STLError(rc) + @__api_check(True) def resolve (self, ports = None, retries = 0): @@ -3078,7 +3122,7 @@ class STLClient(object): try: rc = f(*args) except STLError as e: - client.logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold')) + client.logger.log("Action has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold')) return RC_ERR(e.brief()) # if got true - print time @@ -3697,18 +3741,12 @@ class STLClient(object): self.set_rx_sniffer_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.OUTPUT_FILENAME, - parsing_opts.LIMIT, - parsing_opts.ALL_FILES) + parsing_opts.LIMIT) opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True) if not opts: return opts - rxf = 'all' if opts.all else None - - if rxf: - self.set_port_attr(opts.ports, rxf = rxf) - self.set_rx_sniffer(opts.ports, opts.output_filename, opts.limit) return RC_OK() @@ -3840,10 +3878,37 @@ class STLClient(object): return "{0}(read-only)>".format(prefix) elif self.is_all_ports_acquired(): - return "{0}>".format(prefix) + p = prefix + + if self.get_service_enabled_ports(): + if self.get_service_enabled_ports() == self.get_acquired_ports(): + p += '(service)' + else: + p += '(service: {0})'.format(self.get_service_enabled_ports()) + + return "{0}>".format(p) else: return "{0} {1}>".format(prefix, self.get_acquired_ports()) + @__console + def service_line (self, line): + '''Configures port for service mode. + In service mode ports will reply to ARP, PING + and etc. + ''' + + parser = parsing_opts.gen_parser(self, + "service", + self.service_line.__doc__, + parsing_opts.PORT_LIST_WITH_ALL, + parsing_opts.SERVICE_OFF) + + opts = parser.parse_args(line.split()) + if not opts: + return opts + + self.set_service_mode(ports = opts.ports, enabled = opts.enabled) + 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 389a942b..4ac31fba 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 @@ -489,6 +489,9 @@ class Port(object): @owned def set_rx_sniffer (self, pcap_filename, limit): + if not self.is_service_mode_on(): + return self.err('port service mode must be enabled for performing RX capturing') + params = {"handler": self.handler, "port_id": self.port_id, "type": "capture", @@ -529,7 +532,8 @@ class Port(object): if rc.bad(): return self.err(rc.err()) - return self.ok() + # instead of updating manualy - let's sync with the server + return self.sync() @@ -684,6 +688,9 @@ class Port(object): json_attr['ipv4'] = {'addr': kwargs.get('ipv4')} if kwargs.get('dest') is not None: + if not self.is_service_mode_on(): + return self.err('setting destination requires port to be in service mode') + json_attr['dest'] = {'addr': kwargs.get('dest')} @@ -698,6 +705,26 @@ class Port(object): # update the dictionary from the server explicitly return self.sync() + + @owned + def set_service_mode (self, enabled): + rc = self.set_attr(rx_filter_mode = 'all' if enabled else 'hw') + if not rc: + return rc + + if not enabled: + rc = self.remove_rx_queue() + if not rc: + return rc + + rc = self.remove_rx_sniffer() + if not rc: + return rc + + return self.ok() + + def is_service_mode_on (self): + return self.get_rx_filter_mode() == 'all' @writeable def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler): @@ -877,6 +904,8 @@ class Port(object): return {'mac': src_mac, 'ipv4': src_ipv4} + def get_rx_filter_mode (self): + return self.__attr['rx_filter_mode'] def get_dst_addr (self): dest = self.__attr['dest'] @@ -904,10 +933,16 @@ class Port(object): @writeable def arp_resolve (self, retries): + if not self.is_service_mode_on(): + return self.err('port service mode must be enabled for performing ARP resolution') + return ARPResolver(self).resolve(retries) @writeable def ping (self, ping_ipv4, pkt_size): + if not self.is_service_mode_on(): + return self.err('port service mode must be enabled for performing ping') + return PingResolver(self, ping_ipv4, pkt_size).resolve() diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py index 3754e608..e0fc1724 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_rx_features.py @@ -46,11 +46,6 @@ class Resolver(object): # add the stream(s) self.port.add_streams(self.generate_request()) - - rc = self.port.set_attr(rx_filter_mode = 'all') - if not rc: - return rc - rc = self.port.set_rx_queue(size = 100) if not rc: return rc @@ -59,7 +54,6 @@ class Resolver(object): finally: # best effort restore - self.port.set_attr(rx_filter_mode = 'hw') self.port.remove_rx_queue() self.port.remove_all_streams() @@ -202,19 +196,13 @@ class PingResolver(Resolver): if self.dst['mac'] is None: return self.port.err('Ping - port has an unresolved destination, cannot determine next hop MAC address') - if self.ping_ip == self.src['ipv4']: - return self.port.err('Ping - cannot ping own IP') - return self.port.ok() # return a list of streams for request def generate_request (self): - src = self.port.get_src_addr() - dst = self.port.get_dst_addr() - - base_pkt = Ether(dst = dst['mac'])/IP(src = src['ipv4'], dst = self.ping_ip)/ICMP(type = 8) + base_pkt = Ether(dst = self.dst['mac'])/IP(src = self.src['ipv4'], dst = self.ping_ip)/ICMP(type = 8) pad = max(0, self.pkt_size - len(base_pkt)) base_pkt = base_pkt / (pad * 'x') @@ -222,6 +210,8 @@ class PingResolver(Resolver): #base_pkt.show2() s1 = STLStream( packet = STLPktBuilder(pkt = base_pkt), mode = STLTXSingleBurst(total_pkts = 1) ) + self.base_pkt = base_pkt + return [s1] # return None for more packets otherwise RC object @@ -230,23 +220,32 @@ class PingResolver(Resolver): if not 'ICMP' in scapy_pkt: return None - #scapy_pkt.show2() ip = scapy_pkt['IP'] - + if ip.dst != self.src['ipv4']: + return None + icmp = scapy_pkt['ICMP'] dt = pkt['ts'] - self.start_ts + # echo reply if icmp.type == 0: - # echo reply + # check seq + if icmp.seq != self.base_pkt['ICMP'].seq: + return None return self.port.ok('Reply from {0}: bytes={1}, time={2:.2f}ms, TTL={3}'.format(ip.src, len(pkt['binary']), dt * 1000, ip.ttl)) # unreachable elif icmp.type == 3: + # check seq + if icmp.payload.seq != self.base_pkt['ICMP'].seq: + return None return self.port.ok('Reply from {0}: Destination host unreachable'.format(icmp.src)) + else: - scapy_pkt.show2() - return self.port.err('unknown ICMP reply') + # skip any other types + #scapy_pkt.show2() + return None 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 7ae22e89..66a17a03 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 @@ -60,6 +60,8 @@ PING_IPV4 = 40 PING_COUNT = 41 PKT_SIZE = 42 +SERVICE_OFF = 43 + GLOBAL_STATS = 50 PORT_STATS = 51 PORT_STATUS = 52 @@ -575,6 +577,12 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': None, 'help': "Core mask - only cores responding to the bit mask will be active"}), + SERVICE_OFF: ArgumentPack(['--off'], + {'action': 'store_false', + 'dest': 'enabled', + 'default': True, + 'help': 'Deactivates services on port(s)'}), + # advanced options PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST, ALL_PORTS], diff --git a/src/bp_sim.h b/src/bp_sim.h index 914a26d9..454f5f19 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -643,7 +643,6 @@ public: CMacAddrCfg (){ memset(u.m_data,0,sizeof(u.m_data)); u.m_mac.dest[3]=1; - u.m_mac.src[3]=1; } union { mac_align_t m_mac; diff --git a/src/common/Network/Packet/Arp.h b/src/common/Network/Packet/Arp.h index a16605bd..e23ff139 100644 --- a/src/common/Network/Packet/Arp.h +++ b/src/common/Network/Packet/Arp.h @@ -20,8 +20,7 @@ limitations under the License. #pragma pack(push, 1) class ArpHdr { public: - enum arp_hdr_enum_e { - ARP_HDR_HRD_ETHER = 1, + enum arp_hdr_op_e { ARP_HDR_OP_REQUEST = 1, /* request to resolve address */ ARP_HDR_OP_REPLY = 2, /* response to previous request */ ARP_HDR_OP_REVREQUEST = 3, /* request proto addr given hardware */ @@ -30,6 +29,46 @@ class ArpHdr { ARP_HDR_OP_INVREPLY = 6, /* response identifying peer */ }; + enum arp_hdr_hrd_e { + ARP_HDR_HRD_ETHER = 1, + }; + + enum arp_hdr_proto_e { + ARP_HDR_PROTO_IPV4 = 0x800, + }; + + void setOp(uint16_t op) { + m_arp_op = PKT_HTONS(op); + } + + uint16_t getOp() const { + return PKT_NTOHS(m_arp_op); + } + + uint16_t getHrdType() const { + return PKT_NTOHS(m_arp_hrd); + } + + uint16_t getProtocolType() const { + return PKT_NTOHS(m_arp_pro); + } + + uint32_t getSip() const { + return PKT_NTOHL(m_arp_sip); + } + + void setSip(uint32_t sip) { + m_arp_sip = PKT_HTONL(sip); + } + + uint32_t getTip() const { + return PKT_NTOHL(m_arp_tip); + } + + void setTip(uint32_t tip) { + m_arp_tip = PKT_HTONL(tip); + } + public: uint16_t m_arp_hrd; /* format of hardware address */ uint16_t m_arp_pro; /* format of protocol address */ diff --git a/src/common/Network/Packet/EthernetHeader.h b/src/common/Network/Packet/EthernetHeader.h index c9dcdbe2..002d6c25 100755 --- a/src/common/Network/Packet/EthernetHeader.h +++ b/src/common/Network/Packet/EthernetHeader.h @@ -62,8 +62,10 @@ public: inline EthernetHeader(uint8_t* packet); inline uint8_t* getPointer (){return (uint8_t*)this;} - static inline uint32_t getSize (){return (uint32_t)sizeof(EthernetHeader);} - + inline uint32_t getSize () { + return ( (getNextProtocol() == Protocol::VLAN) ? 18 : 14); + } + // Get dest MAC pointer MacAddress *getDestMacP() { return &myDestination; } diff --git a/src/common/Network/Packet/IcmpHeader.h b/src/common/Network/Packet/IcmpHeader.h index 99d89329..4bc102e3 100644 --- a/src/common/Network/Packet/IcmpHeader.h +++ b/src/common/Network/Packet/IcmpHeader.h @@ -24,6 +24,11 @@ class ICMPHeader { public: + enum { + TYPE_ECHO_REPLY = 0, + TYPE_ECHO_REQUEST = 8, + }; + ICMPHeader() { setCode(0); diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h index 5dc4a9ea..9bd3eae1 100755 --- a/src/common/Network/Packet/MacAddress.h +++ b/src/common/Network/Packet/MacAddress.h @@ -137,6 +137,11 @@ public: return true; } + MacAddress& operator = (const uint8_t *rhs) { + memcpy(data, rhs, ETHER_ADDR_LEN); + return (*this); + } + uint8_t* GetBuffer() { return data; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index f92d18c4..a01d57a2 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -3618,9 +3618,7 @@ int CGlobalTRex::ixgbe_start(void){ if (! get_is_stateless()) { ixgbe_configure_mg(); - } else { - rx_sl_configure(); - } + } /* core 0 - control @@ -3759,6 +3757,8 @@ bool CGlobalTRex::Create(){ cfg.m_publisher = &m_zmq_publisher; m_trex_stateless = new TrexStateless(cfg); + + rx_sl_configure(); } return (true); diff --git a/src/stateless/cp/trex_exception.h b/src/stateless/cp/trex_exception.h index c12732ef..ffc2f734 100644 --- a/src/stateless/cp/trex_exception.h +++ b/src/stateless/cp/trex_exception.h @@ -55,7 +55,10 @@ class TrexException : public std::runtime_error T_FLOW_STAT_NO_FREE_HW_ID, T_FLOW_STAT_RX_CORE_START_FAIL, T_FLOW_STAT_BAD_HW_ID, - T_INVALID + + T_RX_PKT_PARSE_ERR, + + T_INVALID, }; TrexException() : std::runtime_error(""), m_type(T_INVALID) { diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp index f2061bf7..9898e8b9 100644 --- a/src/stateless/rx/trex_stateless_rx_core.cpp +++ b/src/stateless/rx/trex_stateless_rx_core.cpp @@ -84,11 +84,13 @@ void CRxCoreStateless::create(const CRxSlCfg &cfg) { /* create per port manager */ for (int i = 0; i < m_max_ports; i++) { + const TRexPortAttr *port_attr = get_stateless_obj()->get_platform_api()->getPortAttrObj(i); m_rx_port_mngr[i].create(cfg.m_ports[i], m_rfc2544, &m_err_cntrs, &m_cpu_dp_u, - cfg.m_num_crc_fix_bytes); + cfg.m_num_crc_fix_bytes, + port_attr); } } diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp index afc6827c..af312700 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp @@ -22,6 +22,7 @@ #include "trex_stateless_rx_port_mngr.h" #include "common/captureFile.h" #include "trex_stateless_rx_core.h" +#include "common/Network/Packet/Arp.h" /************************************** * latency RX feature @@ -400,6 +401,259 @@ RXPacketRecorder::to_json() const { return output; } + +/************************************** + * RX feature server (ARP, ICMP) and etc. + * + *************************************/ + +class RXPktParser { +public: + RXPktParser(const rte_mbuf_t *m) { + + m_mbuf = m; + + /* start point */ + m_current = rte_pktmbuf_mtod(m, uint8_t *);; + m_size_left = rte_pktmbuf_pkt_len(m); + + m_ether = NULL; + m_arp = NULL; + m_ipv4 = NULL; + m_icmp = NULL; + m_vlan_tag = 0; + + /* ethernet */ + m_ether = (EthernetHeader *)parse_bytes(14); + + uint16_t next_proto; + if (m_ether->getNextProtocol() == EthernetHeader::Protocol::VLAN) { + parse_bytes(4); + m_vlan_tag = m_ether->getVlanTag(); + next_proto = m_ether->getVlanProtocol(); + } else { + next_proto = m_ether->getNextProtocol(); + } + + /** + * support only for ARP or IPv4 based protocols + */ + switch (next_proto) { + case EthernetHeader::Protocol::ARP: + parse_arp(); + return; + + case EthernetHeader::Protocol::IP: + parse_ipv4(); + return; + + default: + return; + } + + } + + const rte_mbuf_t *m_mbuf; + EthernetHeader *m_ether; + ArpHdr *m_arp; + IPHeader *m_ipv4; + ICMPHeader *m_icmp; + uint16_t m_vlan_tag; + +protected: + + const uint8_t *parse_bytes(uint32_t size) { + if (m_size_left < size) { + parse_err(); + } + + const uint8_t *p = m_current; + m_current += size; + m_size_left -= size; + + return p; + } + + void parse_arp() { + m_arp = (ArpHdr *)parse_bytes(sizeof(ArpHdr)); + } + + void parse_ipv4() { + m_ipv4 = (IPHeader *)parse_bytes(IPHeader::DefaultSize); + + /* advance over IP options if exists */ + parse_bytes(m_ipv4->getOptionLen()); + + switch (m_ipv4->getNextProtocol()) { + case IPHeader::Protocol::ICMP: + parse_icmp(); + return; + + default: + return; + } + } + + void parse_icmp() { + m_icmp = (ICMPHeader *)parse_bytes(sizeof(ICMPHeader)); + } + + void parse_err() { + throw TrexException(TrexException::T_RX_PKT_PARSE_ERR); + } + + const uint8_t *m_current; + uint16_t m_size_left; +}; + +RXServer::RXServer() { + m_port_attr = NULL; + m_io = NULL; + m_port_id = 255; +} + +void +RXServer::create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io) { + m_port_attr = port_attr; + m_io = io; + m_port_id = port_attr->get_port_id(); +} + + +void +RXServer::handle_pkt(const rte_mbuf_t *m) { + + RXPktParser parser(m); + + if (parser.m_icmp) { + handle_icmp(parser); + } else if (parser.m_arp) { + handle_arp(parser); + } else { + return; + } + +} +void +RXServer::handle_icmp(RXPktParser &parser) { + + /* maybe not for us... */ + if (parser.m_ipv4->getDestIp() != m_port_attr->get_src_ipv4()) { + return; + } + + /* we handle only echo request */ + if (parser.m_icmp->getType() != ICMPHeader::TYPE_ECHO_REQUEST) { + return; + } + + /* duplicate the MBUF */ + rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf); + if (!response) { + return; + } + + /* reparse the cloned packet */ + RXPktParser response_parser(response); + + /* swap MAC */ + MacAddress tmp = response_parser.m_ether->mySource; + response_parser.m_ether->mySource = response_parser.m_ether->myDestination; + response_parser.m_ether->myDestination = tmp; + + /* swap IP */ + std::swap(response_parser.m_ipv4->mySource, response_parser.m_ipv4->myDestination); + + /* new packet - new TTL */ + response_parser.m_ipv4->setTimeToLive(128); + response_parser.m_ipv4->updateCheckSum(); + + /* update type and fix checksum */ + response_parser.m_icmp->setType(ICMPHeader::TYPE_ECHO_REPLY); + response_parser.m_icmp->updateCheckSum(response_parser.m_ipv4->getTotalLength() - response_parser.m_ipv4->getHeaderLength()); + + /* send */ + m_io->tx(response); +} + +void +RXServer::handle_arp(RXPktParser &parser) { + + /* only ethernet format supported */ + if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) { + return; + } + + /* IPV4 only */ + if (parser.m_arp->getProtocolType() != ArpHdr::ARP_HDR_PROTO_IPV4) { + return; + } + + /* support only for ARP request */ + if (parser.m_arp->getOp() != ArpHdr::ARP_HDR_OP_REQUEST) { + return; + } + + /* are we the target ? if not - go home */ + if (parser.m_arp->getTip() != m_port_attr->get_src_ipv4()) { + return; + } + + /* duplicate the MBUF */ + rte_mbuf_t *response = duplicate_mbuf(parser.m_mbuf); + if (!response) { + return; + } + + /* reparse the cloned packet */ + RXPktParser response_parser(response); + + /* reply */ + response_parser.m_arp->setOp(ArpHdr::ARP_HDR_OP_REPLY); + + /* fix the MAC addresses */ + response_parser.m_ether->mySource = m_port_attr->get_src_mac(); + response_parser.m_ether->myDestination = parser.m_ether->mySource; + + /* fill up the fields */ + + /* src */ + response_parser.m_arp->m_arp_sha = m_port_attr->get_src_mac(); + response_parser.m_arp->setSip(m_port_attr->get_src_ipv4()); + + /* dst */ + response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha; + response_parser.m_arp->m_arp_tip = parser.m_arp->m_arp_sip; + + /* send */ + m_io->tx(response); + +} + +rte_mbuf_t * +RXServer::duplicate_mbuf(const rte_mbuf_t *m) { + /* RX packets should always be one segment */ + assert(m->nb_segs == 1); + + /* allocate */ + rte_mbuf_t *clone_mbuf = CGlobalInfo::pktmbuf_alloc_by_port(m_port_id, rte_pktmbuf_pkt_len(m)); + if (!clone_mbuf) { + return NULL; + } + + /* append data */ + uint8_t *dest = (uint8_t *)rte_pktmbuf_append(clone_mbuf, rte_pktmbuf_pkt_len(m)); + if (!dest) { + return NULL; + } + + /* copy data */ + const uint8_t *src = rte_pktmbuf_mtod(m, const uint8_t *); + memcpy(dest, src, rte_pktmbuf_pkt_len(m)); + + return clone_mbuf; +} + /************************************** * Port manager * @@ -417,13 +671,18 @@ RXPortManager::create(CPortLatencyHWBase *io, CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs, CCpuUtlDp *cpu_util, - uint8_t crc_bytes_num) { + uint8_t crc_bytes_num, + const TRexPortAttr *port_attr) { m_io = io; m_cpu_dp_u = cpu_util; m_num_crc_fix_bytes = crc_bytes_num; /* init features */ m_latency.create(rfc2544, err_cntrs); + m_server.create(port_attr, io); + + /* by default, server feature is always on */ + set_feature(SERVER); } void RXPortManager::handle_pkt(const rte_mbuf_t *m) { @@ -441,6 +700,10 @@ void RXPortManager::handle_pkt(const rte_mbuf_t *m) { if (is_feature_set(QUEUE)) { m_queue.handle_pkt(m); } + + if (is_feature_set(SERVER)) { + m_server.handle_pkt(m); + } } @@ -513,3 +776,4 @@ RXPortManager::to_json() const { return output; } + diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.h b/src/stateless/rx/trex_stateless_rx_port_mngr.h index c049cb56..12b601ea 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.h +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h @@ -255,6 +255,28 @@ private: }; +/************************************** + * RX server (ping, ARP and etc.) + * + *************************************/ +class RXPktParser; +class RXServer { +public: + + RXServer(); + void create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io); + void handle_pkt(const rte_mbuf_t *m); + +private: + void handle_icmp(RXPktParser &parser); + void handle_arp(RXPktParser &parser); + rte_mbuf_t *duplicate_mbuf(const rte_mbuf_t *m); + + const TRexPortAttr *m_port_attr; + CPortLatencyHWBase *m_io; + uint8_t m_port_id; +}; + /************************ manager ***************************/ /** @@ -268,7 +290,8 @@ public: NO_FEATURES = 0x0, LATENCY = 0x1, RECORDER = 0x2, - QUEUE = 0x4 + QUEUE = 0x4, + SERVER = 0x8 }; RXPortManager(); @@ -277,7 +300,8 @@ public: CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs, CCpuUtlDp *cpu_util, - uint8_t crc_bytes_num); + uint8_t crc_bytes_num, + const TRexPortAttr *port_attr); void clear_stats() { m_latency.reset_stats(); @@ -403,6 +427,8 @@ private: RXLatency m_latency; RXPacketRecorder m_recorder; RXQueue m_queue; + RXServer m_server; + // compensate for the fact that hardware send us packets without Ethernet CRC, and we report with it uint8_t m_num_crc_fix_bytes; diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h index 3cb9beff..ae397430 100755 --- a/src/trex_port_attr.h +++ b/src/trex_port_attr.h @@ -134,7 +134,7 @@ public: virtual void get_description(std::string &description) { description = intf_info_st.description; } virtual void get_supported_speeds(supp_speeds_t &supp_speeds) = 0; - uint32_t get_src_ipv4() {return m_src_ipv4;} + uint32_t get_src_ipv4() const {return m_src_ipv4;} DestAttr & get_dest() {return m_dest;} const uint8_t *get_src_mac() const; @@ -161,6 +161,9 @@ public: /* dump object status to JSON */ void to_json(Json::Value &output); + uint8_t get_port_id() const { + return m_port_id; + } protected: |