aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test/test_flowperpkt.py195
-rw-r--r--test/vpp_papi_provider.py68
2 files changed, 117 insertions, 146 deletions
diff --git a/test/test_flowperpkt.py b/test/test_flowperpkt.py
index af68a69e..16fe2a3e 100644
--- a/test/test_flowperpkt.py
+++ b/test/test_flowperpkt.py
@@ -1,17 +1,13 @@
#!/usr/bin/env python
import unittest
-import socket
-import binascii
-import time
from framework import VppTestCase, VppTestRunner
from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP
-from scapy.utils import hexdump
-from util import ppp
+
class TestFlowperpkt(VppTestCase):
""" Flow-per-packet plugin: test both L2 and IP4 reporting """
@@ -22,7 +18,6 @@ class TestFlowperpkt(VppTestCase):
**Config:**
- create three PG interfaces
- - create a couple of loopback interfaces
"""
super(TestFlowperpkt, self).setUp()
@@ -37,11 +32,6 @@ class TestFlowperpkt(VppTestCase):
intf.config_ip4()
intf.resolve_arp()
- def tearDown(self):
- """Run standard test teardown"""
- super(TestFlowperpkt, self).tearDown()
-
-
def create_stream(self, src_if, dst_if, packet_sizes):
"""Create a packet stream to tickle the plugin
@@ -51,8 +41,7 @@ class TestFlowperpkt(VppTestCase):
"""
pkts = []
for size in packet_sizes:
- info = self.create_packet_info(src_if.sw_if_index,
- dst_if.sw_if_index)
+ info = self.create_packet_info(src_if, dst_if)
payload = self.info_to_payload(info)
p = (Ether(src=src_if.local_mac, dst=dst_if.remote_mac) /
IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
@@ -63,119 +52,84 @@ class TestFlowperpkt(VppTestCase):
pkts.append(p)
return pkts
+ @staticmethod
+ def compare_with_mask(payload, masked_expected_data):
+ if len(payload) * 2 != len(masked_expected_data):
+ return False
+
+ # iterate over pairs: raw byte from payload and ASCII code for that byte
+ # from masked payload (or XX if masked)
+ for i in range(len(payload)):
+ p = payload[i]
+ m = masked_expected_data[2 * i:2 * i + 2]
+ if m != "XX":
+ if "%02x" % ord(p) != m:
+ return False
+ return True
+
def verify_ipfix(self, collector_if):
"""Check the ipfix capture"""
- found_data_packet = 0
- found_template_packet = 0
- found_l2_data_packet = 0
- found_l2_template_packet = 0
+ found_data_packet = False
+ found_template_packet = False
+ found_l2_data_packet = False
+ found_l2_template_packet = False
# Scapy, of course, understands ipfix not at all...
# These data vetted by manual inspection in wireshark
# X'ed out fields are timestamps, which will absolutely
- # fail to compare. At L2, kill the pg src MAC address, which
- # is random.
-
- data_udp_string = "1283128300370000000a002fXXXXXXXX00000000000000010100001f0000000100000002ac100102ac10020200XXXXXXXXXXXXXXXX0092"
+ # fail to compare.
- template_udp_string = "12831283003c0000000a0034XXXXXXXX00000002000000010002002401000007000a0004000e000400080004000c000400050001009c000801380002"
+ data_udp_string = "1283128300370000000a002fXXXXXXXX000000000000000101"\
+ "00001f0000000100000002ac100102ac10020200XXXXXXXXXXXXXXXX0092"
- l2_data_udp_string = "12831283003c0000000a0034XXXXXXXX0000000100000001010100240000000100000002XXXXXXXXXXXX02020000ff020008XXXXXXXXXXXXXXXX0092"
+ template_udp_string = "12831283003c0000000a0034XXXXXXXX00000002000000"\
+ "010002002401000007000a0004000e000400080004000c000400050001009c00"\
+ "0801380002"
- l2_template_udp_string = "12831283003c0000000a0034XXXXXXXX00000002000000010002002401010007000a0004000e0004003800060050000601000002009c000801380002"
+ l2_data_udp_string = "12831283003c0000000a0034XXXXXXXX000000010000000"\
+ "1010100240000000100000002%s02020000ff020008XXXXXXXXXXX"\
+ "XXXXX0092" % self.pg1.local_mac.translate(None, ":")
- cap_x = "X"
- data_udp_len = len(data_udp_string)
- template_udp_len = len(template_udp_string)
- l2_data_udp_len = len(l2_data_udp_string)
- l2_template_udp_len = len(l2_template_udp_string)
+ l2_template_udp_string = "12831283003c0000000a0034XXXXXXXX00000002000"\
+ "000010002002401010007000a0004000e0004003800060050000601000002009"\
+ "c000801380002"
- self.logger.info("Look for ipfix packets on %s sw_if_index %d "
+ self.logger.info("Look for ipfix packets on %s sw_if_index %d "
% (collector_if.name, collector_if.sw_if_index))
- capture = collector_if.get_capture()
+ # expecting 4 packets on collector interface based on traffic on other
+ # interfaces
+ capture = collector_if.get_capture(4)
for p in capture:
- data_result = ""
- template_result = ""
- l2_data_result = ""
- l2_template_result = ""
- unmasked_result = ""
ip = p[IP]
udp = p[UDP]
self.logger.info("src %s dst %s" % (ip.src, ip.dst))
- self.logger.info(" udp src_port %s dst_port %s"
+ self.logger.info(" udp src_port %s dst_port %s"
% (udp.sport, udp.dport))
- # Hex-dump the UDP datagram 4 ways in parallel
- # X'ing out incomparable fields
- # Python completely bites at this sort of thing, of course
-
- x = str(udp)
- l = len(x)
- i = 0
- while i < l:
- # If current index within range
- if i < data_udp_len/2:
- # See if we're supposed to don't care the data
- if ord(data_udp_string[i*2]) == ord(cap_x[0]):
- data_result = data_result + "XX"
- else:
- data_result = data_result + ("%02x" % ord(x[i]))
- else:
- # index out of range, emit actual data
- # The test will fail, but it may help debug, etc.
- data_result = data_result + ("%02x" % ord(x[i]))
-
- if i < template_udp_len/2:
- if ord(template_udp_string[i*2]) == ord(cap_x[0]):
- template_result = template_result + "XX"
- else:
- template_result = template_result + ("%02x" % ord(x[i]))
- else:
- template_result = template_result + ("%02x" % ord(x[i]))
-
- if i < l2_data_udp_len/2:
- # See if we're supposed to don't care the data
- if ord(l2_data_udp_string[i*2]) == ord(cap_x[0]):
- l2_data_result = l2_data_result + "XX"
- else:
- l2_data_result = l2_data_result + ("%02x" % ord(x[i]))
- else:
- # index out of range, emit actual data
- # The test will fail, but it may help debug, etc.
- l2_data_result = l2_data_result + ("%02x" % ord(x[i]))
-
- if i < l2_template_udp_len/2:
- if ord(l2_template_udp_string[i*2]) == ord(cap_x[0]):
- l2_template_result = l2_template_result + "XX"
- else:
- l2_template_result = l2_template_result + ("%02x" % ord(x[i]))
- else:
- l2_template_result = l2_template_result + ("%02x" % ord(x[i]))
- # In case we need to
- unmasked_result = unmasked_result + ("%02x" % ord(x[i]))
-
- i = i + 1
-
- if data_result == data_udp_string:
- self.logger.info ("found ip4 data packet")
- found_data_packet = 1
- elif template_result == template_udp_string:
- self.logger.info ("found ip4 template packet")
- found_template_packet = 1
- elif l2_data_result == l2_data_udp_string:
- self.logger.info ("found l2 data packet")
- found_l2_data_packet = 1
- elif l2_template_result == l2_template_udp_string:
- self.logger.info ("found l2 template packet")
- found_l2_template_packet = 1
+ payload = str(udp)
+
+ if self.compare_with_mask(payload, data_udp_string):
+ self.logger.info("found ip4 data packet")
+ found_data_packet = True
+ elif self.compare_with_mask(payload, template_udp_string):
+ self.logger.info("found ip4 template packet")
+ found_template_packet = True
+ elif self.compare_with_mask(payload, l2_data_udp_string):
+ self.logger.info("found l2 data packet")
+ found_l2_data_packet = True
+ elif self.compare_with_mask(payload, l2_template_udp_string):
+ self.logger.info("found l2 template packet")
+ found_l2_template_packet = True
else:
- self.logger.info ("unknown pkt '%s'" % unmasked_result)
-
- self.assertTrue (found_data_packet == 1)
- self.assertTrue (found_template_packet == 1)
- self.assertTrue (found_l2_data_packet == 1)
- self.assertTrue (found_l2_template_packet == 1)
+ unmasked_payload = "".join(["%02x" % ord(c) for c in payload])
+ self.logger.error("unknown pkt '%s'" % unmasked_payload)
+
+ self.assertTrue(found_data_packet, "Data packet not found")
+ self.assertTrue(found_template_packet, "Template packet not found")
+ self.assertTrue(found_l2_data_packet, "L2 data packet not found")
+ self.assertTrue(found_l2_template_packet,
+ "L2 template packet not found")
def test_L3_fpp(self):
""" Flow per packet L3 test """
@@ -186,37 +140,34 @@ class TestFlowperpkt(VppTestCase):
# an ARP request
self.pg_enable_capture(self.pg_interfaces)
- self.vapi.cli("set ip arp pg2 172.16.3.2 dead.beef.0002")
- self.logger.info(self.vapi.cli("set ipfix exporter collector 172.16.3.2 src 172.16.3.1 path-mtu 1450 template-interval 1"))
+ self.pg2.configure_ipv4_neighbors()
+ self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4n,
+ src_address=self.pg2.local_ip4n,
+ path_mtu=1450,
+ template_interval=1)
# Export flow records for all pkts transmitted on pg1
-
- self.logger.info(self.vapi.cli("flowperpkt feature add-del pg1"))
- self.logger.info(self.vapi.cli("flowperpkt feature add-del pg1 l2"))
+ self.vapi.cli("flowperpkt feature add-del pg1")
+ self.vapi.cli("flowperpkt feature add-del pg1 l2")
# Arrange to minimally trace generated ipfix packets
- self.logger.info(self.vapi.cli("trace add flowperpkt-ipv4 10"))
- self.logger.info(self.vapi.cli("trace add flowperpkt-l2 10"))
+ self.vapi.cli("trace add flowperpkt-ipv4 10")
+ self.vapi.cli("trace add flowperpkt-l2 10")
# Create a stream from pg0 -> pg1, which causes
# an ipfix packet to be transmitted on pg2
-
- pkts = self.create_stream(self.pg0, self.pg1,
+
+ pkts = self.create_stream(self.pg0, self.pg1,
self.pg_if_packet_sizes)
self.pg0.add_stream(pkts)
self.pg_start()
-
+
# Flush the ipfix collector, so we don't need any
# asinine time.sleep(5) action
+ self.vapi.cli("ipfix flush") # FIXME this should be an API call
- self.logger.info(self.vapi.cli("ipfix flush"))
-
# Make sure the 4 pkts we expect actually showed up
self.verify_ipfix(self.pg2)
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
-
-
-
-
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 3279a274..bdbcc3d2 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -901,7 +901,6 @@ class VppPapiProvider(object):
miss_next_index=0xFFFFFFFF,
current_data_flag=0,
current_data_offset=0):
-
"""
:param is_add:
:param mask:
@@ -918,17 +917,17 @@ class VppPapiProvider(object):
return self.api(
self.papi.classify_add_del_table,
- {'is_add' : is_add,
- 'table_index' : table_index,
- 'nbuckets' : nbuckets,
+ {'is_add': is_add,
+ 'table_index': table_index,
+ 'nbuckets': nbuckets,
'memory_size': memory_size,
- 'skip_n_vectors' : skip_n_vectors,
- 'match_n_vectors' : match_n_vectors,
- 'next_table_index' : next_table_index,
- 'miss_next_index' : miss_next_index,
- 'current_data_flag' : current_data_flag,
- 'current_data_offset' : current_data_offset,
- 'mask' : mask})
+ 'skip_n_vectors': skip_n_vectors,
+ 'match_n_vectors': match_n_vectors,
+ 'next_table_index': next_table_index,
+ 'miss_next_index': miss_next_index,
+ 'current_data_flag': current_data_flag,
+ 'current_data_offset': current_data_offset,
+ 'mask': mask})
def classify_add_del_session(
self,
@@ -953,14 +952,14 @@ class VppPapiProvider(object):
return self.api(
self.papi.classify_add_del_session,
- {'is_add' : is_add,
- 'table_index' : table_index,
- 'hit_next_index' : hit_next_index,
- 'opaque_index' : opaque_index,
- 'advance' : advance,
- 'action' : action,
- 'metadata' : metadata,
- 'match' : match})
+ {'is_add': is_add,
+ 'table_index': table_index,
+ 'hit_next_index': hit_next_index,
+ 'opaque_index': opaque_index,
+ 'advance': advance,
+ 'action': action,
+ 'metadata': metadata,
+ 'match': match})
def input_acl_set_interface(
self,
@@ -979,8 +978,29 @@ class VppPapiProvider(object):
return self.api(
self.papi.input_acl_set_interface,
- {'sw_if_index' : sw_if_index,
- 'ip4_table_index' : ip4_table_index,
- 'ip6_table_index' : ip6_table_index,
- 'l2_table_index' : l2_table_index,
- 'is_add' : is_add})
+ {'sw_if_index': sw_if_index,
+ 'ip4_table_index': ip4_table_index,
+ 'ip6_table_index': ip6_table_index,
+ 'l2_table_index': l2_table_index,
+ 'is_add': is_add})
+
+ def set_ipfix_exporter(
+ self,
+ collector_address,
+ src_address,
+ path_mtu,
+ template_interval,
+ vrf_id=0,
+ collector_port=4739,
+ udp_checksum=0):
+ return self.api(
+ self.papi.set_ipfix_exporter,
+ {
+ 'collector_address': collector_address,
+ 'collector_port': collector_port,
+ 'src_address': src_address,
+ 'vrf_id': vrf_id,
+ 'path_mtu': path_mtu,
+ 'template_interval': template_interval,
+ 'udp_checksum': udp_checksum,
+ })