pre test: Periodically send gratuitous ARP in stateful
authorIdo Barnea <[email protected]>
Sun, 25 Sep 2016 13:58:02 +0000 (16:58 +0300)
committerIdo Barnea <[email protected]>
Wed, 5 Oct 2016 07:45:28 +0000 (10:45 +0300)
src/bp_sim.h
src/debug.cpp
src/latency.cpp
src/latency.h
src/main_dpdk.cpp
src/platform_cfg.cpp
src/platform_cfg.h
src/pre_test.cpp
src/pre_test.h
src/test_pkt_gen.cpp
src/test_pkt_gen.h

index 37c3e1e..5f21ca2 100755 (executable)
@@ -695,7 +695,28 @@ public:
     } u;
 } __rte_cache_aligned; ;
 
-struct CParserOption {
+class CPerPortIPCfg {
+ public:
+    uint32_t get_ip() {return m_ip;}
+    uint32_t get_mask() {return m_mask;}
+    uint32_t get_def_gw() {return m_def_gw;}
+    uint32_t get_vlan() {return m_vlan;}
+    bool is_loopback() {return m_is_loopback;}
+    void set_ip(uint32_t val) {m_ip = val;}
+    void set_mask(uint32_t val) {m_mask = val;}
+    void set_def_gw(uint32_t val) {m_def_gw = val;}
+    void set_vlan(uint16_t val) {m_vlan = val;}
+    void set_loopback(bool val) {m_is_loopback = val;}
+
+ private:
+    uint32_t m_def_gw;
+    uint32_t m_ip;
+    uint32_t m_mask;
+    uint16_t m_vlan;
+    bool m_is_loopback;
+};
+
+class CParserOption {
 
 public:
     /* Runtime flags */
@@ -757,8 +778,7 @@ public:
     uint16_t           m_vlan_port[2]; /* vlan value */
     uint16_t           m_src_ipv6[6];  /* Most signficant 96-bits */
     uint16_t           m_dst_ipv6[6];  /* Most signficant 96-bits */
-    uint32_t        m_def_gw[TREX_MAX_PORTS];
-    uint32_t        m_ip[TREX_MAX_PORTS];
+    CPerPortIPCfg   m_ip_cfg[TREX_MAX_PORTS];
     uint32_t        m_latency_rate; /* pkt/sec for each thread/port zero disable */
     uint32_t        m_latency_mask;
     uint32_t        m_latency_prev;
@@ -1430,12 +1450,9 @@ public:
         STATELESS_PKT           =5,
         EXIT_SCHED              =6,
         COMMAND                 =7,
-
         EXIT_PORT_SCHED         =8,
-
         PCAP_PKT                =9,
-
-
+        GRAT_ARP                =10,
     };
 
     /* flags MASKS*/
index 2e7eb5d..5abdbdc 100644 (file)
@@ -123,7 +123,6 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t
     char *pkt;
     rte_mbuf_t *m;
     char *p;
-    CTestPktGen gen;
     uint16_t l3_type;
 
     switch (ip_ver) {
@@ -141,7 +140,7 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t
         break;
     }
 
-    pkt = gen.create_test_pkt(l3_type, l4_proto, ttl, ip_id, flags, 1000, pkt_size);
+    pkt = CTestPktGen::create_test_pkt(l3_type, l4_proto, ttl, ip_id, flags, 1000, pkt_size);
     m = CGlobalInfo::pktmbuf_alloc(0, pkt_size);
     if ( unlikely(m == 0) )  {
         printf("ERROR no packets \n");
index 03c48a2..675cf80 100644 (file)
@@ -19,13 +19,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
-#include "latency.h"
 #include "bp_sim.h"
 #include "flow_stat_parser.h"
 #include "utl_json.h"
 #include "trex_watchdog.h"
-
-#include <common/basic_utils.h> 
+#include "test_pkt_gen.h"
+#include "common/basic_utils.h"
+#include "latency.h"
 
 const uint8_t sctp_pkt[]={ 
 
@@ -172,6 +172,7 @@ void CCPortLatency::reset(){
     m_pad       = 0;
     m_tx_pkt_err=0;
     m_tx_pkt_ok =0;
+    m_tx_grat_arp_ok =0;
     m_pkt_ok=0;
     m_rx_check=0;
     m_no_magic=0;
@@ -294,6 +295,7 @@ void CCPortLatency::dump_counters_json(std::string & json ){
 
     json+="\"stats\" : {";
     DPL_J(m_tx_pkt_ok);
+    DPL_J(m_tx_grat_arp_ok);
     DPL_J(m_tx_pkt_err);
     DPL_J(m_pkt_ok);
     DPL_J(m_unsup_prot);
@@ -318,6 +320,7 @@ void CCPortLatency::DumpCounters(FILE *fd){
 
     DP_A1(m_tx_pkt_err);
     DP_A1(m_tx_pkt_ok);
+    DP_A1(m_tx_grat_arp_ok);
     DP_A1(m_pkt_ok);
     DP_A1(m_unsup_prot);
     DP_A1(m_no_magic);
@@ -578,6 +581,34 @@ void  CLatencyManager::send_pkt_all_ports(){
     }
 }
 
+void  CLatencyManager::send_grat_arp_all_ports() {
+    for (int port_id = 0; port_id < m_max_ports; port_id++) {
+        // if port is connected in loopback, no need to send. It will only confuse our ingress counters.
+        if (CGlobalInfo::m_options.m_ip_cfg[port_id].is_loopback())
+            continue;
+
+        CLatencyManagerPerPort * lp = &m_ports[port_id];
+        rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc_small(CGlobalInfo::m_socket.port_to_socket(port_id));
+        assert(m);
+        uint8_t *p = (uint8_t *)rte_pktmbuf_append(m, 60); // ARP packet is shorter than 60
+        uint32_t sip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_ip();
+        uint8_t *src_mac = CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src;
+        uint16_t vlan = CGlobalInfo::m_options.m_ip_cfg[port_id].get_vlan();
+        // gratuitous ARP. Requested IP is our source.
+        CTestPktGen::create_arp_req(p, sip, sip, src_mac, vlan, port_id);
+
+        if (CGlobalInfo::m_options.preview.getVMode() >= 3) {
+            printf("Sending gratuitous ARP on port %d vlan:%d, sip:0x%08x\n", port_id, vlan, sip);
+            utl_DumpBuffer(stdout, p, 60, 0);
+        }
+
+        if ( lp->m_io->tx(m) == 0 ) {
+            lp->m_port.m_tx_grat_arp_ok++;
+        } else {
+            lp->m_port.m_tx_pkt_err++;
+        }
+    }
+}
 
 void  CLatencyManager::wait_for_rx_dump(){
        rte_mbuf_t * rx_pkts[64];
@@ -718,7 +749,13 @@ void  CLatencyManager::start(int iter, bool activate_watchdog) {
     node->m_type = CGenNode::FLOW_PKT; /* latency */
     node->m_time = now_sec(); /* 1/cps rate */
     m_p_queue.push(node);
-    bool do_try_rx_queue =CGlobalInfo::m_options.preview.get_vm_one_queue_enable()?true:false;
+
+    node = new CGenNode();
+    node->m_type = CGenNode::GRAT_ARP; /* gratuitous ARP */
+    node->m_time = now_sec() + 120;
+    m_p_queue.push(node);
+
+    bool do_try_rx_queue = CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ? true : false;
 
     if (activate_watchdog) {
         m_monitor.create("STF RX CORE", 1);
@@ -764,6 +801,15 @@ void  CLatencyManager::start(int iter, bool activate_watchdog) {
             m_p_queue.push(node);
             m_cpu_dp_u.commit1();
             break;
+
+        case CGenNode::GRAT_ARP:
+            m_cpu_dp_u.start_work1();
+            send_grat_arp_all_ports();
+            m_p_queue.pop();
+            node->m_time += 120; // every two minutes
+            m_p_queue.push(node);
+            m_cpu_dp_u.commit1();
+            break;
         }
 
         /* this will be called every sync which is 1msec */
index e398d7c..2f8a113 100644 (file)
@@ -180,6 +180,7 @@ private:
 
 public:
      uint64_t m_tx_pkt_ok;
+     uint64_t m_tx_grat_arp_ok;
      uint64_t m_tx_pkt_err;
      uint64_t m_pkt_ok;
      uint64_t m_unsup_prot;
@@ -319,6 +320,7 @@ public:
 private:
     void  tickle();
     void  send_pkt_all_ports();
+    void  send_grat_arp_all_ports();
     void  try_rx();
     void  try_rx_queues();
     void  run_rx_queue_msgs(uint8_t thread_id, CNodeRing * r);
index cc0fdb5..e1cbf9d 100644 (file)
@@ -2994,9 +2994,9 @@ void CGlobalTRex::pre_test() {
             rte_eth_macaddr_get(port_id,
                                 (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src);
         }
-        pretest.set_port_params(port_id, CGlobalInfo::m_options.m_ip[port_id]
+        pretest.set_port_params(port_id, CGlobalInfo::m_options.m_ip_cfg[port_id]
                                 , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src
-                                , CGlobalInfo::m_options.m_def_gw[port_id], resolve_needed);
+                                , resolve_needed);
     }
 
     pretest.send_grat_arp_all();
@@ -3007,13 +3007,14 @@ void CGlobalTRex::pre_test() {
     uint8_t mac[ETHER_ADDR_LEN];
     for (int port_id = 0; port_id < m_max_ports; port_id++) {
         if (! memcmp(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) {
-            uint32_t ip = CGlobalInfo::m_options.m_def_gw[port_id];
+            uint32_t ip = CGlobalInfo::m_options.m_ip_cfg[port_id].get_def_gw();
             if (! pretest.get_mac(port_id, ip, mac)) {
                 fprintf(stderr, "Failed resolving dest MAC for default gateway:%d.%d.%d.%d on port %d\n"
                         , (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, port_id);
                 exit(1);
             }
             memcpy(CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, mac, ETHER_ADDR_LEN);
+            CGlobalInfo::m_options.m_ip_cfg[port_id].set_loopback(pretest.is_loopback(port_id));
         }
 
         CPhyEthIF *pif = &m_ports[port_id];
@@ -4825,8 +4826,10 @@ int update_global_info_from_platform_file(){
         for (i=0; i<port_size; i++){
             cg->m_mac_info[i].copy_src(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.src)   ;
             cg->m_mac_info[i].copy_dest(( char *)CGlobalInfo::m_options.m_mac_addr[i].u.m_mac.dest)  ;
-            CGlobalInfo::m_options.m_def_gw[i] = cg->m_mac_info[i].get_def_gw();
-            CGlobalInfo::m_options.m_ip[i] = cg->m_mac_info[i].get_ip();
+            CGlobalInfo::m_options.m_ip_cfg[i].set_def_gw(cg->m_mac_info[i].get_def_gw());
+            CGlobalInfo::m_options.m_ip_cfg[i].set_ip(cg->m_mac_info[i].get_ip());
+            CGlobalInfo::m_options.m_ip_cfg[i].set_mask(cg->m_mac_info[i].get_mask());
+            CGlobalInfo::m_options.m_ip_cfg[i].set_vlan(cg->m_mac_info[i].get_vlan());
         }
     }
 
index a090a0c..a8f7997 100755 (executable)
@@ -174,6 +174,14 @@ uint32_t CMacYamlInfo::get_ip() {
     return m_ip;
 }
 
+uint32_t CMacYamlInfo::get_mask() {
+    return m_mask;
+}
+
+uint32_t CMacYamlInfo::get_vlan() {
+    return m_vlan;
+}
+
 void CMacYamlInfo::Dump(FILE *fd){
     if (m_dest_base.size() != 6) {
         fprintf(fd,"ERROR in dest mac addr \n");
@@ -244,6 +252,12 @@ void operator >> (const YAML::Node& node, CMacYamlInfo & mac_info) {
     if (! utl_yaml_read_ip_addr(node, "ip", mac_info.m_ip)) {
         mac_info.m_ip = 0;
     }
+    if (! utl_yaml_read_ip_addr(node, "mask", mac_info.m_mask)) {
+        mac_info.m_mask = 0;
+    }
+    if (! utl_yaml_read_uint16(node, "vlan", mac_info.m_vlan)) {
+        mac_info.m_vlan = 0;
+    }
 }
 
 void operator >> (const YAML::Node& node, CPlatformMemoryYamlInfo & plat_info) {
index cd01f47..d9eca60 100755 (executable)
@@ -101,12 +101,16 @@ struct CMacYamlInfo {
     std::vector     <uint8_t> m_src_base;
     uint32_t m_def_gw;
     uint32_t m_ip;
+    uint32_t m_mask;
+    uint16_t m_vlan;
     void Dump(FILE *fd);
 
     void copy_dest(char *p);
     void copy_src(char *p);
     uint32_t get_def_gw();
     uint32_t get_ip();
+    uint32_t get_vlan();
+    uint32_t get_mask();
 
     void dump_mac_vector( std::vector<uint8_t> & v,FILE *fd){
         int i;
index 9df2ed6..b140111 100644 (file)
@@ -1,20 +1,3 @@
-/* 
-?????
-- read also from q 0
-- read periodically - not wait 1 sec
-flush q 0,1 at end
-close q 0 at end (not close it at start)
-test in trex-dan router for long time. remove static arp from router.
-test 10g, vm
-add also per profile
-
-
-remove stuff in ???
-make 10G work
-documentation
-
- */
-
 /*
   Ido Barnea
   Cisco Systems, Inc.
@@ -43,13 +26,14 @@ documentation
 #include "common/basic_utils.h"
 #include "bp_sim.h"
 #include "main_dpdk.h"
+#include "test_pkt_gen.h"
 #include "pre_test.h"
 
 
-void CPretestPortInfo::set_params(uint32_t ip, const uint8_t *src_mac, uint32_t def_gw
-                                  , bool resolve_needed) {
-    m_ip = ip;
-    m_def_gw = def_gw;
+void CPretestPortInfo::set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed) {
+    m_ip = port_cfg.get_ip();
+    m_def_gw = port_cfg.get_def_gw();
+    m_vlan = port_cfg.get_vlan();
     memcpy(&m_src_mac, src_mac, sizeof(m_src_mac));
     if (resolve_needed) {
         m_state = CPretestPortInfo::RESOLVE_NEEDED;
@@ -69,7 +53,7 @@ void CPretestPortInfo::dump(FILE *fd) {
     }
 
     uint32_t ip = htonl(m_ip);
-    
+
     fprintf(fd, "  ip:%d.%d.%d.%d", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
     ip = htonl(m_def_gw);
     fprintf(fd, "  default gw:%d.%d.%d.%d\n", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
@@ -85,72 +69,33 @@ void CPretestPortInfo::dump(FILE *fd) {
     }
 }
 
-// Create ARP request for our default gateway.
-// If is_grat is true - create gratuitous ARP.
-// pkt_size will contain the size of buffer returned.
-// Return pointer to buffer containing the packet.
-uint8_t *CPretestPortInfo::create_arp_req(uint16_t &pkt_size, uint8_t port, bool is_grat) {
-    pkt_size = 14 + sizeof (struct arp_hdr);
-    uint16_t l2_proto = htons(EthernetHeader::Protocol::ARP);
-    
-    uint8_t *pkt = (uint8_t *)malloc(pkt_size);
-    assert(pkt != NULL);   
-    uint8_t *p = pkt;
-    
-    // dst MAC
-    memset(p, 0xff, ETHER_ADDR_LEN);
-    p += ETHER_ADDR_LEN;
-    // src MAC
-    memcpy(p, m_src_mac, ETHER_ADDR_LEN);
-    p += ETHER_ADDR_LEN;
-    // l3 type
-    memcpy(p, &l2_proto, sizeof(l2_proto));
-    p += 2;
-
-    struct arp_hdr *arp = (struct arp_hdr *)p;
-    arp->arp_hrd = htons(ARP_HRD_ETHER); // Format of hardware address
-    arp->arp_pro = htons(EthernetHeader::Protocol::IP); // Format of protocol address
-    arp->arp_hln = ETHER_ADDR_LEN; // Length of hardware address
-    arp->arp_pln = 4; // Length of protocol address
-    arp->arp_op = htons(ARP_OP_REQUEST); // ARP opcode (command)
-
-    memcpy(&arp->arp_data.arp_sha, m_src_mac, ETHER_ADDR_LEN); // Sender MAC address
-    arp->arp_data.arp_sip = htonl(m_ip); // Sender IP address
-    uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
-    memcpy(&arp->arp_data.arp_tha, magic, 5); // Target MAC address
-    arp->arp_data.arp_tha.addr_bytes[5] = port;
-    if (is_grat)
-        arp->arp_data.arp_tip = htonl(m_ip); // gratuitous ARP is request for your own IP.
-    else
-        arp->arp_data.arp_tip = htonl(m_def_gw); // Target IP address
-    
-    return pkt;
-}
-
 /*
   put in mac relevant dest MAC for port/ip pair.
   return false if no relevant info exists, true otherwise.
  */
 bool CPretest::get_mac(uint16_t port, uint32_t ip, uint8_t *mac) {
-    if (port >= TREX_MAX_PORTS) {
-        return false;
-    }
+    assert(port < TREX_MAX_PORTS);
 
     if (m_port_info[port].m_state != CPretestPortInfo::RESOLVE_DONE) {
         return false;
     }
 
     memcpy(mac, &m_port_info[port].m_dst_mac, sizeof(m_port_info[port].m_dst_mac));
-        
-    return true;    
+
+    return true;
 }
 
-void CPretest::set_port_params(uint16_t port, uint32_t ip, const uint8_t *src_mac, uint32_t def_gw,
-                               bool resolve_needed) {
-    if (port >= m_max_ports)
+bool CPretest::is_loopback(uint16_t port) {
+    assert(port < TREX_MAX_PORTS);
+
+    return m_port_info[port].m_is_loopback;
+}
+
+void CPretest::set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed) {
+    if (port_id >= m_max_ports)
         return;
 
-    m_port_info[port].set_params(ip, src_mac, def_gw, resolve_needed);
+    m_port_info[port_id].set_params(port_cfg, src_mac, resolve_needed);
 }
 
 
@@ -158,9 +103,10 @@ int CPretest::handle_rx(int port_id, int queue_id) {
     rte_mbuf_t * rx_pkts[32];
     uint16_t cnt;
     int i;
+    int verbose = CGlobalInfo::m_options.preview.getVMode();
 
     cnt = rte_eth_rx_burst(port_id, queue_id, rx_pkts, sizeof(rx_pkts)/sizeof(rx_pkts[0]));
+
     for (i = 0; i < cnt; i++) {
         rte_mbuf_t * m = rx_pkts[i];
         int pkt_size = rte_pktmbuf_pkt_len(m);
@@ -169,9 +115,15 @@ int CPretest::handle_rx(int port_id, int queue_id) {
         CPretestPortInfo *port = &m_port_info[port_id];
         if (is_arp(p, pkt_size, arp)) {
                 if (arp->arp_op == htons(ARP_OP_REQUEST)) {
+                    if (verbose >= 3) {
+                        fprintf(stdout, "RX ARP request on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id
+                                , ntohl(arp->arp_data.arp_sip)
+                                , ntohl(arp->arp_data.arp_tip));
+                    }
                     // is this request for our IP?
                     if (ntohl(arp->arp_data.arp_tip) == port->m_ip) {
-                        // If our request, do a shortcut, and write info directly to asking port
+                        // If our request(i.e. we are connected in loopback)
+                        // , do a shortcut, and write info directly to asking port
                         uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
                         if (! memcmp((uint8_t *)&arp->arp_data.arp_tha, magic, 5)) {
                             uint8_t sent_port_id = arp->arp_data.arp_tha.addr_bytes[5];
@@ -179,6 +131,7 @@ int CPretest::handle_rx(int port_id, int queue_id) {
                                 (m_port_info[sent_port_id].m_def_gw == port->m_ip)) {
                                 memcpy(m_port_info[sent_port_id].m_dst_mac, port->m_src_mac, ETHER_ADDR_LEN);
                                 m_port_info[sent_port_id].m_state = CPretestPortInfo::RESOLVE_DONE;
+                                m_port_info[sent_port_id].m_is_loopback = true;
                             }
                         }
                     } else {
@@ -186,16 +139,19 @@ int CPretest::handle_rx(int port_id, int queue_id) {
                     }
                 } else {
                     if (arp->arp_op == htons(ARP_OP_REPLY)) {
+                        if (verbose >= 3) {
+                            fprintf(stdout, "RX ARP response on port %d queue %d sip:0x%08x tip:0x%08x\n", port_id, queue_id
+                                    , ntohl(arp->arp_data.arp_sip)
+                                    , ntohl(arp->arp_data.arp_tip));
+                        }
                         // If this is response to our request, update our tables
                         if (port->m_def_gw == ntohl(arp->arp_data.arp_sip)) {
                             port->set_dst_mac((uint8_t *)&arp->arp_data.arp_sha);
                         }
                     }
                 }
-        }       
+        }
 
-        printf("port %d, queue:%d\n", port_id, queue_id);
-        utl_DumpBuffer(stdout, p, pkt_size, 0); //??? remove
         rte_pktmbuf_free(m);
     }
     return 0;
@@ -252,26 +208,39 @@ void CPretest::dump(FILE *fd) {
     }
 }
 
-void CPretest::send_arp_req(uint16_t port, bool is_grat) {
-    uint16_t pkt_size;
-    uint8_t *pkt;
+// Send ARP request for our default gateway on port
+// If is_grat is true - send gratuitous ARP.
+void CPretest::send_arp_req(uint16_t port_id, bool is_grat) {
     rte_mbuf_t *m[1];
-    char *p;
     int num_sent;
+    int verbose = CGlobalInfo::m_options.preview.getVMode();
 
-    pkt = m_port_info[port].create_arp_req(pkt_size, port, is_grat);
-    m[0] = CGlobalInfo::pktmbuf_alloc(0, pkt_size);
+    m[0] = CGlobalInfo::pktmbuf_alloc_small(0);
     if ( unlikely(m[0] == 0) )  {
-        fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", port);
+        fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", port_id);
         exit(1);
     }
-    p = rte_pktmbuf_append(m[0], pkt_size);
-    memcpy(p, pkt, pkt_size);
-    free(pkt);
 
-    num_sent = rte_eth_tx_burst(port, 0, m, 1);
+    uint32_t tip;
+    uint8_t *p = (uint8_t *)rte_pktmbuf_append(m[0], 60); // ARP packet is shorter than 60
+    uint32_t sip = m_port_info[port_id].m_ip;
+    uint8_t *src_mac = m_port_info[port_id].m_src_mac;
+    uint16_t vlan = m_port_info[port_id].m_vlan;
+    if (is_grat) {
+        tip = sip;
+    } else {
+        tip = m_port_info[port_id].m_def_gw;
+    }
+
+    if (verbose >= 3) {
+        fprintf(stdout, "TX %s port:%d sip:0x%08x, tip:0x%08x\n"
+                , is_grat ? "grat ARP": "ARP request", port_id ,sip, tip);
+    }
+
+    CTestPktGen::create_arp_req(p, sip, tip, src_mac, vlan, port_id);
+    num_sent = rte_eth_tx_burst(port_id, 0, m, 1);
     if (num_sent < 1) {
-        fprintf(stderr, "Failed sending ARP to port:%d\n", port);
+        fprintf(stderr, "Failed sending ARP to port:%d\n", port_id);
         exit(1);
     }
 }
@@ -287,7 +256,7 @@ void CPretest::send_grat_arp_all() {
     }
 }
 
-bool CPretest::is_arp(uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp) {
+bool CPretest::is_arp(const uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp) {
     EthernetHeader *m_ether = (EthernetHeader *)p;
 
     if ((pkt_size < 60) ||
@@ -309,16 +278,25 @@ bool CPretest::is_arp(uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp) {
 }
 
 // Should be run on setup with two interfaces connected by loopback.
-// Before running, should put ports on receive all mode. 
+// Before running, should put ports on receive all mode.
 void CPretest::test() {
     uint8_t found_mac[ETHER_ADDR_LEN];
     uint8_t mac0[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd0};
     uint8_t mac1[ETHER_ADDR_LEN] = {0x90, 0xe2, 0xba, 0xae, 0x87, 0xd1};
     uint32_t ip0 = 0x0f000003;
     uint32_t ip1 = 0x0f000001;
-    
-    set_port_params(0, ip0, mac0, ip1, true);
-    set_port_params(1, ip1, mac1, ip0, true);
+
+    CPerPortIPCfg port_cfg0;
+    CPerPortIPCfg port_cfg1;
+    port_cfg0.set_ip(ip0);
+    port_cfg0.set_def_gw(ip1);
+    port_cfg0.set_vlan(0);
+    port_cfg1.set_ip(ip1);
+    port_cfg1.set_def_gw(ip0);
+    port_cfg1.set_vlan(0);
+
+    set_port_params(0, port_cfg0, mac0, true);
+    set_port_params(1, port_cfg1, mac1, true);
     dump(stdout);
     resolve_all();
     dump(stdout);
index 0908532..bd908cb 100644 (file)
@@ -23,6 +23,7 @@
 #define __PRE_TEST_H__
 
 #include <iostream>
+#include "bp_sim.h"
 #include "trex_defs.h"
 
 class CPretestPortInfo {
@@ -38,18 +39,21 @@ class CPretestPortInfo {
 
     CPretestPortInfo() {
         m_state = INIT_NEEDED;
+        m_is_loopback = false;
     }
     void dump(FILE *fd);
     uint8_t *create_arp_req(uint16_t &pkt_size, uint8_t port, bool is_grat);
-    void set_params(uint32_t ip, const uint8_t *src_mac, uint32_t def_gw, bool resolve_needed);
+    void set_params(CPerPortIPCfg port_cfg, const uint8_t *src_mac, bool resolve_needed);
     void set_dst_mac(const uint8_t *dst_mac);
     
  private:
     uint32_t m_ip;
     uint32_t m_def_gw;
+    uint16_t m_vlan;
     uint8_t m_src_mac[6];
     uint8_t m_dst_mac[6];
     enum CPretestPortInfoStates m_state;
+    bool m_is_loopback;
 };
 
 
@@ -59,12 +63,12 @@ class CPretest {
         m_max_ports = max_ports;
     }
     bool get_mac(uint16_t port, uint32_t ip, uint8_t *mac);
-    void set_port_params(uint16_t port, uint32_t ip, const uint8_t *src_mac, uint32_t def_gw,
-                        bool resolve_needed);
+    bool is_loopback(uint16_t port);
+    void set_port_params(uint16_t port_id, const CPerPortIPCfg &port_cfg, const uint8_t *src_mac, bool resolve_needed);
     bool resolve_all();
     void send_arp_req(uint16_t port, bool is_grat);
     void send_grat_arp_all();
-    bool is_arp(uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp);
+    bool is_arp(const uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp);
     void dump(FILE *fd);
     void test();
     
index b16eca3..14547c4 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <assert.h>
 #include <netinet/in.h>
+#include <rte_arp.h>
 #include <common/Network/Packet/TcpHeader.h>
 #include <common/Network/Packet/UdpHeader.h>
 #include <common/Network/Packet/IcmpHeader.h>
@@ -230,3 +231,54 @@ char *CTestPktGen::create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t
 
     return p_start;
 }
+
+/*
+ * Create ARP request packet
+ * Parameters:
+ *  pkt - Buffer to fill the packet in. Size should be big enough to contain the packet (60 is a good value).
+ *  sip - Our source IP
+ *  tip - Target IP for which we need resolution (In case of gratuitous ARP, should be equal sip).
+ *  src_mac - Our source MAC
+ *  vlan - VLAN tag to send the packet on. If set to 0, no vlan will be sent.
+ *  port - Port we intended to send packet on. This is needed since we put some "magic" number with the port, so
+ *         we can identify if we are connected in loopback, which ports are connected.
+ */
+void CTestPktGen::create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan
+                                 , uint16_t port) {
+    uint16_t l2_proto = htons(EthernetHeader::Protocol::ARP);
+
+    // dst MAC
+    memset(pkt, 0xff, ETHER_ADDR_LEN);
+    pkt += ETHER_ADDR_LEN;
+    // src MAC
+    memcpy(pkt, src_mac, ETHER_ADDR_LEN);
+    pkt += ETHER_ADDR_LEN;
+
+    if (vlan != 0) {
+        uint16_t htons_vlan = htons(vlan);
+        uint16_t vlan_proto = htons(0x8100);
+        memcpy(pkt, &vlan_proto, sizeof(vlan_proto));
+        pkt += 2;
+        memcpy(pkt, &htons_vlan, sizeof(uint16_t));
+        pkt += 2;
+    }
+
+    // l3 type
+    memcpy(pkt, &l2_proto, sizeof(l2_proto));
+    pkt += 2;
+
+    struct arp_hdr *arp = (struct arp_hdr *)pkt;
+    arp->arp_hrd = htons(ARP_HRD_ETHER); // Format of hardware address
+    arp->arp_pro = htons(EthernetHeader::Protocol::IP); // Format of protocol address
+    arp->arp_hln = ETHER_ADDR_LEN; // Length of hardware address
+    arp->arp_pln = 4; // Length of protocol address
+    arp->arp_op = htons(ARP_OP_REQUEST); // ARP opcode (command)
+
+    memcpy(&arp->arp_data.arp_sha, src_mac, ETHER_ADDR_LEN); // Sender MAC address
+    arp->arp_data.arp_sip = htonl(sip); // Sender IP address
+
+    uint8_t magic[5] = {0x1, 0x3, 0x5, 0x7, 0x9};
+    memcpy(&arp->arp_data.arp_tha, magic, 5); // Target MAC address
+    arp->arp_data.arp_tha.addr_bytes[5] = port;
+    arp->arp_data.arp_tip = htonl(tip);
+}
index 49e8e7b..4257c9a 100644 (file)
@@ -41,8 +41,10 @@ enum {
 
 class CTestPktGen {
  public:
-    char *create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags
-                          , uint16_t max_payload, int &pkt_size);
+    static char *create_test_pkt(uint16_t l3_type, uint16_t l4_proto, uint8_t ttl, uint32_t ip_id, uint16_t flags
+                                 , uint16_t max_payload, int &pkt_size);
+    static void create_arp_req(uint8_t *pkt, uint32_t sip, uint32_t tip, uint8_t *src_mac, uint16_t vlan
+                               , uint16_t port);
 };
 
 #endif