summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Barnea <ibarnea@cisco.com>2016-08-11 11:22:34 +0300
committerIdo Barnea <ibarnea@cisco.com>2016-08-11 11:22:34 +0300
commitb5c09779a55f6e0cdd08230109319e086491acdf (patch)
tree6f9fe832c8659b5ddac0015beaf3c279d51f5aac
parent92880804c194990c0a2e3201c6179b8c2f6cae7c (diff)
IPv6 Latency/flow stats on x710 - supporting all packet types
-rw-r--r--scripts/automation/regression/stateless_tests/stl_rx_test.py2
-rw-r--r--src/flow_stat_parser.cpp57
-rw-r--r--src/flow_stat_parser.h2
-rw-r--r--src/main_dpdk.cpp8
4 files changed, 47 insertions, 22 deletions
diff --git a/scripts/automation/regression/stateless_tests/stl_rx_test.py b/scripts/automation/regression/stateless_tests/stl_rx_test.py
index 9c9ce120..d447ad4e 100644
--- a/scripts/automation/regression/stateless_tests/stl_rx_test.py
+++ b/scripts/automation/regression/stateless_tests/stl_rx_test.py
@@ -55,7 +55,7 @@ class STLRX_Test(CStlGeneral_Test):
self.pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
self.ipv6pkt = STLPktBuilder(pkt = Ether()/IPv6(dst="2001:0:4137:9350:8000:f12a:b9c8:2815",src="2001:4860:0:2001::68")
- /ICMP()/('Your_paylaod_comes_here'))
+ /UDP(dport=12,sport=1025)/('Your_paylaod_comes_here'))
self.large_pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*1000))
self.pkt_9k = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/('a'*9000))
self.vm_pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")
diff --git a/src/flow_stat_parser.cpp b/src/flow_stat_parser.cpp
index 29d79b9b..2ab273a6 100644
--- a/src/flow_stat_parser.cpp
+++ b/src/flow_stat_parser.cpp
@@ -29,6 +29,8 @@
#include "flow_stat_parser.h"
void CFlowStatParser::reset() {
+ m_start = 0;
+ m_len = 0;
m_ipv4 = 0;
m_ipv6 = 0;
m_l4_proto = 0;
@@ -45,6 +47,8 @@ int CFlowStatParser::parse(uint8_t *p, uint16_t len) {
if (len < min_len)
return -1;
+ m_start = p;
+ m_len = len;
switch( ether->getNextProtocol() ) {
case EthernetHeader::Protocol::IP :
min_len += IPV4_HDR_LEN;
@@ -60,8 +64,6 @@ int CFlowStatParser::parse(uint8_t *p, uint16_t 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();
m_stat_supported = true;
break;
case EthernetHeader::Protocol::VLAN :
@@ -84,8 +86,6 @@ int CFlowStatParser::parse(uint8_t *p, uint16_t 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();
m_stat_supported = true;
break;
default:
@@ -153,7 +153,12 @@ int CFlowStatParser::get_l4_proto(uint8_t &proto) {
}
if (m_ipv6) {
- proto = m_ipv6->getNextHdr();
+ if (!m_l4) {
+ uint16_t payload_len;
+ // in IPv6 we calculate l4 proto only when running get_payload_len
+ get_payload_len(m_start, m_len, payload_len);
+ }
+ proto = m_l4_proto;
return 0;
}
@@ -187,7 +192,6 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload
uint16_t l2_header_len;
uint16_t l3_header_len;
uint16_t l4_header_len;
- uint8_t l4_proto = 0;
uint8_t *p_l3 = NULL;
uint8_t *p_l4 = NULL;
TCPHeader *p_tcp = NULL;
@@ -199,17 +203,37 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload
if (m_ipv4) {
l2_header_len = ((uint8_t *)m_ipv4) - p;
l3_header_len = m_ipv4->getHeaderLength();
- l4_proto = m_ipv4->getProtocol();
+ m_l4_proto = m_ipv4->getProtocol();
p_l3 = (uint8_t *)m_ipv4;
} else if (m_ipv6) {
- //??? fix payload calc in this case
+ uint8_t *next_header;
+ uint8_t next_header_type;
+ uint16_t len_left;
+
+ p_l3 = (uint8_t *)m_ipv6;
l2_header_len = ((uint8_t *)m_ipv6) - p;
+ next_header_type = m_ipv6->getNextHdr();
+ next_header = p_l3 + IPV6_HDR_LEN;
l3_header_len = IPV6_HDR_LEN;
- l4_proto = m_ipv6->getNextHdr();
- p_l3 = (uint8_t *)m_ipv6;
+ len_left = len - IPV6_HDR_LEN;
+ while ((next_header_type != IPPROTO_UDP) && (next_header_type != IPPROTO_TCP) &&
+ (next_header_type != IPPROTO_NONE) && (len_left >= 2)) {
+ next_header_type = next_header[0];
+ uint16_t curr_header_len = (next_header[1] + 1) * 8;
+ next_header += curr_header_len;
+ l3_header_len += curr_header_len;
+ len_left -= curr_header_len;
+ }
+ if ((next_header_type != IPPROTO_UDP) && (next_header_type != IPPROTO_TCP)) {
+ // L4 type we don't know. Assume everyting after IPv6 header is L4
+ l3_header_len = IPV6_HDR_LEN;
+ m_l4_proto = m_ipv6->getNextHdr();
+ } else {
+ m_l4_proto = next_header_type;
+ }
}
- switch (l4_proto) {
+ switch (m_l4_proto) {
case IPPROTO_UDP:
l4_header_len = 8;
break;
@@ -218,7 +242,7 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload
if ((p_l4 + TCP_HEADER_LEN) > (p + len)) {
//Not enough space for TCP header
payload_len = 0;
- return -1;
+ return -2;
}
p_tcp = (TCPHeader *)p_l4;
l4_header_len = p_tcp->getHeaderLength();
@@ -232,7 +256,7 @@ int CFlowStatParser::get_payload_len(uint8_t *p, uint16_t len, uint16_t &payload
if (len < l2_header_len + l3_header_len + l4_header_len) {
payload_len = 0;
- return -1;
+ return -3;
}
payload_len = len - l2_header_len - l3_header_len - l4_header_len;
@@ -331,10 +355,11 @@ int CFlowStatParserTest::test_one_pkt(const char *name, uint16_t ether_type, uin
printf("%s - ", name);
+ // in case of IPv6, we add rx_check header, just to make sure we now how to parse with multiple headers
if (is_vlan) {
- pkt_flags = DPF_VLAN;
+ pkt_flags = DPF_VLAN | DPF_RXCHECK;
} else {
- pkt_flags = 0;
+ pkt_flags = DPF_RXCHECK;
}
p = (uint8_t *)gen.create_test_pkt(ether_type, l4_proto, 255, TEST_IP_ID, pkt_flags, payload_len, pkt_size);
@@ -359,8 +384,6 @@ int CFlowStatParserTest::test() {
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);
diff --git a/src/flow_stat_parser.h b/src/flow_stat_parser.h
index 3f729903..78bc1e6a 100644
--- a/src/flow_stat_parser.h
+++ b/src/flow_stat_parser.h
@@ -77,6 +77,8 @@ class CFlowStatParser {
, uint32_t ip_id, uint16_t flags, int &pkt_size);
protected:
+ uint8_t *m_start;
+ uint16_t m_len;
IPHeader *m_ipv4;
IPv6Header *m_ipv6;
uint8_t *m_l4;
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index 548394dd..7a64daf3 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -5573,8 +5573,9 @@ void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t po
memset(&filter,0,sizeof(struct rte_eth_fdir_filter));
#if 0
- printf("40g::%s rules: port:%d, type:%d ttl:%d, ip_id:%x, q:%d hw index:%d\n", (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
- , port_id, type, ttl, ip_id, queue, stat_idx);
+ printf("40g::%s rules: port:%d type:%d ttl:%d ip_id:%x l4:%d q:%d hw index:%d\n"
+ , (op == RTE_ETH_FILTER_ADD) ? "add" : "del"
+ , port_id, type, ttl, ip_id, l4_proto, queue, stat_idx);
#endif
filter.action.rx_queue = queue;
@@ -5604,8 +5605,7 @@ void CTRexExtendedDriverBase40G::add_del_rules(enum rte_filter_op op, uint8_t po
case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
filter.input.flow.ipv6_flow.hop_limits=ttl;
filter.input.flow.ipv6_flow.flow_label = ip_id;
- if (l4_proto != 0)
- filter.input.flow.ipv6_flow.proto = l4_proto;
+ filter.input.flow.ipv6_flow.proto = l4_proto;
break;
}