Major refactor - L2 / L3 modes for ports 01/4301/1
authorimarom <[email protected]>
Tue, 13 Dec 2016 16:15:22 +0000 (18:15 +0200)
committerimarom <[email protected]>
Tue, 13 Dec 2016 16:15:22 +0000 (18:15 +0200)
Signed-off-by: imarom <[email protected]>
21 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/trex_stl_rx_features.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
src/bp_sim.h
src/main_dpdk.cpp
src/rpc-server/commands/trex_rpc_cmd_general.cpp
src/rpc-server/commands/trex_rpc_cmds.h
src/rpc-server/trex_rpc_cmds_table.cpp
src/stateful_rx_core.h
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.h

index 1a97ad0..627761f 100755 (executable)
@@ -330,23 +330,21 @@ class TRexConsole(TRexGeneralCmd):
         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")
-        
+    def do_l2 (self, line):
+        '''Configures a port in L2 mode'''
+        self.stateless_client.set_l2_mode_line(line)
         
+    def help_l2 (self):
+        self.do_l2("-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")
-        
-        
+    def do_l3 (self, line):
+        '''Configures a port in L3 mode'''
+        self.stateless_client.set_l3_mode_line(line)
+
+    def help_l3 (self):
+        self.do_l3("-h")
+
         
     @verify_connected
     def do_set_rx_sniffer (self, line):
index 80daadd..ee5db1f 100755 (executable)
@@ -1843,15 +1843,14 @@ class STLClient(object):
             raise STLError(rc)
         
 
-            
     @__api_check(True)
-    def set_source_addr (self, port, addr):
+    def set_l2_mode (self, port, dst_mac):
         """
-            Configures a port with a source address
+            Sets the port mode to L2
 
             :parameters:
-                 port - the port to set the source address
-                 addr     - source address. currently only IPv4 is supported
+                 port      - the port to set the source address
+                 dst_mac   - destination MAC
             :raises:
                 + :exc:`STLError`
         """
@@ -1859,33 +1858,27 @@ class STLClient(object):
         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 is_valid_mac(dst_mac):
+            raise STLError("dest_mac is not a valid MAC address: '{0}'".format(dst_mac))
+            
+        self.logger.pre_cmd("Setting port {0} in L2 mode: ".format(port))
+        rc = self.ports[port].set_l2_mode(dst_mac)
+        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):
+    def set_l3_mode (self, port, src_ipv4, dst_ipv4):
         """
-            Configures a port with a destination address
+            Sets the port mode to L3
 
             :parameters:
-                 port     - the port to set the destination address
-                 addr     - destination address. can be either MAC or IPv4
+                 port      - the port to set the source address
+                 src_ipv4  - IPv4 source address for the port
+                 dst_ipv4  - IPv4 destination address
             :raises:
                 + :exc:`STLError`
         """
@@ -1893,24 +1886,29 @@ class STLClient(object):
         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 is_valid_ipv4(src_ipv4):
+            raise STLError("src_ipv4 is not a valid IPv4 address: '{0}'".format(src_ipv4))
+            
+        if not is_valid_ipv4(dst_ipv4):
+            raise STLError("dst_ipv4 is not a valid IPv4 address: '{0}'".format(dst_ipv4))
+            
+        self.logger.pre_cmd("Setting port {0} in L3 mode: ".format(port))
+        rc = self.ports[port].set_l3_mode(src_ipv4, dst_ipv4)
+        self.logger.post_cmd(rc)
         
         if not rc:
             raise STLError(rc)
-        
-        # resolve the address
-        return self.resolve(ports = port, verbose = False)
-        
-        
+    
+        # try to resolve
+        with self.logger.supress(level = LoggerApi.VERBOSE_REGULAR_SYNC):
+            self.logger.pre_cmd("ARP resolving address '{0}': ".format(dst_ipv4))
+            rc = self.ports[port].arp_resolve(0)
+            self.logger.post_cmd(rc)
+            if not rc:
+                raise STLError(rc)
+            
+
     @__api_check(True)
     def ping_ip (self, src_port, dst_ipv4, pkt_size = 64, count = 5):
         """
@@ -3177,7 +3175,7 @@ class STLClient(object):
         parser = parsing_opts.gen_parser(self,
                                          "ping",
                                          self.ping_line.__doc__,
-                                         parsing_opts.SOURCE_PORT,
+                                         parsing_opts.SINGLE_PORT,
                                          parsing_opts.PING_IPV4,
                                          parsing_opts.PKT_SIZE,
                                          parsing_opts.PING_COUNT)
@@ -3808,41 +3806,46 @@ class STLClient(object):
         
     
     @__console
-    def set_source_addr_line (self, line):
-        '''Configures source address for port(s)'''
+    def set_l2_mode_line (self, line):
+        '''Configures a port in L2 mode'''
 
         parser = parsing_opts.gen_parser(self,
-                                         "source",
-                                         self.set_source_addr_line.__doc__,
-                                         parsing_opts.SOURCE_PORT,
-                                         parsing_opts.IPV4)
+                                         "port",
+                                         self.set_l2_mode_line.__doc__,
+                                         parsing_opts.SINGLE_PORT,
+                                         parsing_opts.DST_MAC,
+                                         )
 
         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)
+        self.set_l2_mode(opts.ports[0], dst_mac = opts.dst_mac)
 
         return RC_OK()
         
         
     @__console
-    def set_dest_addr_line (self, line):
-        '''Configures destination address for port(s)'''
+    def set_l3_mode_line (self, line):
+        '''Configures a port in L3 mode'''
 
         parser = parsing_opts.gen_parser(self,
-                                         "dest",
-                                         self.set_dest_addr_line.__doc__,
-                                         parsing_opts.SOURCE_PORT,
-                                         parsing_opts.DEST)
+                                         "port",
+                                         self.set_l3_mode_line.__doc__,
+                                         parsing_opts.SINGLE_PORT,
+                                         parsing_opts.SRC_IPV4,
+                                         parsing_opts.DST_IPV4,
+                                         )
 
         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)
+        self.set_l3_mode(opts.ports[0], src_ipv4 = opts.src_ipv4, dst_ipv4 = opts.dst_ipv4)
 
         return RC_OK()
         
index 5ec1f85..e44fe80 100644 (file)
@@ -519,39 +519,40 @@ class Port(object):
 
         return self.ok()
      
-    
     @owned
-    def set_source_addr (self, addr):
+    def set_l2_mode (self, dst_mac):
         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.err('port service mode must be enabled for configuring L2 mode. Please enable service mode')
         
-        return self.set_attr(ipv4 = addr)
-            
+        params = {"handler":        self.handler,
+                  "port_id":        self.port_id,
+                  "dst_mac":        dst_mac}
 
-    @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)
+        rc = self.transmit("set_l2", params)
+        if rc.bad():
+            return self.err(rc.err())
+
+        return self.sync()
         
         
     @owned
-    def set_arp_resolution (self, ipv4, mac):
-
+    def set_l3_mode (self, src_addr, dest_addr, resolved_mac = None):
+        if not self.is_service_mode_on():
+            return self.err('port service mode must be enabled for configuring L3 mode. Please enable service mode')
+        
         params = {"handler":        self.handler,
                   "port_id":        self.port_id,
-                  "ipv4":           ipv4,
-                  "mac":            mac}
+                  "src_addr":       src_addr,
+                  "dst_addr":       dest_addr}
 
-        rc = self.transmit("set_arp_resolution", params)
+        if resolved_mac:
+            params["resolved_mac"] = resolved_mac
+            
+        rc = self.transmit("set_l3", params)
         if rc.bad():
             return self.err(rc.err())
 
-        # instead of updating manualy - let's sync with the server
         return self.sync()
-        
-  
 
 
     @owned
@@ -700,15 +701,6 @@ class Port(object):
         if kwargs.get('rx_filter_mode') is not None:
             json_attr['rx_filter_mode'] = {'mode': kwargs.get('rx_filter_mode')}
 
-        if kwargs.get('ipv4') is not None:
-            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')}
-            
 
         params = {"handler": self.handler,
                   "port_id": self.port_id,
@@ -879,7 +871,7 @@ class Port(object):
         info['src_ipv4']  = attr['src_ipv4']
         
         if info['src_ipv4'] is None:
-            info['src_ipv4'] = 'Not Configured'
+            info['src_ipv4'] = '-'
 
         # dest
         dest = attr['dest']
@@ -908,6 +900,14 @@ class Port(object):
         queue = rx_info['queue']
         info['rx_queue'] = '[{0} / {1}]'.format(queue['count'], queue['size']) if queue['is_active'] else 'off'
         
+        # Grat ARP
+        grat_arp = rx_info['grat_arp']
+        if grat_arp['is_active']:
+            info['grat_arp'] = grat_arp['interval_sec']
+        else:
+            info['grat_arp'] = "off"
+
+
         return info
 
 
@@ -991,6 +991,7 @@ class Port(object):
                 "RX Filter Mode": info['rx_filter_mode'],
                 "RX Queueing": info['rx_queue'],
                 "RX sniffer": info['rx_sniffer'],
+                "Grat ARP": info['grat_arp'],
 
                 }
 
index e0fc172..ec83de5 100644 (file)
@@ -164,7 +164,8 @@ class ARPResolver(Resolver):
             return None
 
         
-        rc = self.port.set_arp_resolution(arp.psrc, arp.hwsrc)
+        # update the port with L3 full configuration
+        rc = self.port.set_l3_mode(self.src['ipv4'], self.dst['ipv4'], arp.hwsrc)
         if not rc:
             return rc
             
index 6a59126..c08a0af 100644 (file)
@@ -682,6 +682,7 @@ class CTRexInfoGenerator(object):
                                         ("RX Filter Mode", []),
                                         ("RX Queueing", []),
                                         ("RX sniffer", []),
+                                        ("Grat ARP", []),
                                         ]
                                        )
 
index c5f53d6..0a7b510 100755 (executable)
@@ -49,17 +49,20 @@ OUTPUT_FILENAME = 31
 LIMIT = 33
 PORT_RESTART   = 34
 
-IPV4 = 35
-DEST = 36
 RETRIES = 37
 
-SOURCE_PORT = 39
+SINGLE_PORT = 38
+DST_MAC = 39
+
 PING_IPV4 = 40
 PING_COUNT = 41
 PKT_SIZE = 42
 
 SERVICE_OFF = 43
 
+SRC_IPV4 = 44
+DST_IPV4 = 45
+
 GLOBAL_STATS = 50
 PORT_STATS = 51
 PORT_STATUS = 52
@@ -250,9 +253,9 @@ def check_pkt_size (pkt_size):
     
     return pkt_size
     
-def check_dest_addr (addr):
-    if not (is_valid_ipv4(addr) or is_valid_mac(addr)):
-        raise argparse.ArgumentTypeError("not a valid IPv4 or MAC address: '{0}'".format(addr))
+def check_mac_addr (addr):
+    if not is_valid_mac(addr):
+        raise argparse.ArgumentTypeError("not a valid MAC address: '{0}'".format(addr))
         
     return addr
 
@@ -341,18 +344,24 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                     'dest': 'flow_ctrl',
                                     'choices': FLOW_CTRL_DICT}),
 
-              IPV4: ArgumentPack(['--ipv4'],
-                                 {'help': 'IPv4 address(s) for the port(s)',
-                                  'dest': 'ipv4',
-                                  'required': True,
-                                  'type': check_ipv4_addr}),
-
-              DEST: ArgumentPack(['--addr'],
-                                 {'help': 'Destination address(s) for the port(s) in either IPv4 or MAC format',
-                                  'metavar': 'addr',
-                                  'dest': 'dest',
-                                  'required' : True,
-                                  'type': check_dest_addr}),
+              SRC_IPV4: ArgumentPack(['--src'],
+                                     {'help': 'Configure source IPv4 address',
+                                      'dest': 'src_ipv4',
+                                      'required': True,
+                                      'type': check_ipv4_addr}),
+              
+              DST_IPV4: ArgumentPack(['--dst'],
+                                     {'help': 'Configure destination IPv4 address',
+                                      'dest': 'dst_ipv4',
+                                      'required': True,
+                                      'type': check_ipv4_addr}),
+              
+
+              DST_MAC: ArgumentPack(['--dst'],
+                                    {'help': 'Configure destination MAC address',
+                                     'dest': 'dst_mac',
+                                     'required': True,
+                                     'type': check_mac_addr}),
               
               RETRIES: ArgumentPack(['-r', '--retries'],
                                     {'help': 'retries count [default is zero]',
@@ -405,7 +414,7 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                          'default': []}),
 
               
-              SOURCE_PORT: ArgumentPack(['--port', '-p'],
+              SINGLE_PORT: ArgumentPack(['--port', '-p'],
                                         {'dest':'ports',
                                          'type': int,
                                          'metavar': 'PORT',
index 454f5f1..00699cd 100755 (executable)
@@ -668,6 +668,7 @@ class CPerPortIPCfg {
     uint16_t m_vlan;
 };
 
+
 class CParserOption {
 
 public:
@@ -4239,6 +4240,32 @@ inline  pkt_dir_t CGenNode::cur_interface_dir(){
     }
 }
 
+class CRXCoreIgnoreStat {
+    friend class CCPortLatency;
+    friend class CLatencyManager;
+    friend class RXGratARP;
+ public:
+    inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) const {
+        CRXCoreIgnoreStat t_out;
+        t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp;
+        t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic;
+        t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes;
+        return t_out;
+    }
+    uint64_t get_tx_bytes() {return m_tot_bytes;}
+    uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;}
+    uint64_t get_tx_arp() {return m_tx_arp;}
+    uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;}
+    void clear() {
+        m_tx_arp = 0;
+        m_tx_ipv6_n_solic = 0;
+        m_tot_bytes = 0;
+    }
 
+ private:
+    uint64_t m_tx_arp;
+    uint64_t m_tx_ipv6_n_solic;
+    uint64_t m_tot_bytes;
+};
 
 #endif
index 03c4143..e26aaa2 100644 (file)
@@ -3092,6 +3092,8 @@ public:
     void dump_config(FILE *fd);
     void dump_links_status(FILE *fd);
 
+    bool lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id);
+    
 public:
     port_cfg_t  m_port_cfg;
     uint32_t    m_max_ports;    /* active number of ports supported options are  2,4,8,10,12  */
@@ -3910,6 +3912,16 @@ void CGlobalTRex::dump_links_status(FILE *fd){
     }
 }
 
+bool CGlobalTRex::lookup_port_by_mac(const uint8_t *mac, uint8_t &port_id) {
+    for (int i = 0; i < m_max_ports; i++) {
+        if (memcmp(m_ports[i].get_port_attr()->get_src_mac(), mac, 6) == 0) {
+            port_id = i;
+            return true;
+        }
+    }
+    
+    return false;
+}
 
 void CGlobalTRex::dump_post_test_stats(FILE *fd){
     uint64_t pkt_out=0;
@@ -4848,7 +4860,13 @@ static CGlobalTRex g_trex;
 void CPhyEthIF::update_counters() {
     get_ex_drv()->get_extended_stats(this, &m_stats);
     CRXCoreIgnoreStat ign_stats;
-    g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true);
+    
+    if (get_is_stateless()) {
+        g_trex.m_rx_sl.get_ignore_stats(m_port_id, ign_stats, true);
+    } else {
+        g_trex.m_mg.get_ignore_stats(m_port_id, ign_stats, true);
+    }
+    
     m_stats.obytes -= ign_stats.get_tx_bytes();
     m_stats.opackets -= ign_stats.get_tx_pkts();
     m_ignore_stats.opackets += ign_stats.get_tx_pkts();
@@ -7256,6 +7274,11 @@ int DpdkTRexPortAttr::set_rx_filter_mode(rx_filter_mode_e rx_filter_mode) {
     return (0);
 }
 
+bool DpdkTRexPortAttr::is_loopback() const {
+    uint8_t port_id;
+    return g_trex.lookup_port_by_mac(m_dest.get_dest_mac(), port_id);
+}
+
 /**
  * marks the control plane for a total server shutdown
  *
@@ -7264,3 +7287,4 @@ int DpdkTRexPortAttr::set_rx_filter_mode(rx_filter_mode_e rx_filter_mode) {
 void TrexDpdkPlatformApi::mark_for_shutdown() const {
     g_trex.mark_for_shutdown(CGlobalTRex::SHUTDOWN_RPC_REQ);
 }
+
index 5c397fc..c8b4841 100644 (file)
@@ -357,53 +357,6 @@ TrexRpcCmdSetPortAttr::parse_rx_filter_mode(const Json::Value &msg, uint8_t port
     return get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_rx_filter_mode(filter_mode);
 }
 
-int
-TrexRpcCmdSetPortAttr::parse_ipv4(const Json::Value &msg, uint8_t port_id, Json::Value &result) {
-    
-    const std::string ipv4_str = parse_string(msg, "addr", result);
-    
-    uint32_t ipv4_addr;
-    if (!utl_ipv4_to_uint32(ipv4_str.c_str(), ipv4_addr)) {
-        std::stringstream ss;
-        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);
-            
-    return (0);
-}
-
-int
-TrexRpcCmdSetPortAttr::parse_dest(const Json::Value &msg, uint8_t port_id, Json::Value &result) {
-    
-    /* can be either IPv4 or MAC */
-    const std::string addr = parse_string(msg, "addr", result);
-    
-    TRexPortAttr *port_attr = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id);
-    
-    /* try IPv4 */
-    uint32_t ipv4_addr;
-    uint8_t  mac[6];
-    
-    if (utl_ipv4_to_uint32(addr.c_str(), ipv4_addr)) {
-        port_attr->get_dest().set_dest(ipv4_addr);
-        
-    } else if (utl_str_to_macaddr(addr, mac)) {
-        port_attr->get_dest().set_dest(mac);
-        
-    } else {
-        std::stringstream ss;
-        ss << "'dest' is not an IPv4 address or a MAC address: '" << addr << "'";
-        generate_parse_err(result, ss.str());
-    }
-            
-    
-    return (0);
-}
-
-
 /**
  * set port commands
  *
@@ -451,16 +404,6 @@ TrexRpcCmdSetPortAttr::_run(const Json::Value &params, Json::Value &result) {
             ret = parse_rx_filter_mode(rx, port_id, result);
         }
 
-        else if (name == "ipv4") {
-            const Json::Value &ipv4 = parse_object(attr, name, result);
-            ret = parse_ipv4(ipv4, port_id, result);
-        }
-
-        else if (name == "dest") {
-            const Json::Value &dest = parse_object(attr, name, result);
-            ret = parse_dest(dest, port_id, result);
-        }
-
         /* unknown attribute */
         else {
             generate_execute_err(result, "unknown attribute type: '" + name + "'");
@@ -836,31 +779,78 @@ TrexRpcCmdGetRxQueuePkts::_run(const Json::Value &params, Json::Value &result) {
     return (TREX_RPC_CMD_OK);
 }
 
+
+/**
+ * configures a port in L2 mode
+ * 
+ */
 trex_rpc_cmd_rc_e
-TrexRpcCmdSetARPRes::_run(const Json::Value &params, Json::Value &result) {
+TrexRpcCmdSetL2::_run(const Json::Value &params, Json::Value &result) {
     uint8_t port_id = parse_port(params, result);
 
     TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
     
-    const std::string ipv4_str = parse_string(params, "ipv4", result);
-    const std::string mac_str  = parse_string(params, "mac", result);
+    const std::string dst_mac_str  = parse_string(params, "dst_mac", result);
+    uint8_t dst_mac[6];
+    if (!utl_str_to_macaddr(dst_mac_str, dst_mac)) {
+        std::stringstream ss;
+        ss << "'invalid MAC address: '" << dst_mac_str << "'";
+        generate_parse_err(result, ss.str());
+    }
+    
+    port->set_l2_mode(dst_mac);
+    
+    return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * configures a port in L3 mode
+ * 
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdSetL3::_run(const Json::Value &params, Json::Value &result) {
+    uint8_t port_id = parse_port(params, result);
+
+    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
+    const std::string src_ipv4_str  = parse_string(params, "src_addr", result);
+    const std::string dst_ipv4_str  = parse_string(params, "dst_addr", result);
     
-    uint32_t ipv4_addr;
-    if (!utl_ipv4_to_uint32(ipv4_str.c_str(), ipv4_addr)) {
+    uint32_t src_ipv4;
+    if (!utl_ipv4_to_uint32(src_ipv4_str.c_str(), src_ipv4)) {
         std::stringstream ss;
-        ss << "invalid IPv4 address: '" << ipv4_str << "'";
+        ss << "invalid source IPv4 address: '" << src_ipv4_str << "'";
         generate_parse_err(result, ss.str());
     }
  
-    uint8_t mac[6];
-    if (!utl_str_to_macaddr(mac_str, mac)) {
+    uint32_t dst_ipv4;
+    if (!utl_ipv4_to_uint32(dst_ipv4_str.c_str(), dst_ipv4)) {
         std::stringstream ss;
-        ss << "'invalid MAC address: '" << mac_str << "'";
+        ss << "invalid destination IPv4 address: '" << dst_ipv4_str << "'";
         generate_parse_err(result, ss.str());
-    }   
+    }
+     
+   
     
-    port->getPortAttrObj()->get_dest().set_dest(ipv4_addr, mac);
+    /* did we get a resolved MAC as well ? */
+    if (params["resolved_mac"] != Json::Value::null) {
+        const std::string resolved_mac  = parse_string(params, "resolved_mac", result);
+        
+        uint8_t mac[6];
+        if (!utl_str_to_macaddr(resolved_mac, mac)) {
+            std::stringstream ss;
+            ss << "'invalid MAC address: '" << resolved_mac << "'";
+            generate_parse_err(result, ss.str());
+        } 
     
-    return (TREX_RPC_CMD_OK);
+        port->set_l3_mode(src_ipv4, dst_ipv4, mac);
+        
+    } else {
+        
+        port->set_l3_mode(src_ipv4, dst_ipv4);
+    }
+    
+    return (TREX_RPC_CMD_OK);    
     
 }
index 2b2178e..6639be7 100644 (file)
@@ -96,8 +96,6 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortXStatsNames,  "get_port_xstats_names",  1,
 TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdSetPortAttr, "set_port_attr", 2, true,  APIClass::API_CLASS_TYPE_CORE,
                              
     int parse_rx_filter_mode(const Json::Value &msg, uint8_t port_id, Json::Value &result);
-    int parse_ipv4(const Json::Value &msg, uint8_t port_id, Json::Value &result);
-    int parse_dest(const Json::Value &msg, uint8_t port_id, Json::Value &result);
 );
 
 
@@ -159,8 +157,9 @@ TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdSetRxFeature, "set_rx_feature", 3, false,
 
 );
 
+TREX_RPC_CMD_DEFINE(TrexRpcCmdSetL2, "set_l2", 2, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdSetL3, "set_l3", 3, false, APIClass::API_CLASS_TYPE_CORE);
 TREX_RPC_CMD_DEFINE(TrexRpcCmdGetRxQueuePkts, "get_rx_queue_pkts", 2, false, APIClass::API_CLASS_TYPE_CORE);
-TREX_RPC_CMD_DEFINE(TrexRpcCmdSetARPRes, "set_arp_resolution", 2, false, APIClass::API_CLASS_TYPE_CORE);
 
 #endif /* __TREX_RPC_CMD_H__ */
 
index 919be1f..94a3e1b 100644 (file)
@@ -75,7 +75,8 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
     register_command(new TrexRpcCmdSetRxFeature());
     register_command(new TrexRpcCmdGetRxQueuePkts());
     
-    register_command(new TrexRpcCmdSetARPRes());
+    register_command(new TrexRpcCmdSetL2());
+    register_command(new TrexRpcCmdSetL3());
 }
 
 
index 2df406d..8744a58 100644 (file)
@@ -32,33 +32,6 @@ limitations under the License.
 
 class TrexWatchDog;
 
-class CRXCoreIgnoreStat {
-    friend class CCPortLatency;
-    friend class CLatencyManager;
- public:
-    inline CRXCoreIgnoreStat operator- (const CRXCoreIgnoreStat &t_in) {
-        CRXCoreIgnoreStat t_out;
-        t_out.m_tx_arp = this->m_tx_arp - t_in.m_tx_arp;
-        t_out.m_tx_ipv6_n_solic = this->m_tx_ipv6_n_solic - t_in.m_tx_ipv6_n_solic;
-        t_out.m_tot_bytes = this->m_tot_bytes - t_in.m_tot_bytes;
-        return t_out;
-    }
-    uint64_t get_tx_bytes() {return m_tot_bytes;}
-    uint64_t get_tx_pkts() {return m_tx_arp + m_tx_ipv6_n_solic;}
-    uint64_t get_tx_arp() {return m_tx_arp;}
-    uint64_t get_tx_n_solic() {return m_tx_ipv6_n_solic;}
-    void clear() {
-        m_tx_arp = 0;
-        m_tx_ipv6_n_solic = 0;
-        m_tot_bytes = 0;
-    }
-
- private:
-    uint64_t m_tx_arp;
-    uint64_t m_tx_ipv6_n_solic;
-    uint64_t m_tot_bytes;
-};
-
 class CLatencyPktInfo {
 public:
     void Create(class CLatencyPktMode *m_l_pkt_info);
index 057f652..62805db 100644 (file)
@@ -988,18 +988,67 @@ TrexStatelessPort::get_rx_queue_pkts() {
 }
 
 
+/**
+ * configures port in L2 mode
+ * 
+ */
+void
+TrexStatelessPort::set_l2_mode(const uint8_t *dest_mac) {
+    
+    /* no IPv4 src */
+    getPortAttrObj()->set_src_ipv4(0);
+    
+    /* set destination as MAC */
+    getPortAttrObj()->get_dest().set_dest(dest_mac);
+    
+    TrexStatelessRxSetL2Mode *msg = new TrexStatelessRxSetL2Mode(m_port_id);
+    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
+/**
+ * configures port in L3 mode - unresolved
+ */
+void
+TrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4) {
+    
+    /* set src IPv4 */
+    getPortAttrObj()->set_src_ipv4(src_ipv4);
+    
+    /* set dest IPv4 */
+    getPortAttrObj()->get_dest().set_dest(dest_ipv4);
+    
+    /* send RX core the relevant info */
+    CManyIPInfo ip_info;
+    ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_src_mac()));
+    
+    TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, false);
+    send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
+}
+
+/**
+ * configures port in L3 mode - resolved
+ * 
+ */
 void
-TrexStatelessPort::set_src_ipv4(uint32_t ipv4) {
+TrexStatelessPort::set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4, const uint8_t *resolved_mac) {
     
-    getPortAttrObj()->set_src_ipv4(ipv4);
+    /* set src IPv4 */
+    getPortAttrObj()->set_src_ipv4(src_ipv4);
     
-    CManyIPInfo src_addr;
-    src_addr.insert(COneIPv4Info(ipv4, 0, getPortAttrObj()->get_src_mac(), m_port_id));
+    /* set dest IPv4 + resolved MAC */
+    getPortAttrObj()->get_dest().set_dest(dest_ipv4, resolved_mac);
     
-    TrexStatelessRxUpdateSrcAddr *msg = new TrexStatelessRxUpdateSrcAddr(m_port_id, src_addr);
+    /* send RX core the relevant info */
+    CManyIPInfo ip_info;
+    ip_info.insert(COneIPv4Info(src_ipv4, 0, getPortAttrObj()->get_src_mac()));
+    
+    bool is_grat_arp_needed = !getPortAttrObj()->is_loopback();
+    
+    TrexStatelessRxSetL3Mode *msg = new TrexStatelessRxSetL3Mode(m_port_id, ip_info, is_grat_arp_needed);
     send_message_to_rx( (TrexStatelessCpToRxMsgBase *)msg );
 }
 
+
 Json::Value
 TrexStatelessPort::rx_features_to_json() {
     static MsgReply<Json::Value> reply;
index 3ae74f5..317f4f7 100644 (file)
@@ -400,10 +400,17 @@ public:
     const RXPacketBuffer *get_rx_queue_pkts();
 
     /**
-     * sets an IPv4 source address
+     * configures port for L2 mode
      * 
      */
-    void set_src_ipv4(uint32_t ipv4);
+    void set_l2_mode(const uint8_t *dest_mac);
+    
+    /**
+     * configures port in L3 mode
+     * 
+     */
+    void set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4);
+    void set_l3_mode(uint32_t src_ipv4, uint32_t dest_ipv4, const uint8_t *resolved_mac);
     
     /**
      * generate a JSON describing the status 
index dc656e6..2b8e93b 100644 (file)
@@ -317,7 +317,16 @@ TrexStatelessRxFeaturesToJson::handle(CRxCoreStateless *rx_core) {
 }
 
 bool
-TrexStatelessRxUpdateSrcAddr::handle(CRxCoreStateless *rx_core) {
-    rx_core->get_rx_port_mngr(m_port_id).update_src_addr(m_src_addr);
+TrexStatelessRxSetL2Mode::handle(CRxCoreStateless *rx_core) {
+    rx_core->get_rx_port_mngr(m_port_id).set_l2_mode();
+    
     return true;
 }
+
+bool
+TrexStatelessRxSetL3Mode::handle(CRxCoreStateless *rx_core) {
+    rx_core->get_rx_port_mngr(m_port_id).set_l3_mode(m_src_addr, m_is_grat_arp_needed);
+    
+    return true;
+}
+
index 5f00c24..dbdd9b5 100644 (file)
@@ -569,13 +569,33 @@ private:
     
 };
 
-class TrexStatelessRxUpdateSrcAddr : public TrexStatelessCpToRxMsgBase {
+/**
+ * updates the RX core that we are in L2 mode
+ */
+class TrexStatelessRxSetL2Mode : public TrexStatelessCpToRxMsgBase {
 public:
-    TrexStatelessRxUpdateSrcAddr(uint8_t port_id,
-                                 const CManyIPInfo &src_addr) {
-        
+    TrexStatelessRxSetL2Mode(uint8_t port_id) {
         m_port_id = port_id;
-        m_src_addr = src_addr;
+    }
+
+    virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+    uint8_t           m_port_id;
+};
+
+/**
+ * updates the RX core that we are in a L3 mode
+ */
+class TrexStatelessRxSetL3Mode : public TrexStatelessCpToRxMsgBase {
+public:
+    TrexStatelessRxSetL3Mode(uint8_t port_id,
+                             const CManyIPInfo &src_addr,
+                             bool is_grat_arp_needed) {
+        
+        m_port_id              = port_id;
+        m_src_addr             = src_addr;
+        m_is_grat_arp_needed   = is_grat_arp_needed;
     }
 
     virtual bool handle(CRxCoreStateless *rx_core);
@@ -583,6 +603,7 @@ public:
 private:
     uint8_t           m_port_id;
     CManyIPInfo       m_src_addr;
+    bool              m_is_grat_arp_needed;
 };
 
 /**
index 31fef68..502af9c 100644 (file)
@@ -185,17 +185,30 @@ void CRxCoreStateless::port_manager_tick() {
     }
 }
 
+/**
+ * for each port handle the grat ARP mechansim
+ * 
+ */
+void CRxCoreStateless::handle_grat_arp() {
+    for (int i = 0; i < m_max_ports; i++) {
+        m_rx_port_mngr[i].send_next_grat_arp();
+    }
+}
+
 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;
-    
+    dsec_t grat_arp_sec  = now_sec() + (double)CGlobalInfo::m_options.m_arp_ref_per;
+
     while (m_state == STATE_WORKING) {
         process_all_pending_pkts();
 
         dsec_t now = now_sec();
         
+        /* until a scheduler is added here - dirty IFs */
+
         if ( (now - sync_time_sec) > 0 ) {
             periodic_check_for_cp_messages();
         }
@@ -204,7 +217,12 @@ void CRxCoreStateless::handle_work_stage() {
             port_manager_tick();
             tick_time_sec = now + 1.0;
         }
-        
+
+        if ( (now - grat_arp_sec) > 0) {
+            handle_grat_arp();
+            grat_arp_sec = now + (double)CGlobalInfo::m_options.m_arp_ref_per;
+        }
+
         rte_pause();
         
     }
@@ -346,3 +364,8 @@ CRxCoreStateless::get_rx_port_mngr(uint8_t port_id) {
     return m_rx_port_mngr[port_id];
     
 }
+
+void
+CRxCoreStateless::get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff) {
+    get_rx_port_mngr(port_id).get_ignore_stats(stat, get_diff);
+}
index 96e511b..4eed59a 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef __TREX_STATELESS_RX_CORE_H__
 #define __TREX_STATELESS_RX_CORE_H__
 #include <stdint.h>
+
 #include "stateful_rx_core.h"
 #include "os_time.h"
 #include "pal/linux/sanb_atomic.h"
@@ -153,6 +154,12 @@ class CRxCoreStateless {
 
     RXPortManager &get_rx_port_mngr(uint8_t port_id);
     
+    /**
+     * fetch the ignored stats for a port
+     * 
+     */
+    void get_ignore_stats(int port_id, CRXCoreIgnoreStat &stat, bool get_diff);
+
  private:
     void handle_cp_msg(TrexStatelessCpToRxMsgBase *msg);
     bool periodic_check_for_cp_messages();
@@ -166,7 +173,8 @@ class CRxCoreStateless {
     void handle_rx_queue_msgs(uint8_t thread_id, CNodeRing * r);
     void handle_work_stage();
     void port_manager_tick();
-    
+    void handle_grat_arp();
+
     int process_all_pending_pkts(bool flush_rx = false);
 
     void flush_all_pending_pkts() {
index e36f825..4c54a13 100644 (file)
@@ -661,10 +661,15 @@ RXServer::duplicate_mbuf(const rte_mbuf_t *m) {
  * 
  *************************************/
 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;
+RXGratARP::create(uint8_t port_id,
+                  CPortLatencyHWBase *io,
+                  CManyIPInfo *src_addr,
+                  CRXCoreIgnoreStat *ign_stats) {
+    
+    m_port_id     = port_id;
+    m_io          = io;
+    m_src_addr    = src_addr;
+    m_ign_stats   = ign_stats;
 }
 
 void
@@ -689,9 +694,19 @@ RXGratARP::send_next_grat_arp() {
     
     CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, m_port_id);
     
-    m_io->tx(m);
+    if (m_io->tx(m) == 0) {
+        m_ign_stats->m_tx_arp    += 1;
+        m_ign_stats->m_tot_bytes += 64;
+    }
     
+}
+
+Json::Value
+RXGratARP::to_json() const {
+    Json::Value output = Json::objectValue;
+    output["interval_sec"] = (double)CGlobalInfo::m_options.m_arp_ref_per;
     
+    return output;
 }
 
 /**************************************
@@ -729,11 +744,10 @@ RXPortManager::create(const TRexPortAttr *port_attr,
     /* init features */
     m_latency.create(rfc2544, err_cntrs);
     m_server.create(m_port_id, io, &m_src_addr);
-    m_grat_arp.create(m_port_id, io, &m_src_addr);
+    m_grat_arp.create(m_port_id, io, &m_src_addr, &m_ign_stats);
     
-    /* by default, server feature is always on */
+    /* by default, server is always on */
     set_feature(SERVER);
-    set_feature(GRAT_ARP);
 }
     
 void RXPortManager::handle_pkt(const rte_mbuf_t *m) {
@@ -797,13 +811,43 @@ RXPortManager::tick() {
     if (is_feature_set(RECORDER)) {
         m_recorder.flush_to_disk();
     }
-    
+}
+
+void
+RXPortManager::send_next_grat_arp() {
     if (is_feature_set(GRAT_ARP)) {
         m_grat_arp.send_next_grat_arp();
     }
 }
 
+  
+void
+RXPortManager::set_l2_mode() {
+        
+    /* no IPv4 addresses */
+    m_src_addr.clear();
+        
+    /* stop grat arp */
+    stop_grat_arp();     
+}
+
+void
+RXPortManager::set_l3_mode(const CManyIPInfo &ip_info, bool is_grat_arp_needed) {
+        
+    /* copy L3 address */
+    m_src_addr = ip_info;
+        
+    if (is_grat_arp_needed) {
+        start_grat_arp();
+    }
+    else {
+        stop_grat_arp();
+    }
+    
+}
+
 
+    
 Json::Value
 RXPortManager::to_json() const {
     Json::Value output = Json::objectValue;
@@ -829,7 +873,23 @@ RXPortManager::to_json() const {
         output["queue"]["is_active"] = false;
     }
  
+    if (is_feature_set(GRAT_ARP)) {
+        output["grat_arp"] = m_grat_arp.to_json();
+        output["grat_arp"]["is_active"] = true;
+    } else {
+        output["grat_arp"]["is_active"] = false;
+    }
+    
     return output;
 }
 
 
+void RXPortManager::get_ignore_stats(CRXCoreIgnoreStat &stat, bool get_diff) {
+    if (get_diff) {
+        stat = m_ign_stats - m_ign_stats_prev;
+        m_ign_stats_prev = m_ign_stats;
+    } else {
+        stat = m_ign_stats;
+    }
+}
+
index e72b0ff..8947def 100644 (file)
@@ -284,12 +284,16 @@ private:
 class RXGratARP {
 public:
     RXGratARP() {
-        m_io = NULL;
-        m_port_id = UINT8_MAX;
-        m_src_addr = NULL;
+        m_io        = NULL;
+        m_port_id   = UINT8_MAX;
+        m_src_addr  = NULL;
+        m_ign_stats = NULL;
     }
     
-    void create(uint8_t port_id, CPortLatencyHWBase *io, CManyIPInfo *src_addr);
+    void create(uint8_t port_id,
+                CPortLatencyHWBase *io,
+                CManyIPInfo *src_addr,
+                CRXCoreIgnoreStat *ignore_stats);
 
     
     /**
@@ -298,10 +302,13 @@ public:
      */
     void send_next_grat_arp();
     
+    Json::Value to_json() const;
+    
 private:
+    uint8_t               m_port_id;
     CPortLatencyHWBase   *m_io;
     CManyIPInfo          *m_src_addr;
-    uint8_t               m_port_id;
+    CRXCoreIgnoreStat    *m_ign_stats;
 };
 
 /************************ manager ***************************/
@@ -389,7 +396,13 @@ public:
         return m_queue.fetch();
     }
 
+    void start_grat_arp() {
+        set_feature(GRAT_ARP);
+    }
     
+    void stop_grat_arp() {
+        unset_feature(GRAT_ARP);
+    }
 
     /**
      * fetch and process all packets
@@ -421,14 +434,25 @@ public:
     void tick();
     
     /**
-     * updates the source addresses registered with the port
+     * send next grat arp (if on)
      * 
+     * @author imarom (12/13/2016)
      */
-    void update_src_addr(const CManyIPInfo &new_src_addr) {
-        /* deep copy */
-        m_src_addr = new_src_addr;
-    }
+    void send_next_grat_arp();
+
+    /**
+     * set port mode to L2
+     */
+    void set_l2_mode();
     
+    /**
+     * set port mode to L3
+     * 
+     * @author imarom (12/13/2016)
+     */
+    void set_l3_mode(const CManyIPInfo &ip_info, bool is_grat_arp_needed);
+  
+      
     bool has_features_set() {
         return (m_features != NO_FEATURES);
     }
@@ -438,6 +462,12 @@ public:
         return (!has_features_set());
     }
 
+    /**
+     * returns ignored set of stats
+     * (grat ARP, PING response and etc.)
+     */
+    void get_ignore_stats(CRXCoreIgnoreStat &stat, bool get_diff);
+    
     /**
      * write the status to a JSON format
      */
@@ -475,6 +505,10 @@ private:
     CCpuUtlDp                   *m_cpu_dp_u;
     CPortLatencyHWBase          *m_io;
     CManyIPInfo                  m_src_addr;
+    
+    /* stats to ignore (ARP and etc.) */
+    CRXCoreIgnoreStat            m_ign_stats;
+    CRXCoreIgnoreStat            m_ign_stats_prev;
 };
 
 
index 437fa8c..7336bef 100755 (executable)
@@ -133,7 +133,8 @@ public:
     virtual bool is_link_change_supported() { return flag_is_link_change_supported; }
     virtual void get_description(std::string &description) { description = intf_info_st.description; }
     virtual void get_supported_speeds(supp_speeds_t &supp_speeds) = 0;
-
+    virtual bool is_loopback() const = 0;
+    
     uint32_t get_src_ipv4() const {return m_src_ipv4;}
     DestAttr & get_dest() {return m_dest;}
     
@@ -219,7 +220,8 @@ public:
     virtual int get_xstats_names(xstats_names_t &xstats_names);
     virtual int get_flow_ctrl(int &mode);
     virtual void get_supported_speeds(supp_speeds_t &supp_speeds);
-
+    virtual bool is_loopback() const;
+    
 /*    SETTERS    */
     virtual int set_promiscuous(bool enabled);
     virtual int add_mac(char * mac);
@@ -273,6 +275,7 @@ public:
     int set_led(bool on) { return -ENOTSUP; }
     void dump_link(FILE *fd) {}
     int set_rx_filter_mode(rx_filter_mode_e mode) { return -ENOTSUP; }
+    virtual bool is_loopback() const { return false; }
 };