summaryrefslogtreecommitdiffstats
path: root/src/flow_stat_parser.cpp
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-08-10 15:09:45 +0300
committerIdo Barnea <ibarnea@cisco.com>2016-08-10 15:09:45 +0300
commit92880804c194990c0a2e3201c6179b8c2f6cae7c (patch)
tree6650b767894e35b0090b7e80d8f0371d2ba0f97c /src/flow_stat_parser.cpp
parente61cecf7febc28116507221af6922e252bda89a4 (diff)
Better flow stat parser unit tests, including IPv6
Diffstat (limited to 'src/flow_stat_parser.cpp')
-rw-r--r--src/flow_stat_parser.cpp203
1 files changed, 134 insertions, 69 deletions
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;
}