From 92880804c194990c0a2e3201c6179b8c2f6cae7c Mon Sep 17 00:00:00 2001 From: Ido Barnea Date: Wed, 10 Aug 2016 15:09:45 +0300 Subject: Better flow stat parser unit tests, including IPv6 --- linux/ws_main.py | 1 + linux_dpdk/ws_main.py | 1 + src/debug.cpp | 204 +++----------------------------- src/flow_stat_parser.cpp | 203 +++++++++++++++++++++----------- src/flow_stat_parser.h | 28 ++++- src/gtest/trex_stateless_gtest.cpp | 4 +- src/test_pkt_gen.cpp | 232 +++++++++++++++++++++++++++++++++++++ src/test_pkt_gen.h | 46 ++++++++ 8 files changed, 459 insertions(+), 260 deletions(-) create mode 100644 src/test_pkt_gen.cpp create mode 100644 src/test_pkt_gen.h diff --git a/linux/ws_main.py b/linux/ws_main.py index 66d79d13..b1704e5e 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -113,6 +113,7 @@ main_src = SrcGroup(dir='src', 'rx_check_header.cpp', 'nat_check.cpp', 'nat_check_flow_table.cpp', + 'test_pkt_gen.cpp', 'timer_wheel_pq.cpp', 'time_histogram.cpp', 'utl_json.cpp', diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index e6feb219..9e07da05 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -110,6 +110,7 @@ main_src = SrcGroup(dir='src', 'tuple_gen.cpp', 'rx_check.cpp', 'rx_check_header.cpp', + 'test_pkt_gen.cpp', 'timer_wheel_pq.cpp', 'time_histogram.cpp', 'os_time.cpp', diff --git a/src/debug.cpp b/src/debug.cpp index dd07cd05..3cb4e3cb 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -27,26 +27,10 @@ #include #include #include -#include "rx_check_header.h" +#include "test_pkt_gen.h" #include "main_dpdk.h" #include "debug.h" -enum { - D_PKT_TYPE_ICMP = 1, - D_PKT_TYPE_UDP = 2, - D_PKT_TYPE_TCP = 3, - D_PKT_TYPE_9k_UDP = 4, - D_PKT_TYPE_IPV6 = 60, - D_PKT_TYPE_HW_VERIFY = 100, - -}; - -enum { - DPF_VLAN = 0x1, - DPF_QINQ = 0X2, - DPF_RXCHECK = 0x4 -}; - const uint8_t udp_pkt[] = { 0x00,0x00,0x00,0x01,0x00,0x00, 0x00,0x00,0x00,0x01,0x00,0x00, @@ -133,194 +117,40 @@ rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t t } #else -// For playing around, and testing packet sending in debug mode rte_mbuf_t *CTrexDebug::create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t ttl , uint32_t ip_id, uint16_t flags) { - int pkt_size = 0; - // ASA 2 - uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25}; - uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02}; - uint8_t vlan_header[4] = {0x0a, 0xbc, 0x00, 0x00}; // we set the type below according to if pkt is ipv4 or 6 - uint8_t vlan_header2[4] = {0x0a, 0xbc, 0x88, 0xa8}; - uint16_t l2_proto; - // ASA 1A - // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b}; - // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0}; - if (flags & DPF_VLAN) { - l2_proto = 0x0081; - } else { - if (ip_ver == 4) - l2_proto = 0x0008; - else // IPV6 - l2_proto = 0xdd86; - } + int pkt_size; + char *pkt; + rte_mbuf_t *m; + char *p; + CTestPktGen gen; + uint16_t l3_type; - uint8_t ip_header[] = { - 0x45,0x02,0x00,0x30, - 0x00,0x00,0x40,0x00, - 0xff,0x01,0xbd,0x04, - 0x10,0x0,0x0,0x1, //SIP - 0x30,0x0,0x0,0x1, //DIP - // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it. - }; - uint8_t ipv6_header[] = { - 0x60,0x00,0xff,0x30, // traffic class + flow label - 0x00,0x00,0x40,0x00, // payload len + next header + hop limit - 0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP - 0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP - }; - uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00}; - uint8_t udp_data[] = {0x64,0x31,0x3a,0x61, - 0x64,0x32,0x3a,0x69,0x64, - 0x32,0x30,0x3a,0xd0,0x0e, - 0xa1,0x4b,0x7b,0xbd,0xbd, - 0x16,0xc6,0xdb,0xc4,0xbb,0x43, - 0xf9,0x4b,0x51,0x68,0x33,0x72, - 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, - 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, - 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, - 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, - 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, - 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, - 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, - 0xe7 - }; - - uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num - 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size - 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer - }; - - uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5, - 0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5}; - - uint8_t icmp_header[] = { - 0x08, 0x00, - 0xb8, 0x21, //checksum - 0xaa, 0xbb, // id - 0x00, 0x01, // Sequence number - }; - uint8_t icmp_data[] = { - 0xd6, 0x6e, 0x64, 0x34, // magic - 0x6a, 0xad, 0x0f, 0x00, //64 bit counter - 0x00, 0x56, 0x34, 0x12, - 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq - }; - - pkt_size = 14; - switch(ip_ver) { + switch (ip_ver) { case 4: - pkt_size += sizeof(ip_header); + l3_type = EthernetHeader::Protocol::IP; break; case 6: - pkt_size += sizeof(ipv6_header); - if (flags & DPF_RXCHECK) { - pkt_size += sizeof(struct CRx_check_header); - } - break; - default: - printf("Internal error. Wrong ip_ver\n"); - exit(-1); - } - - switch (l4_proto) { - case IPPROTO_ICMP: - pkt_size += sizeof(icmp_header) + sizeof (icmp_data); - break; - case IPPROTO_UDP: - pkt_size += sizeof(udp_header) + sizeof (udp_data); - break; - case IPPROTO_TCP: - pkt_size += sizeof(tcp_header) + sizeof (tcp_data); + l3_type = EthernetHeader::Protocol::IPv6; break; default: return NULL; + break; } - rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(0, pkt_size); + pkt = gen.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"); return (NULL); } - char *p = rte_pktmbuf_append(m, pkt_size); - assert(p); - - /* set pkt data */ - memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac); - memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac); - memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto); - - if (flags & DPF_VLAN) { - if (flags & DPF_QINQ) { - memcpy(p, &vlan_header2, sizeof(vlan_header2)); p += sizeof(vlan_header2); - } - if (ip_ver == 4) { - vlan_header[2] = 0x08; - vlan_header[3] = 0x00; - } else { - vlan_header[2] = 0x86; - vlan_header[3] = 0xdd; - } - memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header); - } - - struct IPHeader *ip = (IPHeader *)p; - struct IPv6Header *ipv6 = (IPv6Header *)p; - if (ip_ver == 4) { - memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header); - ip->setProtocol(l4_proto); - ip->setTotalLength(pkt_size - 14); - ip->setId(ip_id); - } else { - memcpy(p, ipv6_header, sizeof(ipv6_header)); p += sizeof(ipv6_header); - if (flags & DPF_RXCHECK) { - // rx check header - ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE); - if (flags & DPF_RXCHECK) { - struct CRx_check_header *rxch = (struct CRx_check_header *)p; - p += sizeof(CRx_check_header); - rxch->m_option_type = l4_proto; - rxch->m_option_len = RX_CHECK_V6_OPT_LEN; - } - } else { - ipv6->setNextHdr(l4_proto); - } - ipv6->setPayloadLen(pkt_size - 14 - sizeof(ipv6_header)); - ipv6->setFlowLabel(ip_id); - } - - struct TCPHeader *tcp = (TCPHeader *)p; - struct ICMPHeader *icmp= (ICMPHeader *)p; - switch (l4_proto) { - case IPPROTO_ICMP: - memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header); - memcpy(p, icmp_data, sizeof(icmp_data)); p += sizeof(icmp_data); - icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data)); - break; - case IPPROTO_UDP: - memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header); - memcpy(p, udp_data, sizeof(udp_data)); p += sizeof(udp_data); - break; - case IPPROTO_TCP: - memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header); - memcpy(p, tcp_data, sizeof(tcp_data)); p += sizeof(tcp_data); - tcp->setSynFlag(false); - // printf("Sending TCP header:"); - //tcp->dump(stdout); - break; - default: - return NULL; - } + p = rte_pktmbuf_append(m, pkt_size); + memcpy(p, pkt, pkt_size); + free(pkt); - if (ip_ver == 4) { - ip->setTimeToLive(ttl); - ip->updateCheckSum(); - } else { - ipv6->setHopLimit(ttl); - } return m; } + #endif rte_mbuf_t *CTrexDebug::create_pkt(uint8_t *pkt, int pkt_size) { diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp index deae7062..29d79b9b 100644 --- a/src/flow_stat_parser.cpp +++ b/src/flow_stat_parser.cpp @@ -25,6 +25,7 @@ #include "common/Network/Packet/IPHeader.h" #include "common/Network/Packet/IPv6Header.h" #include "common/Network/Packet/TcpHeader.h" +#include "test_pkt_gen.h" #include "flow_stat_parser.h" void CFlowStatParser::reset() { @@ -38,7 +39,7 @@ void CFlowStatParser::reset() { int CFlowStatParser::parse(uint8_t *p, uint16_t len) { EthernetHeader *ether = (EthernetHeader *)p; - int min_len = ETH_HDR_LEN + IPV4_HDR_LEN; + int min_len = ETH_HDR_LEN; reset(); if (len < min_len) @@ -46,12 +47,18 @@ int CFlowStatParser::parse(uint8_t *p, uint16_t len) { switch( ether->getNextProtocol() ) { case EthernetHeader::Protocol::IP : + min_len += IPV4_HDR_LEN; + if (len < min_len) + return -1; m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN); m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength(); m_l4_proto = m_ipv4->getProtocol(); m_stat_supported = true; break; case EthernetHeader::Protocol::IPv6 : + min_len += IPV6_HDR_LEN; + if (len < min_len) + return -1; m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN); m_l4 = ((uint8_t *)m_ipv6) + m_ipv6->getHeaderLength(); m_l4_proto = m_ipv6->getNextHdr(); @@ -64,12 +71,18 @@ int CFlowStatParser::parse(uint8_t *p, uint16_t len) { return -1; switch ( ether->getVlanProtocol() ){ case EthernetHeader::Protocol::IP: + min_len += IPV4_HDR_LEN; + if (len < min_len) + return -1; m_ipv4 = (IPHeader *)(p + ETH_HDR_LEN + 4); m_l4 = ((uint8_t *)m_ipv4) + m_ipv4->getHeaderLength(); m_l4_proto = m_ipv4->getProtocol(); m_stat_supported = true; break; case EthernetHeader::Protocol::IPv6 : + min_len += IPV6_HDR_LEN; + if (len < min_len) + return -1; m_ipv6 = (IPv6Header *)(p + ETH_HDR_LEN + 4); m_l4 = ((uint8_t *)m_ipv6) + m_ipv6->getHeaderLength(); m_l4_proto = m_ipv6->getNextHdr(); @@ -169,7 +182,7 @@ uint8_t CFlowStatParser::get_ttl(){ } // calculate the payload len. Do not want to do this in parse(), since this is required only in -// specific cases, while parse is used in many places (including on packet RX path, where we want to bo as fast as possible) +// specific cases, while parse is used in many places (including on packet RX path, where we want to be as fast as possible) int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len) { uint16_t l2_header_len; uint16_t l3_header_len; @@ -189,6 +202,7 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload l4_proto = m_ipv4->getProtocol(); p_l3 = (uint8_t *)m_ipv4; } else if (m_ipv6) { + //??? fix payload calc in this case l2_header_len = ((uint8_t *)m_ipv6) - p; l3_header_len = IPV6_HDR_LEN; l4_proto = m_ipv6->getNextHdr(); @@ -227,78 +241,129 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload } static const uint16_t TEST_IP_ID = 0xabcd; +static const uint16_t TEST_IP_ID2 = 0xabcd; static const uint8_t TEST_L4_PROTO = IPPROTO_UDP; -int CFlowStatParser::test() { - uint32_t ip_id = 0; - uint8_t l4_proto; - uint8_t test_pkt[] = { - // ether header - 0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25, - 0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02, - 0x81, 0x00, - 0x0a, 0xbc, 0x08, 0x00, // vlan - // IP header - 0x45,0x02,0x00,0x30, - 0x01,0x02,0x40,0x00, - 0xff, TEST_L4_PROTO, 0xbd,0x04, - 0x10,0x0,0x0,0x1, - 0x30,0x0,0x0,0x1, - // TCP heaader - 0xab, 0xcd, 0x00, 0x80, // src, dst ports - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num - 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size - 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer - // some extra bytes - 0x1, 0x2, 0x3, 0x4 - }; - - // good packet - assert (parse(test_pkt, sizeof(test_pkt)) == 0); - m_ipv4->updateCheckSum(); - assert(m_ipv4->isChecksumOK() == true); - set_ip_id(TEST_IP_ID); - // utl_DumpBuffer(stdout, test_pkt, sizeof(test_pkt), 0); - get_ip_id(ip_id); - assert(ip_id == TEST_IP_ID); - assert(m_ipv4->isChecksumOK() == true); - assert(get_l4_proto(l4_proto) == 0); - assert(l4_proto == TEST_L4_PROTO); - assert(m_stat_supported == true); - - // payload len test - uint16_t payload_len; + +int CFlowStatParserTest::verify_pkt_one_parser(uint8_t * p, uint16_t pkt_size, uint16_t payload_len, uint32_t ip_id + , uint8_t l4_proto, CFlowStatParser &parser, bool sup_pkt) { int ret; - ret = get_payload_len(test_pkt, sizeof(test_pkt), payload_len); - // UDP packet. - assert(ret == 0); - assert(payload_len == 16); - reset(); - // ICMP packet - test_pkt[27] = IPPROTO_ICMP; - assert (parse(test_pkt, sizeof(test_pkt)) == 0); - ret = get_payload_len(test_pkt, sizeof(test_pkt), payload_len); - assert(ret == 0); - assert(payload_len == 16); - // TCP packet - test_pkt[27] = IPPROTO_TCP; - assert (parse(test_pkt, sizeof(test_pkt)) == 0); - ret = get_payload_len(test_pkt, sizeof(test_pkt), payload_len); - assert(ret == 0); - assert(payload_len == 4); - // Other protocol - test_pkt[27] = 0xaa; - assert (parse(test_pkt, sizeof(test_pkt)) == 0); - ret = get_payload_len(test_pkt, sizeof(test_pkt), payload_len); - assert(ret == 0); - assert(payload_len == 24); + uint32_t pkt_ip_id = 0; + uint8_t pkt_l4_proto; + uint16_t pkt_payload_len; + + ret = parser.parse(p, pkt_size); + if (sup_pkt) { + assert (ret == 0); + parser.get_ip_id(pkt_ip_id); + assert(pkt_ip_id == ip_id); + parser.set_ip_id(TEST_IP_ID2); + // utl_DumpBuffer(stdout, test_pkt, sizeof(test_pkt), 0); + parser.get_ip_id(ip_id); + assert(ip_id == TEST_IP_ID2); + if (parser.m_ipv4) + assert(parser.m_ipv4->isChecksumOK() == true); + assert(parser.get_l4_proto(pkt_l4_proto) == 0); + assert(pkt_l4_proto == l4_proto); + assert(parser.m_stat_supported == true); + ret = parser.get_payload_len(p, pkt_size, pkt_payload_len); + assert(ret == 0); + assert(pkt_payload_len == payload_len); + } else { + assert(ret != 0); + assert(parser.m_stat_supported == false); + } - reset(); + return 0; +} + +int CFlowStatParserTest::verify_pkt(uint8_t *p, uint16_t pkt_size, uint16_t payload_len, uint32_t ip_id, uint8_t l4_proto + , uint16_t flags) { + int ret, ret_val; + CFlowStatParser parser; + C82599Parser parser82599(false); + C82599Parser parser82599_vlan(true); + + printf (" "); + if ((flags & P_OK) || (flags & P_BAD)) { + printf("general parser"); + ret = verify_pkt_one_parser(p, pkt_size, payload_len, ip_id, l4_proto, parser, flags & P_OK); + ret_val = ret; + if (ret == 0) + printf("-OK"); + else { + printf("-BAD"); + } + } + if ((flags & P82599_OK) || (flags & P82599_BAD)) { + printf(", 82599 parser"); + ret = verify_pkt_one_parser(p, pkt_size, payload_len, ip_id, l4_proto, parser82599, flags & P82599_OK); + ret_val |= ret; + if (ret == 0) + printf("-OK"); + else { + printf("-BAD"); + } + } + if ((flags & P82599_VLAN_OK) || (flags & P82599_VLAN_BAD)) { + printf(", 82599 vlan parser"); + ret = verify_pkt_one_parser(p, pkt_size, payload_len, ip_id, l4_proto, parser82599_vlan, flags & P82599_VLAN_OK); + ret_val |= ret; + if (ret == 0) + printf("-OK"); + else { + printf("-BAD"); + } + } + printf("\n"); + + return 0; +} + +int CFlowStatParserTest::test_one_pkt(const char *name, uint16_t ether_type, uint8_t l4_proto, bool is_vlan + , uint16_t verify_flags) { + CTestPktGen gen; + uint8_t *p; + int pkt_size; + uint16_t payload_len = 16; + uint16_t pkt_flags; + int ret = 0; + + printf("%s - ", name); + + if (is_vlan) { + pkt_flags = DPF_VLAN; + } else { + pkt_flags = 0; + } + + p = (uint8_t *)gen.create_test_pkt(ether_type, l4_proto, 255, TEST_IP_ID, pkt_flags, payload_len, pkt_size); + ret = verify_pkt(p, pkt_size, payload_len, TEST_IP_ID, l4_proto, verify_flags); + free(p); + + return ret; +} - // bad packet. change eth protocol - test_pkt[16] = 0xaa; - assert (parse(test_pkt, sizeof(test_pkt)) == -1); - assert(m_stat_supported == false); +int CFlowStatParserTest::test() { + bool vlan = true; + uint8_t tcp = IPPROTO_TCP, udp = IPPROTO_UDP, icmp = IPPROTO_ICMP; + uint16_t ipv4 = EthernetHeader::Protocol::IP, ipv6 = EthernetHeader::Protocol::IPv6; + + test_one_pkt("IPv4 TCP", ipv4, tcp, !vlan, P_OK | P82599_OK | P82599_VLAN_BAD); + test_one_pkt("IPv4 TCP VLAN", ipv4, tcp, vlan, P_OK | P82599_BAD | P82599_VLAN_OK); + test_one_pkt("IPv4 UDP", ipv4, udp, !vlan, P_OK | P82599_OK | P82599_VLAN_BAD); + test_one_pkt("IPv4 UDP VLAN", ipv4, udp, vlan, P_OK | P82599_BAD | P82599_VLAN_OK); + test_one_pkt("IPv4 ICMP", ipv4, icmp, !vlan, P_OK | P82599_OK | P82599_VLAN_BAD); + test_one_pkt("IPv4 ICMP VLAN", ipv4, icmp, vlan, P_OK | P82599_BAD | P82599_VLAN_OK); + test_one_pkt("IPv6 TCP", ipv6, tcp, !vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv6 TCP VLAN", ipv6, tcp, vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv6 UDP", ipv6, udp, !vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv6 UDP VLAN", ipv6, udp, vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv6 ICMP", ipv6, icmp, !vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv6 ICMP VLAN", ipv6, icmp, vlan, P_OK | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("IPv4 IGMP", ipv4, IPPROTO_IGMP, !vlan, P_OK | P82599_OK | P82599_VLAN_BAD); + test_one_pkt("BAD l3 type", 0xaa, icmp, !vlan, P_BAD | P82599_BAD | P82599_VLAN_BAD); + test_one_pkt("VLAN + BAD l3 type", 0xaa, icmp, vlan, P_BAD | P82599_BAD | P82599_VLAN_BAD); return 0; } diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h index 8ec5a229..3f729903 100644 --- a/src/flow_stat_parser.h +++ b/src/flow_stat_parser.h @@ -30,6 +30,7 @@ // Basic flow stat parser. Relevant for xl710/x710/x350 cards class CFlowStatParser { + friend class CFlowStatParserTest; public: virtual ~CFlowStatParser() {} virtual void reset(); @@ -42,7 +43,6 @@ class CFlowStatParser { virtual int get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload_len); virtual uint16_t get_pkt_size(); virtual uint8_t get_ttl(); - virtual int test(); uint8_t *get_l3() { if (m_ipv4) return (uint8_t *)m_ipv4; @@ -72,6 +72,10 @@ class CFlowStatParser { return true; } + private: + char *create_test_pkt(int ip_ver, uint16_t l4_proto, uint8_t ttl + , uint32_t ip_id, uint16_t flags, int &pkt_size); + protected: IPHeader *m_ipv4; IPv6Header *m_ipv6; @@ -132,7 +136,27 @@ class CSimplePacketParser { uint16_t m_vlan_offset; uint8_t * m_l4; private: - rte_mbuf_t * m_m ; + rte_mbuf_t * m_m; +}; + +class CFlowStatParserTest { + enum { + P_OK = 0x1, + P_BAD = 0x2, + P82599_OK = 0x4, + P82599_BAD = 0x8, + P82599_VLAN_OK = 0x10, + P82599_VLAN_BAD = 0x20, + }; + + public: + int test(); + + private: + int test_one_pkt(const char *name, uint16_t ether_type, uint8_t l4_proto, bool is_vlan, uint16_t verify_flags); + int verify_pkt(uint8_t *p, uint16_t pkt_size, uint16_t payload_len, uint32_t ip_id, uint8_t l4_proto, uint16_t flags); + int verify_pkt_one_parser(uint8_t * p, uint16_t pkt_size, uint16_t payload_len, uint32_t ip_id, uint8_t l4_proto + , CFlowStatParser &parser, bool sup_pkt); }; #endif diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 35254713..376d2454 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -3719,8 +3719,8 @@ class flow_stat_pkt_parse : public testing::Test { }; -TEST_F(flow_stat_pkt_parse, x710_parser) { - CFlowStatParser parser; +TEST_F(flow_stat_pkt_parse, parser) { + CFlowStatParserTest parser; parser.test(); } diff --git a/src/test_pkt_gen.cpp b/src/test_pkt_gen.cpp new file mode 100644 index 00000000..b16eca37 --- /dev/null +++ b/src/test_pkt_gen.cpp @@ -0,0 +1,232 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include "rx_check_header.h" +#include "test_pkt_gen.h" + +// For use in tests +char *CTestPktGen::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) { + // ASA 2 + uint8_t dst_mac[6] = {0x74, 0xa2, 0xe6, 0xd5, 0x39, 0x25}; + uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x02}; + uint8_t vlan_header[4] = {0x0a, 0xbc, 0x00, 0x00}; // we set the type below according to if pkt is ipv4 or 6 + uint8_t vlan_header2[4] = {0x0a, 0xbc, 0x88, 0xa8}; + uint16_t l2_proto; + uint16_t payload_len; + + // ASA 1 + // uint8_t dst_mac[6] = {0xd4, 0x8c, 0xb5, 0xc9, 0x54, 0x2b}; + // uint8_t src_mac[6] = {0xa0, 0x36, 0x9f, 0x38, 0xa4, 0x0}; + if (flags & DPF_VLAN) { + l2_proto = 0x0081; + } else { + l2_proto = htons(l3_type); + } + + uint8_t ip_header[] = { + 0x45,0x02,0x00,0x30, + 0x00,0x00,0x40,0x00, + 0xff,0x01,0xbd,0x04, + 0x10,0x0,0x0,0x1, //SIP + 0x30,0x0,0x0,0x1, //DIP + // 0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IP option. change 45 to 48 (header len) if using it. + }; + uint8_t ipv6_header[] = { + 0x60,0x00,0xff,0x30, // traffic class + flow label + 0x00,0x00,0x40,0x00, // payload len + next header + hop limit + 0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //SIP + 0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1,0x30,0x0,0x0,0x1,0x10,0x0,0x0,0x1, //DIP + }; + uint8_t udp_header[] = {0x11, 0x11, 0x11,0x11, 0x00, 0x6d, 0x00, 0x00}; + uint8_t udp_data[] = {0x64,0x31,0x3a,0x61, + 0x64,0x32,0x3a,0x69,0x64, + 0x32,0x30,0x3a,0xd0,0x0e, + 0xa1,0x4b,0x7b,0xbd,0xbd, + 0x16,0xc6,0xdb,0xc4,0xbb,0x43, + 0xf9,0x4b,0x51,0x68,0x33,0x72, + 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, + 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, + 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, + 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, + 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, + 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, + 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, + 0xe7 + }; + + uint8_t tcp_header[] = {0xab, 0xcd, 0x00, 0x80, // src, dst ports + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // seq num, ack num + 0x50, 0x00, 0xff, 0xff, // Header size, flags, window size + 0x00, 0x00, 0x00, 0x00, // checksum ,urgent pointer + }; + + uint8_t tcp_data[] = {0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5, + 0x8, 0xa, 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x6, 0x5}; + + uint8_t icmp_header[] = { + 0x08, 0x00, + 0xb8, 0x21, //checksum + 0xaa, 0xbb, // id + 0x00, 0x01, // Sequence number + }; + uint8_t icmp_data[] = { + 0xd6, 0x6e, 0x64, 0x34, // magic + 0x6a, 0xad, 0x0f, 0x00, //64 bit counter + 0x00, 0x56, 0x34, 0x12, + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00 // seq + }; + + pkt_size = 14; + + if (flags & DPF_VLAN) { + pkt_size += 4; + if (flags & DPF_QINQ) { + pkt_size += 4; + } + } + + switch(l3_type) { + case EthernetHeader::Protocol::IP: + pkt_size += sizeof(ip_header); + break; + case EthernetHeader::Protocol::IPv6: + pkt_size += sizeof(ipv6_header); + if (flags & DPF_RXCHECK) { + pkt_size += sizeof(struct CRx_check_header); + } + break; + } + + switch (l4_proto) { + case IPPROTO_ICMP: + pkt_size += sizeof(icmp_header); + payload_len = (max_payload < sizeof(icmp_data)) ? max_payload:sizeof(icmp_data); + pkt_size += payload_len; + break; + case IPPROTO_UDP: + pkt_size += sizeof(udp_header); + payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); + pkt_size += payload_len; + break; + case IPPROTO_TCP: + pkt_size += sizeof(tcp_header); + payload_len = (max_payload < sizeof(tcp_data)) ? max_payload:sizeof(tcp_data); + pkt_size += payload_len; + break; + default: + payload_len = (max_payload < sizeof(udp_data)) ? max_payload:sizeof(udp_data); + pkt_size += payload_len; + break; + } + + char *p_start = (char *)malloc(pkt_size); + assert(p_start); + char *p = p_start; + + /* set pkt data */ + memcpy(p, dst_mac, sizeof(dst_mac)); p += sizeof(dst_mac); + memcpy(p, src_mac, sizeof(src_mac)); p += sizeof(src_mac); + memcpy(p, &l2_proto, sizeof(l2_proto)); p += sizeof(l2_proto); + + if (flags & DPF_VLAN) { + if (flags & DPF_QINQ) { + memcpy(p, &vlan_header2, sizeof(vlan_header2)); p += sizeof(vlan_header2); + } + + uint16_t l3_type_htons = htons(l3_type); + memcpy(&vlan_header[2], &l3_type_htons, sizeof(l3_type)); + memcpy(p, &vlan_header, sizeof(vlan_header)); p += sizeof(vlan_header); + } + + struct IPHeader *ip = (IPHeader *)p; + struct IPv6Header *ipv6 = (IPv6Header *)p; + switch(l3_type) { + case EthernetHeader::Protocol::IP: + memcpy(p, ip_header, sizeof(ip_header)); p += sizeof(ip_header); + ip->setProtocol(l4_proto); + ip->setTotalLength(pkt_size - 14); + ip->setId(ip_id); + break; + case EthernetHeader::Protocol::IPv6: + memcpy(p, ipv6_header, sizeof(ipv6_header)); p += sizeof(ipv6_header); + if (flags & DPF_RXCHECK) { + // rx check header + ipv6->setNextHdr(RX_CHECK_V6_OPT_TYPE); + if (flags & DPF_RXCHECK) { + struct CRx_check_header *rxch = (struct CRx_check_header *)p; + p += sizeof(CRx_check_header); + rxch->m_option_type = l4_proto; + rxch->m_option_len = RX_CHECK_V6_OPT_LEN; + } + } else { + ipv6->setNextHdr(l4_proto); + } + ipv6->setPayloadLen(pkt_size - 14 - sizeof(ipv6_header)); + ipv6->setFlowLabel(ip_id); + break; + } + + + struct TCPHeader *tcp = (TCPHeader *)p; + struct ICMPHeader *icmp= (ICMPHeader *)p; + switch (l4_proto) { + case IPPROTO_ICMP: + memcpy(p, icmp_header, sizeof(icmp_header)); p += sizeof(icmp_header); + memcpy(p, icmp_data, payload_len); p += payload_len; + icmp->updateCheckSum(sizeof(icmp_header) + sizeof(icmp_data)); + break; + case IPPROTO_UDP: + memcpy(p, udp_header, sizeof(udp_header)); p += sizeof(udp_header); + memcpy(p, udp_data, payload_len); p += payload_len; + break; + case IPPROTO_TCP: + memcpy(p, tcp_header, sizeof(tcp_header)); p += sizeof(tcp_header); + memcpy(p, tcp_data, payload_len); p += payload_len; + tcp->setSynFlag(false); + // printf("Sending TCP header:"); + //tcp->dump(stdout); + break; + default: + memcpy(p, udp_data, payload_len); p += payload_len; + break; + } + + switch(l3_type) { + case EthernetHeader::Protocol::IP: + ip->setTimeToLive(ttl); + ip->updateCheckSum(); + break; + case EthernetHeader::Protocol::IPv6: + ipv6->setHopLimit(ttl); + break; + } + + return p_start; +} diff --git a/src/test_pkt_gen.h b/src/test_pkt_gen.h new file mode 100644 index 00000000..f4ac3a83 --- /dev/null +++ b/src/test_pkt_gen.h @@ -0,0 +1,46 @@ +/* + 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 __TEST_PKT_GEN_H__ +#define __TEST_PKT_GEN_H__ + +enum { + D_PKT_TYPE_ICMP = 1, + D_PKT_TYPE_UDP = 2, + D_PKT_TYPE_TCP = 3, + D_PKT_TYPE_9k_UDP = 4, + D_PKT_TYPE_IPV6 = 60, + D_PKT_TYPE_HW_VERIFY = 100, +}; + +enum { + DPF_VLAN = 0x1, + DPF_QINQ = 0X2, + DPF_RXCHECK = 0x4 +}; + +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); +}; + +#endif -- cgit 1.2.3-korg