diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/bp_sim.h | 31 | ||||
-rw-r--r-- | src/debug.cpp | 3 | ||||
-rw-r--r-- | src/latency.cpp | 54 | ||||
-rw-r--r-- | src/latency.h | 2 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 13 | ||||
-rwxr-xr-x | src/platform_cfg.cpp | 14 | ||||
-rwxr-xr-x | src/platform_cfg.h | 4 | ||||
-rw-r--r-- | src/pre_test.cpp | 168 | ||||
-rw-r--r-- | src/pre_test.h | 12 | ||||
-rw-r--r-- | src/test_pkt_gen.cpp | 52 | ||||
-rw-r--r-- | src/test_pkt_gen.h | 6 |
11 files changed, 240 insertions, 119 deletions
diff --git a/src/bp_sim.h b/src/bp_sim.h index 37c3e1ef..5f21ca26 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -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*/ diff --git a/src/debug.cpp b/src/debug.cpp index 2e7eb5db..5abdbdc6 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -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"); diff --git a/src/latency.cpp b/src/latency.cpp index 03c48a25..675cf80a 100644 --- a/src/latency.cpp +++ b/src/latency.cpp @@ -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 */ diff --git a/src/latency.h b/src/latency.h index e398d7c7..2f8a1134 100644 --- a/src/latency.h +++ b/src/latency.h @@ -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); diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index cc0fdb53..e1cbf9de 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -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()); } } diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index a090a0cd..a8f7997c 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -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) { diff --git a/src/platform_cfg.h b/src/platform_cfg.h index cd01f476..d9eca60b 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -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; diff --git a/src/pre_test.cpp b/src/pre_test.cpp index 9df2ed6b..b1401112 100644 --- a/src/pre_test.cpp +++ b/src/pre_test.cpp @@ -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); diff --git a/src/pre_test.h b/src/pre_test.h index 09085329..bd908cbb 100644 --- a/src/pre_test.h +++ b/src/pre_test.h @@ -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(); diff --git a/src/test_pkt_gen.cpp b/src/test_pkt_gen.cpp index b16eca37..14547c41 100644 --- a/src/test_pkt_gen.cpp +++ b/src/test_pkt_gen.cpp @@ -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); +} diff --git a/src/test_pkt_gen.h b/src/test_pkt_gen.h index 49e8e7b0..4257c9ae 100644 --- a/src/test_pkt_gen.h +++ b/src/test_pkt_gen.h @@ -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 |