diff options
-rwxr-xr-x | linux_dpdk/ws_main.py | 1 | ||||
-rwxr-xr-x | src/bp_sim.h | 3 | ||||
-rw-r--r-- | src/main_dpdk.cpp | 62 | ||||
-rw-r--r-- | src/main_dpdk.h | 2 | ||||
-rwxr-xr-x | src/platform_cfg.cpp | 72 | ||||
-rwxr-xr-x | src/platform_cfg.h | 4 | ||||
-rw-r--r-- | src/pre_test.cpp | 339 | ||||
-rw-r--r-- | src/pre_test.h | 79 |
8 files changed, 537 insertions, 25 deletions
diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index dc169f11..47c479c4 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -117,6 +117,7 @@ main_src = SrcGroup(dir='src', 'bp_sim.cpp', 'latency.cpp', 'platform_cfg.cpp', + 'pre_test.cpp', 'tuple_gen.cpp', 'rx_check.cpp', 'rx_check_header.cpp', diff --git a/src/bp_sim.h b/src/bp_sim.h index 2790aa95..37c3e1ef 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -757,7 +757,8 @@ 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]; uint32_t m_latency_rate; /* pkt/sec for each thread/port zero disable */ uint32_t m_latency_mask; uint32_t m_latency_prev; diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index e45e2abf..cc0fdb53 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -73,6 +73,7 @@ extern "C" { #include "utl_term_io.h" #include "msg_manager.h" #include "platform_cfg.h" +#include "pre_test.h" #include "latency.h" #include "debug.h" #include "test_pkt_gen.h" @@ -1392,7 +1393,7 @@ void CPhyEthIF::configure_rx_duplicate_rules(){ } -void CPhyEthIF::configure_rx_drop_queue(){ +void CPhyEthIF::stop_rx_drop_queue() { // In debug mode, we want to see all packets. Don't want to disable any queue. if ( get_vm_one_queue_enable() || (CGlobalInfo::m_options.m_debug_pkt_proto != 0)) { return; @@ -2833,6 +2834,7 @@ public: void ixgbe_configure_mg(); void rx_sl_configure(); bool is_all_links_are_up(bool dump=false); + void pre_test(); int reset_counters(); /** @@ -2973,6 +2975,53 @@ public: }; +// Before starting, send gratitues ARP on our addresses, and try to resolve dst MAC addresses. +void CGlobalTRex::pre_test() { + CPretest pretest(m_max_ports); + bool resolve_needed = false; + uint8_t empty_mac[ETHER_ADDR_LEN] = {0,0,0,0,0,0}; + + for (int port_id = 0; port_id < m_max_ports; port_id++) { + CPhyEthIF *pif = &m_ports[port_id]; + // Configure port to send all packets to software + CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, true); + if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.dest, empty_mac, ETHER_ADDR_LEN)) { + resolve_needed = true; + } else { + resolve_needed = false; + } + if (! memcmp( CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src, empty_mac, ETHER_ADDR_LEN)) { + rte_eth_macaddr_get(port_id, + (struct ether_addr *)&CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src); + } + pretest.set_port_params(port_id, CGlobalInfo::m_options.m_ip[port_id] + , CGlobalInfo::m_options.m_mac_addr[port_id].u.m_mac.src + , CGlobalInfo::m_options.m_def_gw[port_id], resolve_needed); + } + + pretest.send_grat_arp_all(); + pretest.resolve_all(); + if ( CGlobalInfo::m_options.preview.getVMode() > 0) { + pretest.dump(stdout); + } + 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]; + 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); + } + + CPhyEthIF *pif = &m_ports[port_id]; + // Configure port back to normal mode. Only relevant packets handled by software. + CTRexExtendedDriverDb::Ins()->get_drv()->set_rcv_all(pif, false); + } +} + int CGlobalTRex::reset_counters(){ int i; for (i=0; i<m_max_ports; i++) { @@ -3257,7 +3306,6 @@ int CGlobalTRex::ixgbe_start(void){ _if->stats_clear(); _if->start(); - _if->configure_rx_drop_queue(); _if->configure_rx_duplicate_rules(); if ( ! get_vm_one_queue_enable() && ! CGlobalInfo::m_options.preview.get_is_disable_flow_control_setting() @@ -4777,6 +4825,8 @@ 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(); } } @@ -5143,6 +5193,14 @@ int main_test(int argc , char * argv[]){ } } + g_trex.pre_test(); + // after doing all needed ARP resolution, we need to flush queues, and stop our drop queue + g_trex.ixgbe_rx_queue_flush(); + for (int i = 0; i < g_trex.m_max_ports; i++) { + CPhyEthIF *_if = &g_trex.m_ports[i]; + _if->stop_rx_drop_queue(); + } + if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){ rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER); RTE_LCORE_FOREACH_SLAVE(lcore_id) { diff --git a/src/main_dpdk.h b/src/main_dpdk.h index 3104ff50..bde10659 100644 --- a/src/main_dpdk.h +++ b/src/main_dpdk.h @@ -81,7 +81,7 @@ class CPhyEthIF { uint16_t nb_tx_desc, unsigned int socket_id, const struct rte_eth_txconf *tx_conf); - void configure_rx_drop_queue(); + void stop_rx_drop_queue(); void configure_rx_duplicate_rules(); void start(); void stop(); diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index 64bbb71b..a090a0cd 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -23,6 +23,7 @@ limitations under the License. #include <iostream> #include <stdlib.h> #include "common/basic_utils.h" +#include "utl_yaml.h" #include "platform_cfg.h" #include "utl_yaml.h" @@ -165,6 +166,13 @@ void CMacYamlInfo::copy_src(char *p){ } } +uint32_t CMacYamlInfo::get_def_gw() { + return m_def_gw; +} + +uint32_t CMacYamlInfo::get_ip() { + return m_ip; +} void CMacYamlInfo::Dump(FILE *fd){ if (m_dest_base.size() != 6) { @@ -187,32 +195,54 @@ void operator >> (const YAML::Node& node, CMacYamlInfo & mac_info) { bool res; std::string mac_str; - const YAML::Node& dmac = node["dest_mac"]; - if (dmac.Type() == YAML::NodeType::Sequence) { // [1,2,3,4,5,6] - ASSERT_MSG(dmac.size() == 6, "Array of dest MAC should have 6 elements."); - for(unsigned i=0;i<dmac.size();i++) { - dmac[i] >> fi; - mac_info.m_dest_base.push_back(fi); + if (node.FindValue("dest_mac")) { + const YAML::Node& dmac = node["dest_mac"]; + if (dmac.Type() == YAML::NodeType::Sequence) { // [1,2,3,4,5,6] + ASSERT_MSG(dmac.size() == 6, "Array of dest MAC should have 6 elements."); + for(unsigned i=0;i<dmac.size();i++) { + dmac[i] >> fi; + mac_info.m_dest_base.push_back(fi); + } + } + else if (dmac.Type() == YAML::NodeType::Scalar) { // "12:34:56:78:9a:bc" + dmac >> mac_str; + res = mac2vect(mac_str, mac_info.m_dest_base); + ASSERT_MSG(res && mac_info.m_dest_base.size() == 6 + , "String of dest MAC should be in format '12:34:56:78:9a:bc'."); + } + } else { + for(unsigned i = 0; i < 6; i++) { + mac_info.m_dest_base.push_back(0); } - } - else if (dmac.Type() == YAML::NodeType::Scalar) { // "12:34:56:78:9a:bc" - dmac >> mac_str; - res = mac2vect(mac_str, mac_info.m_dest_base); - ASSERT_MSG(res && mac_info.m_dest_base.size() == 6, "String of dest MAC should be in format '12:34:56:78:9a:bc'."); } - const YAML::Node& smac = node["src_mac"]; - if (smac.Type() == YAML::NodeType::Sequence) { - ASSERT_MSG(smac.size() == 6, "Array of src MAC should have 6 elements."); - for(unsigned i=0;i<smac.size();i++) { - smac[i] >> fi; - mac_info.m_src_base.push_back(fi); + if (node.FindValue("src_mac")) { + const YAML::Node& smac = node["src_mac"]; + if (smac.Type() == YAML::NodeType::Sequence) { + ASSERT_MSG(smac.size() == 6, "Array of src MAC should have 6 elements."); + for(unsigned i=0;i<smac.size();i++) { + smac[i] >> fi; + mac_info.m_src_base.push_back(fi); + } + } + else if (smac.Type() == YAML::NodeType::Scalar) { + smac >> mac_str; + res = mac2vect(mac_str, mac_info.m_src_base); + ASSERT_MSG(res && mac_info.m_src_base.size() == 6 + , "String of src MAC should be in format '12:34:56:78:9a:bc'."); + } + } else { + for(unsigned i = 0; i < 6; i++) { + mac_info.m_src_base.push_back(0); } } - else if (smac.Type() == YAML::NodeType::Scalar) { - smac >> mac_str; - res = mac2vect(mac_str, mac_info.m_src_base); - ASSERT_MSG(res && mac_info.m_src_base.size() == 6, "String of src MAC should be in format '12:34:56:78:9a:bc'."); + + if (! utl_yaml_read_ip_addr(node, "default_gw", mac_info.m_def_gw)) { + mac_info.m_def_gw = 0; + } + + if (! utl_yaml_read_ip_addr(node, "ip", mac_info.m_ip)) { + mac_info.m_ip = 0; } } diff --git a/src/platform_cfg.h b/src/platform_cfg.h index 1b56aad2..cd01f476 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -99,10 +99,14 @@ const std::string * get_mbuf_names(void); struct CMacYamlInfo { std::vector <uint8_t> m_dest_base; std::vector <uint8_t> m_src_base; + uint32_t m_def_gw; + uint32_t m_ip; void Dump(FILE *fd); void copy_dest(char *p); void copy_src(char *p); + uint32_t get_def_gw(); + uint32_t get_ip(); 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 new file mode 100644 index 00000000..9df2ed6b --- /dev/null +++ b/src/pre_test.cpp @@ -0,0 +1,339 @@ +/* +????? +- 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. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + 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 <rte_arp.h> +#include <rte_ethdev.h> +#include <arpa/inet.h> +#include <common/Network/Packet/EthernetHeader.h> +#include "common/basic_utils.h" +#include "bp_sim.h" +#include "main_dpdk.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; + memcpy(&m_src_mac, src_mac, sizeof(m_src_mac)); + if (resolve_needed) { + m_state = CPretestPortInfo::RESOLVE_NEEDED; + } else { + m_state = CPretestPortInfo::RESOLVE_NOT_NEEDED; + } +} + +void CPretestPortInfo::set_dst_mac(const uint8_t *dst_mac) { + memcpy(&m_dst_mac, dst_mac, sizeof(m_dst_mac)); + m_state = CPretestPortInfo::RESOLVE_DONE; +} + +void CPretestPortInfo::dump(FILE *fd) { + if (m_state == INIT_NEEDED) { + return; + } + + 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); + + printf(" src MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", m_src_mac[0], m_src_mac[1], m_src_mac[2], m_src_mac[3] + , m_src_mac[4], m_src_mac[5]); + printf( " dst MAC: "); + if (m_state == RESOLVE_DONE) { + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", m_dst_mac[0], m_dst_mac[1], m_dst_mac[2], m_dst_mac[3] + , m_dst_mac[4], m_dst_mac[5]); + } else { + printf("Not resolved\n"); + } +} + +// 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; + } + + 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; +} + +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) + return; + + m_port_info[port].set_params(ip, src_mac, def_gw, resolve_needed); +} + + +int CPretest::handle_rx(int port_id, int queue_id) { + rte_mbuf_t * rx_pkts[32]; + uint16_t cnt; + int i; + + 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); + uint8_t *p = rte_pktmbuf_mtod(m, uint8_t *); + struct arp_hdr *arp; + CPretestPortInfo *port = &m_port_info[port_id]; + if (is_arp(p, pkt_size, arp)) { + if (arp->arp_op == htons(ARP_OP_REQUEST)) { + // 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 + 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]; + if ((sent_port_id < m_max_ports) && + (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; + } + } + } else { + // ARP request not to our IP. At the moment, we ignore this. + } + } else { + if (arp->arp_op == htons(ARP_OP_REPLY)) { + // 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; +} + +/* + Try to resolve def_gw address on all ports marked as needed. + Return false if failed to resolve on one of the ports + */ +bool CPretest::resolve_all() { + uint16_t port; + + // send ARP request on all ports + for (port = 0; port < m_max_ports; port++) { + if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) { + send_arp_req(port, false); + } + } + + int max_tries = 1000; + int i; + for (i = 0; i < max_tries; i++) { + bool all_resolved = true; + for (port = 0; port < m_max_ports; port++) { + if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) { + // We need to stop reading packets only if all ports are resolved. + // If we are on loopback, We might get requests on port even after it is in RESOLVE_DONE state + all_resolved = false; + } + handle_rx(port, MAIN_DPDK_DATA_Q); + if (! CGlobalInfo::m_options.preview.get_vm_one_queue_enable()) + handle_rx(port, MAIN_DPDK_RX_Q); + } + if (all_resolved) { + break; + } else { + delay(1); + } + } + + if (i == max_tries) { + return false; + } else { + return true; + } +} + +void CPretest::dump(FILE *fd) { + for (int port = 0; port < m_max_ports; port++) { + if (m_port_info[port].m_state != CPretestPortInfo::INIT_NEEDED) { + fprintf(fd, "port %d:\n", port); + m_port_info[port].dump(fd); + } + } +} + +void CPretest::send_arp_req(uint16_t port, bool is_grat) { + uint16_t pkt_size; + uint8_t *pkt; + rte_mbuf_t *m[1]; + char *p; + int num_sent; + + pkt = m_port_info[port].create_arp_req(pkt_size, port, is_grat); + m[0] = CGlobalInfo::pktmbuf_alloc(0, pkt_size); + if ( unlikely(m[0] == 0) ) { + fprintf(stderr, "ERROR: Could not allocate mbuf for sending ARP to port:%d\n", port); + 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); + if (num_sent < 1) { + fprintf(stderr, "Failed sending ARP to port:%d\n", port); + exit(1); + } +} + +/* + Send gratuitous ARP on all ports + */ +void CPretest::send_grat_arp_all() { + for (uint16_t port = 0; port < m_max_ports; port++) { + if (m_port_info[port].m_state == CPretestPortInfo::RESOLVE_NEEDED) { + send_arp_req(port, true); + } + } +} + +bool CPretest::is_arp(uint8_t *p, uint16_t pkt_size, struct arp_hdr *&arp) { + EthernetHeader *m_ether = (EthernetHeader *)p; + + if ((pkt_size < 60) || + ((m_ether->getNextProtocol() != EthernetHeader::Protocol::ARP) + && (m_ether->getNextProtocol() != EthernetHeader::Protocol::VLAN))) + return false; + + if (m_ether->getNextProtocol() == EthernetHeader::Protocol::ARP) { + arp = (struct arp_hdr *)(p + 14); + } else { + if (m_ether->getVlanProtocol() != EthernetHeader::Protocol::ARP) { + return false; + } else { + arp = (struct arp_hdr *)(p + 18); + } + } + + return true; +} + +// Should be run on setup with two interfaces connected by loopback. +// 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); + dump(stdout); + resolve_all(); + dump(stdout); + get_mac(0, ip1, found_mac); + if (memcmp(found_mac, mac1, ETHER_ADDR_LEN)) { + fprintf(stderr, "Test failed: Could not resolve def gw on port 0\n"); + exit(1); + } + + get_mac(1, ip0, found_mac); + if (memcmp(found_mac, mac0, ETHER_ADDR_LEN)) { + fprintf(stderr, "Test failed: Could not resolve def gw on port 1\n"); + exit(1); + } + + printf("Test passed\n"); + exit(0); +} diff --git a/src/pre_test.h b/src/pre_test.h new file mode 100644 index 00000000..09085329 --- /dev/null +++ b/src/pre_test.h @@ -0,0 +1,79 @@ +/* + Ido Barnea + Cisco Systems, Inc. +*/ + +/* + Copyright (c) 2016-2016 Cisco Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + 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. +*/ + +#ifndef __PRE_TEST_H__ +#define __PRE_TEST_H__ + +#include <iostream> +#include "trex_defs.h" + +class CPretestPortInfo { + friend class CPretest; + + private: + enum CPretestPortInfoStates { + INIT_NEEDED, + RESOLVE_NEEDED, + RESOLVE_DONE, + RESOLVE_NOT_NEEDED, + }; + + CPretestPortInfo() { + m_state = INIT_NEEDED; + } + 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_dst_mac(const uint8_t *dst_mac); + + private: + uint32_t m_ip; + uint32_t m_def_gw; + uint8_t m_src_mac[6]; + uint8_t m_dst_mac[6]; + enum CPretestPortInfoStates m_state; +}; + + +class CPretest { + public: + CPretest(uint16_t max_ports) { + 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 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); + void dump(FILE *fd); + void test(); + + private: + int handle_rx(int port, int queue_id); + + private: + CPretestPortInfo m_port_info[TREX_MAX_PORTS]; + uint16_t m_max_ports; +}; + +#endif |