Better flow stat parser unit tests, including IPv6
authorIdo Barnea <[email protected]>
Wed, 10 Aug 2016 12:09:45 +0000 (15:09 +0300)
committerIdo Barnea <[email protected]>
Wed, 10 Aug 2016 12:09:45 +0000 (15:09 +0300)
linux/ws_main.py
linux_dpdk/ws_main.py
src/debug.cpp
src/flow_stat_parser.cpp
src/flow_stat_parser.h
src/gtest/trex_stateless_gtest.cpp
src/test_pkt_gen.cpp [new file with mode: 0644]
src/test_pkt_gen.h [new file with mode: 0644]

index 66d79d1..b1704e5 100755 (executable)
@@ -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',
index e6feb21..9e07da0 100755 (executable)
@@ -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',
index dd07cd0..3cb4e3c 100644 (file)
 #include <rte_pci.h>
 #include <rte_ethdev.h>
 #include <common/basic_utils.h>
-#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) {
index deae706..29d79b9 100644 (file)
@@ -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;
 }
index 8ec5a22..3f72990 100644 (file)
@@ -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
index 3525471..376d245 100644 (file)
@@ -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 (file)
index 0000000..b16eca3
--- /dev/null
@@ -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 <assert.h>
+#include <netinet/in.h>
+#include <common/Network/Packet/TcpHeader.h>
+#include <common/Network/Packet/UdpHeader.h>
+#include <common/Network/Packet/IcmpHeader.h>
+#include <common/Network/Packet/IPHeader.h>
+#include <common/Network/Packet/IPv6Header.h>
+#include <common/Network/Packet/EthernetHeader.h>
+#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 (file)
index 0000000..f4ac3a8
--- /dev/null
@@ -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