From 0c45815234abbb79b147b8093eb19e274ee65f52 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 12 Dec 2016 19:26:24 +0200 Subject: grat ARP Signed-off-by: imarom --- .../trex_control_plane/stl/console/trex_console.py | 19 +++ .../stl/trex_stl_lib/trex_stl_client.py | 176 ++++++++++++++------- .../stl/trex_stl_lib/trex_stl_port.py | 18 ++- .../stl/trex_stl_lib/utils/parsing_opts.py | 37 ++--- src/common/Network/Packet/MacAddress.h | 2 +- src/main_dpdk.cpp | 25 ++- src/rpc-server/commands/trex_rpc_cmd_general.cpp | 4 +- src/stateless/cp/trex_stateless_port.cpp | 13 ++ src/stateless/cp/trex_stateless_port.h | 6 + .../messaging/trex_stateless_messaging.cpp | 5 + src/stateless/messaging/trex_stateless_messaging.h | 17 ++ src/stateless/rx/trex_stateless_rx_core.cpp | 16 +- src/stateless/rx/trex_stateless_rx_core.h | 2 +- src/stateless/rx/trex_stateless_rx_port_mngr.cpp | 86 ++++++++-- src/stateless/rx/trex_stateless_rx_port_mngr.h | 55 ++++++- src/trex_port_attr.cpp | 9 +- src/trex_port_attr.h | 6 +- src/utl_ip.cpp | 20 ++- src/utl_ip.h | 31 +++- 19 files changed, 407 insertions(+), 140 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 eb8a0443..1a97ad0c 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -329,6 +329,25 @@ class TRexConsole(TRexGeneralCmd): def help_portattr (self): self.do_portattr("-h") + @verify_connected + def do_source (self, line): + '''Configure source address for port(s)\n''' + self.stateless_client.set_source_addr_line(line) + + def help_source (self): + self.do_source("-h") + + + @verify_connected + def do_dest (self, line): + '''Configure destination address for port(s)\n''' + self.stateless_client.set_dest_addr_line(line) + + def help_dest (self): + self.do_dest("-h") + + + @verify_connected def do_set_rx_sniffer (self, line): '''Sets a port sniffer on RX channel as PCAP recorder''' 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 fe691fb0..80daadd2 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 @@ -1843,6 +1843,74 @@ class STLClient(object): raise STLError(rc) + + @__api_check(True) + def set_source_addr (self, port, addr): + """ + Configures a port with a source address + + :parameters: + port - the port to set the source address + addr - source address. currently only IPv4 is supported + :raises: + + :exc:`STLError` + """ + + validate_type('port', port, int) + if port not in self.get_all_ports(): + raise STLError("port {0} is not a valid port id".format(port)) + + if not is_valid_ipv4(addr): + raise STLError("addr is not a valid IPv4 address: '{0}'".format(addr)) + + self.logger.pre_cmd("Setting port {0} source address as '{1}': ".format(port, addr)) + rc = self.ports[port].set_source_addr(addr) + self.logger.post_cmd(rc) + + if not rc: + raise STLError(rc) + + # for MAC dest - no resolve + if not self.ports[port].get_dst_addr()['ipv4']: + return rc + + # resolve the address + return self.resolve(ports = port, verbose = False) + + + @__api_check(True) + def set_dest_addr (self, port, addr): + """ + Configures a port with a destination address + + :parameters: + port - the port to set the destination address + addr - destination address. can be either MAC or IPv4 + :raises: + + :exc:`STLError` + """ + + validate_type('port', port, int) + if port not in self.get_all_ports(): + raise STLError("port {0} is not a valid port id".format(port)) + + if not is_valid_ipv4(addr) and not is_valid_mac(addr): + raise STLError("addr is not a valid IPv4 address or a MAC address: '{0}'".format(addr)) + + if is_valid_ipv4(addr) and not self.ports[port].get_src_addr()['ipv4']: + raise STLError("cannot configure destination as IPv4 address without IPv4 source address") + + self.logger.pre_cmd("Setting port {0} destination address as '{1}': ".format(port, addr)) + rc = self.ports[port].set_dest_addr(addr) + self.logger.post_cmd(rc) + + if not rc: + raise STLError(rc) + + # resolve the address + return self.resolve(ports = port, verbose = False) + + @__api_check(True) def ping_ip (self, src_port, dst_ipv4, pkt_size = 64, count = 5): """ @@ -2010,8 +2078,8 @@ class STLClient(object): self.clear_stats(ports) self.set_port_attr(ports, promiscuous = False, - link_up = True if restart else None, - rxf = 'hw') + link_up = True if restart else None) + self.set_service_mode(ports, False) self.remove_rx_sniffer(ports) self.remove_rx_queue(ports) @@ -2813,9 +2881,6 @@ class STLClient(object): link_up = None, led_on = None, flow_ctrl = None, - rxf = None, - ipv4 = None, - dest = None, resolve = True): """ Set port attributes @@ -2825,9 +2890,6 @@ class STLClient(object): link_up - True or False led_on - True or False flow_ctrl - 0: disable all, 1: enable tx side, 2: enable rx side, 3: full enable - rxf - 'hw' for hardware rules matching packets only or 'all' all packets - ipv4 - configure IPv4 address for port(s). for multiple ports should be a list of IPv4 addresses in the same length of the ports array - dest - configure destination address for port(s) in either IPv4 or MAC format. for multiple ports should be a list in the same length of the ports array resolve - if true, in case a destination address is configured as IPv4 try to resolve it :raises: + :exe:'STLError' @@ -2842,7 +2904,6 @@ class STLClient(object): validate_type('link_up', link_up, (bool, type(None))) 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 = {} @@ -2851,34 +2912,10 @@ class STLClient(object): cmn_attr_dict['link_status'] = link_up cmn_attr_dict['led_status'] = led_on cmn_attr_dict['flow_ctrl_mode'] = flow_ctrl - cmn_attr_dict['rx_filter_mode'] = rxf # each port starts with a set of the common attributes attr_dict = [dict(cmn_attr_dict) for _ in ports] - # default value for IPv4 / dest is none for all ports - if ipv4 is None: - ipv4 = [None] * len(ports) - if dest is None: - dest = [None] * len(ports) - - ipv4 = listify(ipv4) - if len(ipv4) != len(ports): - raise STLError("'ipv4' must be a list in the same length of ports - 'ports': {0}, 'ip': {1}".format(ports, ipv4)) - - dest = listify(dest) - if len(dest) != len(ports): - raise STLError("'dest' must be a list in the same length of ports - 'ports': {0}, 'dest': {1}".format(ports, dest)) - - # update each port attribute with ipv4 - for addr, port_attr in zip(ipv4, attr_dict): - port_attr['ipv4'] = addr - - # update each port attribute with dest - for addr, port_attr in zip(dest, attr_dict): - port_attr['dest'] = addr - - self.logger.pre_cmd("Applying attributes on port(s) {0}:".format(ports)) rc = self.__set_port_attr(ports, attr_dict) self.logger.post_cmd(rc) @@ -2886,15 +2923,7 @@ class STLClient(object): if not rc: raise STLError(rc) - - # automatic resolve - if resolve: - # find any port with a dest configured as IPv4 - resolve_ports = [port_id for port_id, port_dest in zip(ports, dest) if is_valid_ipv4(port_dest)] - - if resolve_ports: - self.resolve(ports = resolve_ports) - + @__api_check(True) @@ -2927,13 +2956,14 @@ class STLClient(object): @__api_check(True) - def resolve (self, ports = None, retries = 0): + def resolve (self, ports = None, retries = 0, verbose = True): """ Resolves ports (ARP resolution) :parameters: ports - for which ports to apply a unique sniffer (each port gets a unique file) retires - how many times to retry on each port (intervals of 100 milliseconds) + verbose - log for each request the response :raises: + :exe:'STLError' @@ -2957,8 +2987,9 @@ class STLClient(object): raise STLError(rc) # print the ARP transaction - self.logger.log(rc) - self.logger.log('') + if verbose: + self.logger.log(rc) + self.logger.log('') @@ -3122,7 +3153,7 @@ class STLClient(object): try: rc = f(*args) except STLError as e: - client.logger.log("Action has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold')) + client.logger.log("\nAction has failed with the following error:\n" + format_text(e.brief() + "\n", 'bold')) return RC_ERR(e.brief()) # if got true - print time @@ -3156,7 +3187,8 @@ class STLClient(object): return opts # IP ping - self.ping_ip(opts.source_port, opts.ping_ipv4, opts.pkt_size, opts.count) + # source ports maps to ports as a single port + self.ping_ip(opts.ports[0], opts.ping_ipv4, opts.pkt_size, opts.count) @__console @@ -3691,9 +3723,6 @@ class STLClient(object): parsing_opts.LED_STATUS, parsing_opts.FLOW_CTRL, parsing_opts.SUPPORTED, - parsing_opts.RX_FILTER_MODE, - parsing_opts.IPV4, - parsing_opts.DEST ) opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True) @@ -3706,7 +3735,7 @@ class STLClient(object): opts.flow_ctrl = parsing_opts.FLOW_CTRL_DICT.get(opts.flow_ctrl) # if no attributes - fall back to printing the status - if not list(filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp, opts.rx_filter_mode, opts.ipv4, opts.dest])): + if not list(filter(lambda x:x is not None, [opts.prom, opts.link, opts.led, opts.flow_ctrl, opts.supp])): self.show_stats_line("--ps --port {0}".format(' '.join(str(port) for port in opts.ports))) return @@ -3724,10 +3753,7 @@ class STLClient(object): opts.prom, opts.link, opts.led, - opts.flow_ctrl, - opts.rx_filter_mode, - opts.ipv4, - opts.dest) + opts.flow_ctrl) @@ -3781,6 +3807,46 @@ class STLClient(object): return RC_OK() + @__console + def set_source_addr_line (self, line): + '''Configures source address for port(s)''' + + parser = parsing_opts.gen_parser(self, + "source", + self.set_source_addr_line.__doc__, + parsing_opts.SOURCE_PORT, + parsing_opts.IPV4) + + opts = parser.parse_args(line.split()) + if not opts: + return opts + + # source ports maps to ports as a single port + self.set_source_addr(opts.ports[0], opts.ipv4) + + return RC_OK() + + + @__console + def set_dest_addr_line (self, line): + '''Configures destination address for port(s)''' + + parser = parsing_opts.gen_parser(self, + "dest", + self.set_dest_addr_line.__doc__, + parsing_opts.SOURCE_PORT, + parsing_opts.DEST) + + opts = parser.parse_args(line.split()) + if not opts: + return opts + + # source ports maps to ports as a single port + self.set_dest_addr(opts.ports[0], opts.dest) + + return RC_OK() + + @__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 9309ad0c..5ec1f852 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 @@ -519,7 +519,23 @@ class Port(object): return self.ok() - + + @owned + def set_source_addr (self, addr): + if not self.is_service_mode_on(): + return self.err('port service mode must be enabled for configuring source address. Please enable service mode') + + return self.set_attr(ipv4 = addr) + + + @owned + def set_dest_addr (self, addr): + if not self.is_service_mode_on(): + return self.err('port service mode must be enabled for configuring destination address. Please enable service mode') + + return self.set_attr(dest = addr) + + @owned def set_arp_resolution (self, ipv4, mac): 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 66a17a03..c5f53d68 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 @@ -46,7 +46,6 @@ SUPPORTED = 29 FILE_PATH_NO_CHECK = 30 OUTPUT_FILENAME = 31 -ALL_FILES = 32 LIMIT = 33 PORT_RESTART = 34 @@ -54,7 +53,6 @@ IPV4 = 35 DEST = 36 RETRIES = 37 -RX_FILTER_MODE = 38 SOURCE_PORT = 39 PING_IPV4 = 40 PING_COUNT = 41 @@ -343,24 +341,17 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'dest': 'flow_ctrl', 'choices': FLOW_CTRL_DICT}), - RX_FILTER_MODE: ArgumentPack(['--rxf'], - {'help': 'Set RX filtering mode', - 'dest': 'rx_filter_mode', - 'choices': ['hw', 'all']}), - - IPV4: ArgumentPack(['--ipv4'], {'help': 'IPv4 address(s) for the port(s)', 'dest': 'ipv4', - 'nargs': '+', - 'default': None, + 'required': True, 'type': check_ipv4_addr}), - DEST: ArgumentPack(['--dest'], + DEST: ArgumentPack(['--addr'], {'help': 'Destination address(s) for the port(s) in either IPv4 or MAC format', + 'metavar': 'addr', 'dest': 'dest', - 'nargs': '+', - 'default': None, + 'required' : True, 'type': check_dest_addr}), RETRIES: ArgumentPack(['-r', '--retries'], @@ -384,14 +375,6 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': False, 'action': 'store_true'}), - - 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', @@ -423,8 +406,9 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], SOURCE_PORT: ArgumentPack(['--port', '-p'], - {'dest':'source_port', + {'dest':'ports', 'type': int, + 'metavar': 'PORT', 'help': 'source port for the action', 'required': True}), @@ -652,6 +636,8 @@ class CCmdArgParser(argparse.ArgumentParser): if not self.has_ports_cfg(opts): return opts + opts.ports = listify(opts.ports) + # if all ports are marked or if (getattr(opts, "all_ports", None) == True) or (getattr(opts, "ports", None) == []): if default_ports is None: @@ -664,7 +650,12 @@ class CCmdArgParser(argparse.ArgumentParser): # so maybe we have ports configured invalid_ports = list_difference(opts.ports, self.stateless_client.get_all_ports()) if invalid_ports: - msg = "{0}: port(s) {1} are not valid port IDs".format(self.cmd_name, invalid_ports) + + if len(invalid_ports) > 1: + msg = "{0}: port(s) {1} are not valid port IDs".format(self.cmd_name, invalid_ports) + else: + msg = "{0}: port {1} is not a valid port ID".format(self.cmd_name, invalid_ports[0]) + self.stateless_client.logger.log(format_text(msg, 'bold')) return RC_ERR(msg) diff --git a/src/common/Network/Packet/MacAddress.h b/src/common/Network/Packet/MacAddress.h index 9bd3eae1..924f774e 100755 --- a/src/common/Network/Packet/MacAddress.h +++ b/src/common/Network/Packet/MacAddress.h @@ -47,7 +47,7 @@ public: a5); }; - MacAddress(uint8_t macAddr[ETHER_ADDR_LEN]) + MacAddress(const uint8_t macAddr[ETHER_ADDR_LEN]) { set(macAddr[0], macAddr[1], diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index a01d57a2..03c41431 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -3153,11 +3153,6 @@ void CGlobalTRex::pre_test() { // If we got src MAC for port in global config, take it, otherwise use src MAC from DPDK uint8_t port_macs[m_max_ports][ETHER_ADDR_LEN]; for (int port_id = 0; port_id < m_max_ports; port_id++) { - uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0}; - if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) { - rte_eth_macaddr_get(port_id, - (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src); - } memcpy(port_macs[port_id], CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, ETHER_ADDR_LEN); } @@ -3200,16 +3195,9 @@ void CGlobalTRex::pre_test() { } else { resolve_needed = false; } - if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) { - rte_eth_macaddr_get(port_id, - (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src); - need_grat_arp[port_id] = true; - } else { - // If we got src MAC from config file, do not send gratuitous ARP for it - // (for compatibility with old behaviour) - need_grat_arp[port_id] = false; - } - + + need_grat_arp[port_id] = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() != 0; + pretest.add_ip(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip() , CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan() , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src); @@ -4880,7 +4868,14 @@ bool CPhyEthIF::Create(uint8_t portid) { m_last_tx_pps = 0.0; m_port_attr = g_trex.m_drv->create_port_attr(portid); + /* set src MAC addr */ + uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0}; + if (! memcmp( CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) { + rte_eth_macaddr_get(m_port_id, + (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[m_port_id].u.m_mac.src); + } + /* set src IPv4 */ uint32_t src_ipv4 = CGlobalInfo::m_options.m_ip_cfg[m_port_id].get_ip(); if (src_ipv4) { m_port_attr->set_src_ipv4(src_ipv4); diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 3d541fe5..5c397fcd 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -368,8 +368,10 @@ TrexRpcCmdSetPortAttr::parse_ipv4(const Json::Value &msg, uint8_t port_id, Json: ss << "invalid IPv4 address: '" << ipv4_str << "'"; generate_parse_err(result, ss.str()); } + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + port->set_src_ipv4(ipv4_addr); - get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_src_ipv4(ipv4_addr); return (0); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 7edf1a31..057f6521 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -987,6 +987,19 @@ TrexStatelessPort::get_rx_queue_pkts() { return reply.wait_for_reply(); } + +void +TrexStatelessPort::set_src_ipv4(uint32_t ipv4) { + + getPortAttrObj()->set_src_ipv4(ipv4); + + CManyIPInfo src_addr; + src_addr.insert(COneIPv4Info(ipv4, 0, getPortAttrObj()->get_src_mac(), m_port_id)); + + TrexStatelessRxUpdateSrcAddr *msg = new TrexStatelessRxUpdateSrcAddr(m_port_id, src_addr); + send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg ); +} + Json::Value TrexStatelessPort::rx_features_to_json() { static MsgReply reply; diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 74ab17f1..3ae74f5a 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -399,6 +399,12 @@ public: */ const RXPacketBuffer *get_rx_queue_pkts(); + /** + * sets an IPv4 source address + * + */ + void set_src_ipv4(uint32_t ipv4); + /** * generate a JSON describing the status * of the RX features diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 17acb21e..dc656e67 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -316,3 +316,8 @@ TrexStatelessRxFeaturesToJson::handle(CRxCoreStateless *rx_core) { return true; } +bool +TrexStatelessRxUpdateSrcAddr::handle(CRxCoreStateless *rx_core) { + rx_core->get_rx_port_mngr(m_port_id).update_src_addr(m_src_addr); + return true; +} diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index 79a6bf08..5f00c244 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -27,6 +27,7 @@ limitations under the License. #include "trex_exception.h" #include "trex_stateless_rx_defs.h" #include "os_time.h" +#include "utl_ip.h" class TrexStatelessDpCore; class CRxCoreStateless; @@ -568,6 +569,22 @@ private: }; +class TrexStatelessRxUpdateSrcAddr : public TrexStatelessCpToRxMsgBase { +public: + TrexStatelessRxUpdateSrcAddr(uint8_t port_id, + const CManyIPInfo &src_addr) { + + m_port_id = port_id; + m_src_addr = src_addr; + } + + virtual bool handle(CRxCoreStateless *rx_core); + +private: + uint8_t m_port_id; + CManyIPInfo m_src_addr; +}; + /** * a request from RX core to dump to Json the RX features */ diff --git a/src/stateless/rx/trex_stateless_rx_core.cpp b/src/stateless/rx/trex_stateless_rx_core.cpp index 9898e8b9..31fef68f 100644 --- a/src/stateless/rx/trex_stateless_rx_core.cpp +++ b/src/stateless/rx/trex_stateless_rx_core.cpp @@ -85,12 +85,12 @@ 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_rx_port_mngr[i].create(port_attr, + cfg.m_ports[i], m_rfc2544, &m_err_cntrs, &m_cpu_dp_u, - cfg.m_num_crc_fix_bytes, - port_attr); + cfg.m_num_crc_fix_bytes); } } @@ -189,6 +189,7 @@ void CRxCoreStateless::handle_work_stage() { /* set the next sync time to */ dsec_t sync_time_sec = now_sec() + (1.0 / 1000); + dsec_t tick_time_sec = now_sec() + 1.0; while (m_state == STATE_WORKING) { process_all_pending_pkts(); @@ -197,8 +198,11 @@ void CRxCoreStateless::handle_work_stage() { if ( (now - sync_time_sec) > 0 ) { periodic_check_for_cp_messages(); + } + + if ( (now - tick_time_sec) > 0) { port_manager_tick(); - sync_time_sec = now + (1.0 / 1000); + tick_time_sec = now + 1.0; } rte_pause(); @@ -211,6 +215,8 @@ void CRxCoreStateless::start() { m_monitor.create("STL RX CORE", 1); TrexWatchDog::getInstance().register_monitor(&m_monitor); + recalculate_next_state(); + while (m_state != STATE_QUIT) { switch (m_state) { case STATE_IDLE: @@ -334,7 +340,7 @@ CRxCoreStateless::disable_latency() { recalculate_next_state(); } -const RXPortManager & +RXPortManager & CRxCoreStateless::get_rx_port_mngr(uint8_t port_id) { assert(port_id < m_max_ports); return m_rx_port_mngr[port_id]; diff --git a/src/stateless/rx/trex_stateless_rx_core.h b/src/stateless/rx/trex_stateless_rx_core.h index cd16bb8a..96e511b4 100644 --- a/src/stateless/rx/trex_stateless_rx_core.h +++ b/src/stateless/rx/trex_stateless_rx_core.h @@ -151,7 +151,7 @@ class CRxCoreStateless { void enable_latency(); void disable_latency(); - const RXPortManager &get_rx_port_mngr(uint8_t port_id); + RXPortManager &get_rx_port_mngr(uint8_t port_id); private: void handle_cp_msg(TrexStatelessCpToRxMsgBase *msg); diff --git a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp index af312700..e36f825d 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.cpp +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.cpp @@ -23,6 +23,7 @@ #include "common/captureFile.h" #include "trex_stateless_rx_core.h" #include "common/Network/Packet/Arp.h" +#include "pkt_gen.h" /************************************** * latency RX feature @@ -507,16 +508,16 @@ protected: }; RXServer::RXServer() { - m_port_attr = NULL; m_io = NULL; + m_src_addr = 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(); +RXServer::create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr) { + m_port_id = port_id; + m_io = io; + m_src_addr = src_addr; } @@ -538,7 +539,7 @@ void RXServer::handle_icmp(RXPktParser &parser) { /* maybe not for us... */ - if (parser.m_ipv4->getDestIp() != m_port_attr->get_src_ipv4()) { + if (!m_src_addr->exists(parser.m_ipv4->getDestIp())) { return; } @@ -578,6 +579,7 @@ RXServer::handle_icmp(RXPktParser &parser) { void RXServer::handle_arp(RXPktParser &parser) { + MacAddress src_mac; /* only ethernet format supported */ if (parser.m_arp->getHrdType() != ArpHdr::ARP_HDR_HRD_ETHER) { @@ -595,7 +597,7 @@ RXServer::handle_arp(RXPktParser &parser) { } /* are we the target ? if not - go home */ - if (parser.m_arp->getTip() != m_port_attr->get_src_ipv4()) { + if (!m_src_addr->lookup(parser.m_arp->getTip(), 0, src_mac)) { return; } @@ -612,14 +614,14 @@ RXServer::handle_arp(RXPktParser &parser) { 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->mySource = 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()); + response_parser.m_arp->m_arp_sha = src_mac; + response_parser.m_arp->setSip(parser.m_arp->getTip()); /* dst */ response_parser.m_arp->m_arp_tha = parser.m_arp->m_arp_sha; @@ -654,6 +656,44 @@ RXServer::duplicate_mbuf(const rte_mbuf_t *m) { return clone_mbuf; } +/************************************** + * Gratidious ARP + * + *************************************/ +void +RXGratARP::create(uint8_t port_id, CPortLatencyHWBase *io, CManyIPInfo *src_addr) { + m_io = io; + m_port_id = port_id; + m_src_addr = src_addr; +} + +void +RXGratARP::send_next_grat_arp() { + uint8_t src_mac[ETHER_ADDR_LEN]; + + const COneIPInfo *ip_info = m_src_addr->get_next_loop(); + if (!ip_info) { + return; + } + + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(m_port_id)); + assert(m); + + uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, ip_info->get_grat_arp_len()); + ip_info->get_mac(src_mac); + uint16_t vlan = ip_info->get_vlan(); + + /* for now only IPv4 */ + assert(ip_info->ip_ver() == COneIPInfo::IP4_VER); + uint32_t sip = ((COneIPv4Info *)ip_info)->get_ip(); + + CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, m_port_id); + + m_io->tx(m); + + +} + /************************************** * Port manager * @@ -663,26 +703,37 @@ RXPortManager::RXPortManager() { clear_all_features(); m_io = NULL; m_cpu_dp_u = NULL; + m_port_id = UINT8_MAX; } void -RXPortManager::create(CPortLatencyHWBase *io, +RXPortManager::create(const TRexPortAttr *port_attr, + CPortLatencyHWBase *io, CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs, CCpuUtlDp *cpu_util, - uint8_t crc_bytes_num, - const TRexPortAttr *port_attr) { + uint8_t crc_bytes_num) { + + m_port_id = port_attr->get_port_id(); m_io = io; m_cpu_dp_u = cpu_util; m_num_crc_fix_bytes = crc_bytes_num; + /* if IPv4 is configured - add it to the grat service */ + uint32_t src_ipv4 = port_attr->get_src_ipv4(); + if (src_ipv4) { + m_src_addr.insert(COneIPv4Info(src_ipv4, 0, port_attr->get_src_mac(), m_port_id)); + } + /* init features */ m_latency.create(rfc2544, err_cntrs); - m_server.create(port_attr, io); + m_server.create(m_port_id, io, &m_src_addr); + m_grat_arp.create(m_port_id, io, &m_src_addr); /* by default, server feature is always on */ set_feature(SERVER); + set_feature(GRAT_ARP); } void RXPortManager::handle_pkt(const rte_mbuf_t *m) { @@ -706,7 +757,6 @@ void RXPortManager::handle_pkt(const rte_mbuf_t *m) { } } - int RXPortManager::process_all_pending_pkts(bool flush_rx) { rte_mbuf_t *rx_pkts[64]; @@ -747,8 +797,13 @@ RXPortManager::tick() { if (is_feature_set(RECORDER)) { m_recorder.flush_to_disk(); } + + if (is_feature_set(GRAT_ARP)) { + m_grat_arp.send_next_grat_arp(); + } } + Json::Value RXPortManager::to_json() const { Json::Value output = Json::objectValue; @@ -777,3 +832,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 12b601ea..e72b0ff0 100644 --- a/src/stateless/rx/trex_stateless_rx_port_mngr.h +++ b/src/stateless/rx/trex_stateless_rx_port_mngr.h @@ -264,7 +264,7 @@ class RXServer { public: RXServer(); - void create(const TRexPortAttr *port_attr, CPortLatencyHWBase *io); + void create(uint8_t port_id, CPortLatencyHWBase *io, const CManyIPInfo *src_addr); void handle_pkt(const rte_mbuf_t *m); private: @@ -272,9 +272,36 @@ private: 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; + const CManyIPInfo *m_src_addr; +}; + +/************************************** + * Gratidious ARP + * + *************************************/ +class RXGratARP { +public: + RXGratARP() { + m_io = NULL; + m_port_id = UINT8_MAX; + m_src_addr = NULL; + } + + void create(uint8_t port_id, CPortLatencyHWBase *io, CManyIPInfo *src_addr); + + + /** + * the main 'tick' of the service + * + */ + void send_next_grat_arp(); + +private: + CPortLatencyHWBase *m_io; + CManyIPInfo *m_src_addr; + uint8_t m_port_id; }; /************************ manager ***************************/ @@ -291,22 +318,25 @@ public: LATENCY = 0x1, RECORDER = 0x2, QUEUE = 0x4, - SERVER = 0x8 + SERVER = 0x8, + GRAT_ARP = 0x10, }; RXPortManager(); - void create(CPortLatencyHWBase *io, + void create(const TRexPortAttr *port_attr, + CPortLatencyHWBase *io, CRFC2544Info *rfc2544, CRxCoreErrCntrs *err_cntrs, CCpuUtlDp *cpu_util, - uint8_t crc_bytes_num, - const TRexPortAttr *port_attr); + uint8_t crc_bytes_num); + void clear_stats() { m_latency.reset_stats(); } + void get_latency_stats(rx_per_flow_t *rx_stats, int min, int max, @@ -390,6 +420,15 @@ public: */ void tick(); + /** + * updates the source addresses registered with the port + * + */ + void update_src_addr(const CManyIPInfo &new_src_addr) { + /* deep copy */ + m_src_addr = new_src_addr; + } + bool has_features_set() { return (m_features != NO_FEATURES); } @@ -423,17 +462,19 @@ private: } uint32_t m_features; - + uint8_t m_port_id; RXLatency m_latency; RXPacketRecorder m_recorder; RXQueue m_queue; RXServer m_server; + RXGratARP m_grat_arp; // compensate for the fact that hardware send us packets without Ethernet CRC, and we report with it uint8_t m_num_crc_fix_bytes; CCpuUtlDp *m_cpu_dp_u; CPortLatencyHWBase *m_io; + CManyIPInfo m_src_addr; }; diff --git a/src/trex_port_attr.cpp b/src/trex_port_attr.cpp index 0ecbc2c4..2a68fcb9 100644 --- a/src/trex_port_attr.cpp +++ b/src/trex_port_attr.cpp @@ -99,7 +99,14 @@ TRexPortAttr::get_src_mac() const { return CGlobalInfo::m_options.get_src_mac_addr(m_port_id); } - +void +TRexPortAttr::set_src_ipv4(uint32_t addr) { + m_src_ipv4 = addr; + + /* when IP source changes - consider this as link down */ + m_dest.on_link_down(); +} + std::string TRexPortAttr::get_rx_filter_mode() const { switch (m_rx_filter_mode) { diff --git a/src/trex_port_attr.h b/src/trex_port_attr.h index c69314fc..437fa8c7 100755 --- a/src/trex_port_attr.h +++ b/src/trex_port_attr.h @@ -151,11 +151,7 @@ public: virtual int set_led(bool on) = 0; virtual int set_rx_filter_mode(rx_filter_mode_e mode) = 0; - void set_src_ipv4(uint32_t addr) { - m_src_ipv4 = addr; - /* when IP source changes - consider this as link down */ - m_dest.on_link_down(); - } + void set_src_ipv4(uint32_t addr); /* DUMPS */ virtual void dump_link(FILE *fd) = 0; diff --git a/src/utl_ip.cpp b/src/utl_ip.cpp index e7bb6fab..d29ab60a 100644 --- a/src/utl_ip.cpp +++ b/src/utl_ip.cpp @@ -71,13 +71,14 @@ void COneIPv6Info::fill_grat_arp_buf(uint8_t *p) { } const COneIPInfo *CManyIPInfo::get_next() { - COneIPInfo *ret; - + const COneIPInfo *ret; + if (!m_iter_initiated) { m_ipv4_iter = m_ipv4_resolve.begin(); m_iter_initiated = true; } + if (m_ipv4_iter == m_ipv4_resolve.end()) { m_ipv4_iter = m_ipv4_resolve.begin(); return NULL; @@ -99,13 +100,13 @@ void CManyIPInfo::dump(FILE *fd) { } } -void CManyIPInfo::insert(COneIPv4Info &ip_info) { +void CManyIPInfo::insert(const COneIPv4Info &ip_info) { CIpVlan ip_vlan(ip_info.get_ip(), ip_info.get_vlan()); m_ipv4_resolve.insert(std::make_pair(ip_vlan, ip_info)); } -bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) { +bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const { ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan)); if (it != m_ipv4_resolve.end()) { uint8_t mac[ETHER_ADDR_LEN]; @@ -117,6 +118,17 @@ bool CManyIPInfo::lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) { } } +bool CManyIPInfo::exists(uint32_t ip, uint16_t vlan) const { + ip_vlan_to_many_ip_iter_t it = m_ipv4_resolve.find(CIpVlan(ip, vlan)); + return (it != m_ipv4_resolve.end()); +} + +void CManyIPInfo::clear() { + m_ipv4_resolve.clear(); + m_ipv6_resolve.clear(); + m_iter_initiated = false; +} + const COneIPInfo *CManyIPInfo::get_first() { if (m_ipv4_resolve.size() == 0) { return NULL; diff --git a/src/utl_ip.h b/src/utl_ip.h index 27bb6c81..bab92c0f 100644 --- a/src/utl_ip.h +++ b/src/utl_ip.h @@ -156,7 +156,7 @@ class COneIPv4Info : public COneIPInfo { m_ip = ip; } ~COneIPv4Info() {}; - uint32_t get_ip() {return m_ip;} + uint32_t get_ip() const {return m_ip;} virtual uint8_t ip_ver() const {return IP4_VER;} virtual uint32_t get_arp_req_len() const {return 60;} virtual uint32_t get_grat_arp_len() const {return 60;} @@ -225,7 +225,7 @@ inline bool operator== (const COneIPv6Info& lhs, const COneIPv6Info& rhs) { inline bool operator!= (const COneIPv6Info& lhs, const COneIPv6Info& rhs){ return !(lhs == rhs); } typedef std::map ip_vlan_to_many_ip_t; -typedef std::map::iterator ip_vlan_to_many_ip_iter_t; +typedef std::map::const_iterator ip_vlan_to_many_ip_iter_t; typedef std::map, COneIPv6Info> ipv6_vlan_to_many_ipv6_t; class CManyIPInfo { @@ -233,18 +233,37 @@ class CManyIPInfo { CManyIPInfo () { m_iter_initiated = false; } - void insert(COneIPv4Info &ip_info); - bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac); + void insert(const COneIPv4Info &ip_info); + bool lookup(uint32_t ip, uint16_t vlan, MacAddress &ret_mac) const; + bool exists(uint32_t ip, uint16_t vlan = 0) const; + void clear(); + void dump(FILE *fd); uint32_t size() { return m_ipv4_resolve.size() + m_ipv6_resolve.size();} const COneIPInfo *get_first(); const COneIPInfo *get_next(); + const COneIPInfo *get_next_loop() { + const COneIPInfo *ip_info = get_next(); + return (ip_info ? ip_info : get_next()); + } + + CManyIPInfo& operator = (const CManyIPInfo &rhs) { + m_ipv4_resolve = rhs.m_ipv4_resolve; + m_ipv6_resolve = rhs.m_ipv6_resolve; + + m_iter_initiated = false; + return (*this); + } + private: - ip_vlan_to_many_ip_t m_ipv4_resolve; + ip_vlan_to_many_ip_t m_ipv4_resolve; + ipv6_vlan_to_many_ipv6_t m_ipv6_resolve; + ip_vlan_to_many_ip_iter_t m_ipv4_iter; - ipv6_vlan_to_many_ipv6_t m_ipv6_resolve; + bool m_iter_initiated; }; + #endif -- cgit 1.2.3-korg