grat ARP 96/4296/1
authorimarom <[email protected]>
Mon, 12 Dec 2016 17:26:24 +0000 (19:26 +0200)
committerimarom <[email protected]>
Mon, 12 Dec 2016 17:26:24 +0000 (19:26 +0200)
Signed-off-by: imarom <[email protected]>
19 files changed:
scripts/automation/trex_control_plane/stl/console/trex_console.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
src/common/Network/Packet/MacAddress.h
src/main_dpdk.cpp
src/rpc-server/commands/trex_rpc_cmd_general.cpp
src/stateless/cp/trex_stateless_port.cpp
src/stateless/cp/trex_stateless_port.h
src/stateless/messaging/trex_stateless_messaging.cpp
src/stateless/messaging/trex_stateless_messaging.h
src/stateless/rx/trex_stateless_rx_core.cpp
src/stateless/rx/trex_stateless_rx_core.h
src/stateless/rx/trex_stateless_rx_port_mngr.cpp
src/stateless/rx/trex_stateless_rx_port_mngr.h
src/trex_port_attr.cpp
src/trex_port_attr.h
src/utl_ip.cpp
src/utl_ip.h

index eb8a044..1a97ad0 100755 (executable)
@@ -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'''
index fe691fb..80daadd 100755 (executable)
@@ -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'''
index 9309ad0..5ec1f85 100644 (file)
@@ -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):
 
index 66a17a0..c5f53d6 100755 (executable)
@@ -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)
 
index 9bd3eae..924f774 100755 (executable)
@@ -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],
index a01d57a..03c4143 100644 (file)
@@ -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);
index 3d541fe..5c397fc 100644 (file)
@@ -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);
 }
 
index 7edf1a3..057f652 100644 (file)
@@ -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<Json::Value> reply;
index 74ab17f..3ae74f5 100644 (file)
@@ -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 
index 17acb21..dc656e6 100644 (file)
@@ -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;
+}
index 79a6bf0..5f00c24 100644 (file)
@@ -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
  */
index 9898e8b..31fef68 100644 (file)
@@ -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];
index cd16bb8..96e511b 100644 (file)
@@ -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);
index af31270..e36f825 100644 (file)
@@ -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;
 }
 
+
index 12b601e..e72b0ff 100644 (file)
@@ -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;
 };
 
 
index 0ecbc2c..2a68fcb 100644 (file)
@@ -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) {
index c69314f..437fa8c 100755 (executable)
@@ -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;
index e7bb6fa..d29ab60 100644 (file)
@@ -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;
index 27bb6c8..bab92c0 100644 (file)
@@ -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<CIpVlan, COneIPv4Info> ip_vlan_to_many_ip_t;
-typedef std::map<CIpVlan, COneIPv4Info>::iterator ip_vlan_to_many_ip_iter_t;
+typedef std::map<CIpVlan, COneIPv4Info>::const_iterator ip_vlan_to_many_ip_iter_t;
 typedef std::map<std::pair<uint16_t[8], uint16_t>, 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