make test: improve handling of packet captures 52/4452/5
authorKlement Sekera <ksekera@cisco.com>
Wed, 21 Dec 2016 07:50:14 +0000 (08:50 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Fri, 23 Dec 2016 17:38:33 +0000 (17:38 +0000)
Perform accounting of expected packets based on created packet infos.
Use this accounting info to automatically expect (and verify) the
correct number of packets to be captured. Automatically retry the read
of the capture file if scapy raises an exception while doing so to
handle rare cases when capture file is read while only partially
written during busy wait. Don't fail assert_nothing_captured if only
junk packets arrived.

Change-Id: I16ec2e9410ef510d313ec16b7e13c57d0b2a63f5
Signed-off-by: Klement Sekera <ksekera@cisco.com>
19 files changed:
test/framework.py
test/template_bd.py
test/test_bfd.py
test/test_classifier.py
test/test_gre.py
test/test_ip4.py
test/test_ip4_irb.py
test/test_ip6.py
test/test_l2_fib.py
test/test_l2bd.py
test/test_l2bd_multi_instance.py
test/test_l2xc.py
test/test_l2xc_multi_instance.py
test/test_lb.py
test/test_mpls.py
test/test_snat.py
test/test_span.py
test/util.py
test/vpp_pg_interface.py

index 1b745ff..324a64c 100644 (file)
@@ -10,6 +10,7 @@ from threading import Thread
 from inspect import getdoc
 from hook import StepHook, PollHook
 from vpp_pg_interface import VppPGInterface
+from vpp_sub_interface import VppSubInterface
 from vpp_lo_interface import VppLoInterface
 from vpp_papi_provider import VppPapiProvider
 from scapy.packet import Raw
@@ -63,9 +64,13 @@ class VppTestCase(unittest.TestCase):
         """List of packet infos"""
         return self._packet_infos
 
-    @packet_infos.setter
-    def packet_infos(self, value):
-        self._packet_infos = value
+    @classmethod
+    def get_packet_count_for_if_idx(cls, dst_if_index):
+        """Get the number of packet info for specified destination if index"""
+        if dst_if_index in cls._packet_count_for_dst_if_idx:
+            return cls._packet_count_for_dst_if_idx[dst_if_index]
+        else:
+            return 0
 
     @classmethod
     def instance(cls):
@@ -184,9 +189,9 @@ class VppTestCase(unittest.TestCase):
         cls.logger.info("Temporary dir is %s, shm prefix is %s",
                         cls.tempdir, cls.shm_prefix)
         cls.setUpConstants()
+        cls.reset_packet_infos()
         cls._captures = []
         cls._zombie_captures = []
-        cls.packet_infos = {}
         cls.verbose = 0
         cls.vpp_dead = False
         print(double_line_delim)
@@ -394,31 +399,37 @@ class VppTestCase(unittest.TestCase):
         if extend > 0:
             packet[Raw].load += ' ' * extend
 
-    def add_packet_info_to_list(self, info):
-        """
-        Add packet info to the testcase's packet info list
-
-        :param info: packet info
-
-        """
-        info.index = len(self.packet_infos)
-        self.packet_infos[info.index] = info
+    @classmethod
+    def reset_packet_infos(cls):
+        """ Reset the list of packet info objects and packet counts to zero """
+        cls._packet_infos = {}
+        cls._packet_count_for_dst_if_idx = {}
 
-    def create_packet_info(self, src_pg_index, dst_pg_index):
+    @classmethod
+    def create_packet_info(cls, src_if, dst_if):
         """
         Create packet info object containing the source and destination indexes
         and add it to the testcase's packet info list
 
-        :param src_pg_index: source packet-generator index
-        :param dst_pg_index: destination packet-generator index
+        :param VppInterface src_if: source interface
+        :param VppInterface dst_if: destination interface
 
         :returns: _PacketInfo object
 
         """
         info = _PacketInfo()
-        self.add_packet_info_to_list(info)
-        info.src = src_pg_index
-        info.dst = dst_pg_index
+        info.index = len(cls._packet_infos)
+        info.src = src_if.sw_if_index
+        info.dst = dst_if.sw_if_index
+        if isinstance(dst_if, VppSubInterface):
+            dst_idx = dst_if.parent.sw_if_index
+        else:
+            dst_idx = dst_if.sw_if_index
+        if dst_idx in cls._packet_count_for_dst_if_idx:
+            cls._packet_count_for_dst_if_idx[dst_idx] += 1
+        else:
+            cls._packet_count_for_dst_if_idx[dst_idx] = 1
+        cls._packet_infos[info.index] = info
         return info
 
     @staticmethod
@@ -462,10 +473,10 @@ class VppTestCase(unittest.TestCase):
             next_index = 0
         else:
             next_index = info.index + 1
-        if next_index == len(self.packet_infos):
+        if next_index == len(self._packet_infos):
             return None
         else:
-            return self.packet_infos[next_index]
+            return self._packet_infos[next_index]
 
     def get_next_packet_info_for_interface(self, src_index, info):
         """
index 01e8b85..d70648b 100644 (file)
@@ -56,10 +56,7 @@ class BridgeDomain(object):
         self.pg_start()
 
         # Pick first received frame and check if it's the non-encapsulated frame
-        out = self.pg1.get_capture()
-        self.assertEqual(len(out), 1,
-                         'Invalid number of packets on '
-                         'output: {}'.format(len(out)))
+        out = self.pg1.get_capture(1)
         pkt = out[0]
 
         # TODO: add error messages
@@ -83,10 +80,7 @@ class BridgeDomain(object):
         self.pg_start()
 
         # Pick first received frame and check if it's corectly encapsulated.
-        out = self.pg0.get_capture()
-        self.assertEqual(len(out), 1,
-                         'Invalid number of packets on '
-                         'output: {}'.format(len(out)))
+        out = self.pg0.get_capture(1)
         pkt = out[0]
         self.check_encapsulation(pkt)
 
index 87a5ea4..1ea69f5 100644 (file)
@@ -184,10 +184,10 @@ class BFDTestCase(VppTestCase):
         self.pg_enable_capture([self.pg0])
         expected_packets = 3
         self.logger.info("BFD: Waiting for %d BFD packets" % expected_packets)
-        self.wait_for_bfd_packet()
+        self.wait_for_bfd_packet(2)
         for i in range(expected_packets):
             before = time.time()
-            self.wait_for_bfd_packet()
+            self.wait_for_bfd_packet(2)
             after = time.time()
             # spec says the range should be <0.75, 1>, allow extra 0.05 margin
             # to work around timing issues
@@ -198,7 +198,7 @@ class BFDTestCase(VppTestCase):
     def test_zero_remote_min_rx(self):
         """ no packets when zero BFD RemoteMinRxInterval """
         self.pg_enable_capture([self.pg0])
-        p = self.wait_for_bfd_packet()
+        p = self.wait_for_bfd_packet(2)
         self.test_session.update(my_discriminator=randint(0, 40000000),
                                  your_discriminator=p[BFD].my_discriminator,
                                  state=BFDState.init,
@@ -216,7 +216,7 @@ class BFDTestCase(VppTestCase):
     def bfd_session_up(self):
         self.pg_enable_capture([self.pg0])
         self.logger.info("BFD: Waiting for slow hello")
-        p = self.wait_for_bfd_packet()
+        p = self.wait_for_bfd_packet(2)
         self.logger.info("BFD: Sending Init")
         self.test_session.update(my_discriminator=randint(0, 40000000),
                                  your_discriminator=p[BFD].my_discriminator,
index 0923387..302430f 100644 (file)
@@ -11,6 +11,7 @@ from scapy.layers.l2 import Ether
 from scapy.layers.inet import IP, UDP
 from util import ppp
 
+
 class TestClassifier(VppTestCase):
     """ Classifier Test Case """
 
@@ -84,8 +85,7 @@ class TestClassifier(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(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
@@ -150,8 +150,8 @@ class TestClassifier(VppTestCase):
         :param str dst_port: destination port number <0-ffff>
         """
 
-        return ('{:0>20}{:0>12}{:0>8}{:0>12}{:0>4}'.format(proto, src_ip,
-                dst_ip, src_port, dst_port)).rstrip('0')
+        return ('{:0>20}{:0>12}{:0>8}{:0>12}{:0>4}'.format(
+            proto, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
 
     @staticmethod
     def build_ip_match(proto='', src_ip='', dst_ip='',
@@ -164,11 +164,13 @@ class TestClassifier(VppTestCase):
         :param str src_port: source port number <0-ffff>
         :param str dst_port: destination port number <0-ffff>
         """
-        if src_ip: src_ip = socket.inet_aton(src_ip).encode('hex')
-        if dst_ip: dst_ip = socket.inet_aton(dst_ip).encode('hex')
+        if src_ip:
+            src_ip = socket.inet_aton(src_ip).encode('hex')
+        if dst_ip:
+            dst_ip = socket.inet_aton(dst_ip).encode('hex')
 
-        return ('{:0>20}{:0>12}{:0>8}{:0>12}{:0>4}'.format(proto, src_ip,
-                dst_ip, src_port, dst_port)).rstrip('0')
+        return ('{:0>20}{:0>12}{:0>8}{:0>12}{:0>4}'.format(
+            proto, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
 
     @staticmethod
     def build_mac_mask(dst_mac='', src_mac='', ether_type=''):
@@ -180,7 +182,7 @@ class TestClassifier(VppTestCase):
         """
 
         return ('{:0>12}{:0>12}{:0>4}'.format(dst_mac, src_mac,
-                ether_type)).rstrip('0')
+                                              ether_type)).rstrip('0')
 
     @staticmethod
     def build_mac_match(dst_mac='', src_mac='', ether_type=''):
@@ -190,11 +192,13 @@ class TestClassifier(VppTestCase):
         :param str src_mac: destination MAC address <x:x:x:x:x:x>
         :param str ether_type: ethernet type <0-ffff>
         """
-        if dst_mac: dst_mac = dst_mac.replace(':', '')
-        if src_mac: src_mac = src_mac.replace(':', '')
+        if dst_mac:
+            dst_mac = dst_mac.replace(':', '')
+        if src_mac:
+            src_mac = src_mac.replace(':', '')
 
         return ('{:0>12}{:0>12}{:0>4}'.format(dst_mac, src_mac,
-                ether_type)).rstrip('0')
+                                              ether_type)).rstrip('0')
 
     def create_classify_table(self, key, mask, data_offset=0, is_add=1):
         """Create Classify Table
@@ -206,12 +210,12 @@ class TestClassifier(VppTestCase):
             - create(1) or delete(0)
         """
         r = self.vapi.classify_add_del_table(
-                is_add,
-                binascii.unhexlify(mask),
-                match_n_vectors=(len(mask)-1)//32 + 1,
-                miss_next_index=0,
-                current_data_flag=1,
-                current_data_offset=data_offset)
+            is_add,
+            binascii.unhexlify(mask),
+            match_n_vectors=(len(mask) - 1) // 32 + 1,
+            miss_next_index=0,
+            current_data_flag=1,
+            current_data_offset=data_offset)
         self.assertIsNotNone(r, msg='No response msg for add_del_table')
         self.acl_tbl_idx[key] = r.new_table_index
 
@@ -228,12 +232,12 @@ class TestClassifier(VppTestCase):
             - create(1) or delete(0)
         """
         r = self.vapi.classify_add_del_session(
-                is_add,
-                table_index,
-                binascii.unhexlify(match),
-                opaque_index=0,
-                action=pbr_option,
-                metadata=vrfid)
+            is_add,
+            table_index,
+            binascii.unhexlify(match),
+            opaque_index=0,
+            action=pbr_option,
+            metadata=vrfid)
         self.assertIsNotNone(r, msg='No response msg for add_del_session')
 
     def input_acl_set_interface(self, intf, table_index, is_add=1):
@@ -245,9 +249,9 @@ class TestClassifier(VppTestCase):
             - enable(1) or disable(0)
         """
         r = self.vapi.input_acl_set_interface(
-                is_add,
-                intf.sw_if_index,
-                ip4_table_index=table_index)
+            is_add,
+            intf.sw_if_index,
+            ip4_table_index=table_index)
         self.assertIsNotNone(r, msg='No response msg for acl_set_interface')
 
     def test_acl_ip(self):
@@ -264,14 +268,15 @@ class TestClassifier(VppTestCase):
         self.pg0.add_stream(pkts)
 
         self.create_classify_table('ip', self.build_ip_mask(src_ip='ffffffff'))
-        self.create_classify_session(self.pg0, self.acl_tbl_idx.get('ip'),
-                self.build_ip_match(src_ip=self.pg0.remote_ip4))
+        self.create_classify_session(
+            self.pg0, self.acl_tbl_idx.get('ip'),
+            self.build_ip_match(src_ip=self.pg0.remote_ip4))
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('ip'))
 
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg1.get_capture()
+        pkts = self.pg1.get_capture(len(pkts))
         self.verify_capture(self.pg1, pkts)
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('ip'), 0)
         self.pg0.assert_nothing_captured(remark="packets forwarded")
@@ -291,16 +296,17 @@ class TestClassifier(VppTestCase):
         pkts = self.create_stream(self.pg0, self.pg2, self.pg_if_packet_sizes)
         self.pg0.add_stream(pkts)
 
-        self.create_classify_table('mac',
-                self.build_mac_mask(src_mac='ffffffffffff'), data_offset=-14)
-        self.create_classify_session(self.pg0, self.acl_tbl_idx.get('mac'),
-                self.build_mac_match(src_mac=self.pg0.remote_mac))
+        self.create_classify_table(
+            'mac', self.build_mac_mask(src_mac='ffffffffffff'), data_offset=-14)
+        self.create_classify_session(
+            self.pg0, self.acl_tbl_idx.get('mac'),
+            self.build_mac_match(src_mac=self.pg0.remote_mac))
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('mac'))
 
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg2.get_capture()
+        pkts = self.pg2.get_capture(len(pkts))
         self.verify_capture(self.pg2, pkts)
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('mac'), 0)
         self.pg0.assert_nothing_captured(remark="packets forwarded")
@@ -322,16 +328,17 @@ class TestClassifier(VppTestCase):
 
         self.create_classify_table('pbr', self.build_ip_mask(src_ip='ffffffff'))
         pbr_option = 1
-        self.create_classify_session(self.pg0, self.acl_tbl_idx.get('pbr'),
-                self.build_ip_match(src_ip=self.pg0.remote_ip4),
-                pbr_option, self.pbr_vrfid)
+        self.create_classify_session(
+            self.pg0, self.acl_tbl_idx.get('pbr'),
+            self.build_ip_match(src_ip=self.pg0.remote_ip4),
+            pbr_option, self.pbr_vrfid)
         self.config_pbr_fib_entry(self.pg3)
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('pbr'))
 
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg3.get_capture()
+        pkts = self.pg3.get_capture(len(pkts))
         self.verify_capture(self.pg3, pkts)
         self.input_acl_set_interface(self.pg0, self.acl_tbl_idx.get('pbr'), 0)
         self.pg0.assert_nothing_captured(remark="packets forwarded")
index f00e446..b131304 100644 (file)
@@ -43,8 +43,7 @@ class TestGRE(VppTestCase):
     def create_stream_ip4(self, src_if, src_ip, dst_ip):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_ip, dst=dst_ip) /
@@ -59,8 +58,7 @@ class TestGRE(VppTestCase):
                                  src_ip, dst_ip):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=tunnel_src, dst=tunnel_dst) /
@@ -77,8 +75,7 @@ class TestGRE(VppTestCase):
                                  src_ip, dst_ip):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=tunnel_src, dst=tunnel_dst) /
@@ -94,8 +91,7 @@ class TestGRE(VppTestCase):
                                   tunnel_src, tunnel_dst):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=tunnel_src, dst=tunnel_dst) /
@@ -113,8 +109,7 @@ class TestGRE(VppTestCase):
                                     tunnel_src, tunnel_dst, vlan):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=tunnel_src, dst=tunnel_dst) /
@@ -342,7 +337,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_tunneled_4o4(self.pg0, rx, tx,
                                  self.pg0.local_ip4, "1.1.1.2")
 
@@ -361,7 +356,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_decapped_4o4(self.pg0, rx, tx)
 
         #
@@ -426,7 +421,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_decapped_6o4(self.pg0, rx, tx)
 
         #
@@ -483,7 +478,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg1.get_capture()
+        rx = self.pg1.get_capture(len(tx))
         self.verify_tunneled_4o4(self.pg1, rx, tx,
                                  self.pg1.local_ip4, "2.2.2.2")
 
@@ -503,7 +498,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_decapped_4o4(self.pg0, rx, tx)
 
         #
@@ -564,7 +559,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                   self.pg0.local_ip4,
                                   "2.2.2.3")
@@ -578,7 +573,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_tunneled_l2o4(self.pg0, rx, tx,
                                   self.pg0.local_ip4,
                                   "2.2.2.2")
@@ -635,7 +630,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                     self.pg0.local_ip4,
                                     "2.2.2.3",
@@ -651,7 +646,7 @@ class TestGRE(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg0.get_capture()
+        rx = self.pg0.get_capture(len(tx))
         self.verify_tunneled_vlano4(self.pg0, rx, tx,
                                     self.pg0.local_ip4,
                                     "2.2.2.2",
index f67c3b9..df93533 100644 (file)
@@ -108,8 +108,7 @@ class TestIPv4(VppTestCase):
         pkts = []
         for i in range(0, 257):
             dst_if = self.flows[src_if][i % 2]
-            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(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
@@ -254,15 +253,13 @@ class TestIPv4FibCrud(VppTestCase):
 
         for _ in range(count):
             dst_addr = random.choice(dst_ips)
-            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(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_if.remote_ip4, dst=dst_addr) /
                  UDP(sport=1234, dport=1234) /
                  Raw(payload))
             info.data = p.copy()
-            size = random.choice(self.pg_if_packet_sizes)
             self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
             pkts.append(p)
 
@@ -270,7 +267,8 @@ class TestIPv4FibCrud(VppTestCase):
 
     def _find_ip_match(self, find_in, pkt):
         for p in find_in:
-            if self.payload_to_info(str(p[Raw])) == self.payload_to_info(str(pkt[Raw])):
+            if self.payload_to_info(str(p[Raw])) == \
+                    self.payload_to_info(str(pkt[Raw])):
                 if p[IP].src != pkt[IP].src:
                     break
                 if p[IP].dst != pkt[IP].dst:
@@ -357,7 +355,7 @@ class TestIPv4FibCrud(VppTestCase):
 
     def setUp(self):
         super(TestIPv4FibCrud, self).setUp()
-        self.packet_infos = {}
+        self.reset_packet_infos()
 
     def test_1_add_routes(self):
         """ Add 1k routes
@@ -381,10 +379,9 @@ class TestIPv4FibCrud(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg0.get_capture()
+        pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
 
-
     def test_2_del_routes(self):
         """ Delete 100 routes
 
@@ -411,7 +408,7 @@ class TestIPv4FibCrud(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg0.get_capture()
+        pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
 
     def test_3_add_new_routes(self):
@@ -446,7 +443,7 @@ class TestIPv4FibCrud(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        pkts = self.pg0.get_capture()
+        pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
 
     def test_4_del_routes(self):
index cf2bb15..bbec7ca 100644 (file)
@@ -103,8 +103,7 @@ class TestIpIrb(VppTestCase):
         pkts = []
         for i in range(0, 257):
             remote_dst_host = choice(dst_ip_if.remote_hosts)
-            info = self.create_packet_info(
-                src_ip_if.sw_if_index, dst_ip_if.sw_if_index)
+            info = self.create_packet_info(src_ip_if, dst_ip_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_ip_if.local_mac, src=src_ip_if.remote_mac) /
                  IP(src=src_ip_if.remote_ip4,
@@ -121,14 +120,13 @@ class TestIpIrb(VppTestCase):
                                packet_sizes):
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(
-                src_ip_if.sw_if_index, dst_ip_if.sw_if_index)
+            info = self.create_packet_info(src_ip_if, dst_ip_if)
             payload = self.info_to_payload(info)
 
             host = choice(src_l2_if.remote_hosts)
 
             p = (Ether(src=host.mac,
-                       dst = src_ip_if.local_mac) /
+                       dst=src_ip_if.local_mac) /
                  IP(src=host.ip4,
                     dst=dst_ip_if.remote_ip4) /
                  UDP(sport=1234, dport=1234) /
@@ -152,7 +150,6 @@ class TestIpIrb(VppTestCase):
             ip = packet[IP]
             udp = packet[IP][UDP]
             payload_info = self.payload_to_info(str(packet[IP][UDP][Raw]))
-            packet_index = payload_info.index
 
             self.assertEqual(payload_info.dst, dst_ip_sw_if_index)
 
@@ -231,8 +228,10 @@ class TestIpIrb(VppTestCase):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rcvd1 = self.pg0.get_capture()
-        rcvd2 = self.pg1.get_capture()
+        packet_count = self.get_packet_count_for_if_idx(self.loop0.sw_if_index)
+
+        rcvd1 = self.pg0.get_capture(packet_count)
+        rcvd2 = self.pg1.get_capture(packet_count)
 
         self.verify_capture(self.loop0, self.pg2, rcvd1)
         self.verify_capture(self.loop0, self.pg2, rcvd2)
@@ -259,8 +258,6 @@ class TestIpIrb(VppTestCase):
         rcvd = self.pg2.get_capture()
         self.verify_capture_l2_to_ip(self.pg2, self.loop0, rcvd)
 
-        self.assertEqual(len(stream1) + len(stream2), len(rcvd.res))
-
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index 06b15f9..e8b12f6 100644 (file)
@@ -116,8 +116,7 @@ class TestIPv6(VppTestCase):
         pkts = []
         for i in range(0, 257):
             dst_if = self.flows[src_if][i % 2]
-            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(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) /
index 4855a3e..d4ef3f4 100644 (file)
@@ -130,11 +130,8 @@ class TestL2fib(VppTestCase):
             raise
 
     def setUp(self):
-        """
-        Clear trace and packet infos before running each test.
-        """
         super(TestL2fib, self).setUp()
-        self.packet_infos = {}
+        self.reset_packet_infos()
 
     def tearDown(self):
         """
@@ -236,8 +233,7 @@ class TestL2fib(VppTestCase):
             for i in range(0, n_int):
                 dst_host = dst_hosts[i]
                 src_host = random.choice(src_hosts)
-                pkt_info = self.create_packet_info(
-                    src_if.sw_if_index, dst_if.sw_if_index)
+                pkt_info = self.create_packet_info(src_if, dst_if)
                 payload = self.info_to_payload(pkt_info)
                 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                      IP(src=src_host.ip4, dst=dst_host.ip4) /
@@ -314,7 +310,7 @@ class TestL2fib(VppTestCase):
         # Test
         # Create incoming packet streams for packet-generator interfaces for
         # deleted MAC addresses
-        self.packet_infos = {}
+        self.reset_packet_infos()
         for i in self.pg_interfaces:
             pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
             i.add_stream(pkts)
index 50720e6..30708a4 100644 (file)
@@ -99,7 +99,7 @@ class TestL2bd(VppTestCase):
         Clear trace and packet infos before running each test.
         """
         super(TestL2bd, self).setUp()
-        self.packet_infos = {}
+        self.reset_packet_infos()
 
     def tearDown(self):
         """
@@ -158,8 +158,7 @@ class TestL2bd(VppTestCase):
             dst_if = self.flows[src_if][i % 2]
             dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
             src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
-            pkt_info = self.create_packet_info(
-                src_if.sw_if_index, dst_if.sw_if_index)
+            pkt_info = self.create_packet_info(src_if, dst_if)
             payload = self.info_to_payload(pkt_info)
             p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                  IP(src=src_host.ip4, dst=dst_host.ip4) /
index 1272d76..a122622 100644 (file)
@@ -138,7 +138,6 @@ class TestL2bdMultiInst(VppTestCase):
         Clear trace and packet infos before running each test.
         """
         super(TestL2bdMultiInst, self).setUp()
-        self.packet_infos = {}
 
     def tearDown(self):
         """
@@ -243,8 +242,7 @@ class TestL2bdMultiInst(VppTestCase):
             for i in range(0, n_int):
                 dst_host = dst_hosts[i]
                 src_host = random.choice(src_hosts)
-                pkt_info = self.create_packet_info(
-                    src_if.sw_if_index, dst_if.sw_if_index)
+                pkt_info = self.create_packet_info(src_if, dst_if)
                 payload = self.info_to_payload(pkt_info)
                 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                      IP(src=src_host.ip4, dst=dst_host.ip4) /
@@ -393,17 +391,8 @@ class TestL2bdMultiInst(VppTestCase):
         for pg_if in self.pg_interfaces:
             capture = pg_if.get_capture()
             if pg_if in self.pg_in_bd:
-                if len(capture) == 0:
-                    raise RuntimeError("Interface %s is in BD but the capture "
-                                       "is empty!" % pg_if.name)
                 self.verify_capture(pg_if, capture)
-            elif pg_if in self.pg_not_in_bd:
-                try:
-                    self.assertEqual(len(capture), 0)
-                except AssertionError:
-                    raise RuntimeError("Interface %s is not in BD but "
-                                       "the capture is not empty!" % pg_if.name)
-            else:
+            elif pg_if not in self.pg_not_in_bd:
                 self.logger.error("Unknown interface: %s" % pg_if.name)
 
     def test_l2bd_inst_01(self):
index 3789304..2ec4af9 100644 (file)
@@ -77,11 +77,8 @@ class TestL2xc(VppTestCase):
             raise
 
     def setUp(self):
-        """
-        Clear trace and packet infos before running each test.
-        """
         super(TestL2xc, self).setUp()
-        self.packet_infos = {}
+        self.reset_packet_infos()
 
     def tearDown(self):
         """
@@ -123,8 +120,7 @@ class TestL2xc(VppTestCase):
             dst_if = self.flows[src_if][0]
             dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
             src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
-            pkt_info = self.create_packet_info(
-                src_if.sw_if_index, dst_if.sw_if_index)
+            pkt_info = self.create_packet_info(src_if, dst_if)
             payload = self.info_to_payload(pkt_info)
             p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                  IP(src=src_host.ip4, dst=dst_host.ip4) /
index 2e55674..6c28ceb 100644 (file)
@@ -113,7 +113,7 @@ class TestL2xcMultiInst(VppTestCase):
         Clear trace and packet infos before running each test.
         """
         super(TestL2xcMultiInst, self).setUp()
-        self.packet_infos = {}
+        self.reset_packet_infos()
 
     def tearDown(self):
         """
@@ -205,8 +205,7 @@ class TestL2xcMultiInst(VppTestCase):
             for i in range(0, n_int):
                 dst_host = dst_hosts[i]
                 src_host = random.choice(src_hosts)
-                pkt_info = self.create_packet_info(
-                    src_if.sw_if_index, dst_if.sw_if_index)
+                pkt_info = self.create_packet_info(src_if, dst_if)
                 payload = self.info_to_payload(pkt_info)
                 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
                      IP(src=src_host.ip4, dst=dst_host.ip4) /
index 9b5baae..e5802d9 100644 (file)
@@ -69,10 +69,10 @@ class TestLB(VppTestCase):
                 UDP(sport=10000 + id, dport=20000 + id))
 
     def generatePackets(self, src_if, isv4):
-        self.packet_infos = {}
+        self.reset_packet_infos()
         pkts = []
         for pktid in self.packets:
-            info = self.create_packet_info(src_if.sw_if_index, pktid)
+            info = self.create_packet_info(src_if, self.pg1)
             payload = self.info_to_payload(info)
             ip = self.getIPv4Flow(pktid) if isv4 else self.getIPv6Flow(pktid)
             packet = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
@@ -90,14 +90,13 @@ class TestLB(VppTestCase):
         self.assertEqual(gre.version, 0)
         inner = IPver(str(gre.payload))
         payload_info = self.payload_to_info(str(inner[Raw]))
-        self.info = self.get_next_packet_info_for_interface2(
-            self.pg0.sw_if_index, payload_info.dst, self.info)
+        self.info = self.packet_infos[payload_info.index]
+        self.assertEqual(payload_info.src, self.pg0.sw_if_index)
         self.assertEqual(str(inner), str(self.info.data[IPver]))
 
     def checkCapture(self, gre4, isv4):
         self.pg0.assert_nothing_captured()
-        out = self.pg1.get_capture()
-        self.assertEqual(len(out), len(self.packets))
+        out = self.pg1.get_capture(len(self.packets))
 
         load = [0] * len(self.ass)
         self.info = None
index 6d5eeb2..806e69d 100644 (file)
@@ -12,6 +12,7 @@ from scapy.layers.inet import IP, UDP, ICMP
 from scapy.layers.inet6 import IPv6
 from scapy.contrib.mpls import MPLS
 
+
 class TestMPLS(VppTestCase):
     """ MPLS Test Case """
 
@@ -44,11 +45,17 @@ class TestMPLS(VppTestCase):
         super(TestMPLS, self).tearDown()
 
     # the default of 64 matches the IP packet TTL default
-    def create_stream_labelled_ip4(self, src_if, mpls_labels, mpls_ttl=255, ping=0, ip_itf=None):
+    def create_stream_labelled_ip4(
+            self,
+            src_if,
+            mpls_labels,
+            mpls_ttl=255,
+            ping=0,
+            ip_itf=None):
+        self.reset_packet_infos()
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
 
@@ -71,10 +78,10 @@ class TestMPLS(VppTestCase):
         return pkts
 
     def create_stream_ip4(self, src_if, dst_ip):
+        self.reset_packet_infos()
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_if.remote_ip4, dst=dst_ip) /
@@ -85,10 +92,10 @@ class TestMPLS(VppTestCase):
         return pkts
 
     def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl):
+        self.reset_packet_infos()
         pkts = []
         for i in range(0, 257):
-            info = self.create_packet_info(src_if.sw_if_index,
-                                           src_if.sw_if_index)
+            info = self.create_packet_info(src_if, src_if)
             payload = self.info_to_payload(info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  MPLS(label=mpls_label, ttl=mpls_ttl) /
@@ -342,7 +349,6 @@ class TestMPLS(VppTestCase):
                                             labels=[44, 45])])
         route_34_eos.add_vpp_config()
 
-        self.vapi.cli("clear trace")
         tx = self.create_stream_labelled_ip4(self.pg0, [34])
         self.pg0.add_stream(tx)
 
@@ -628,7 +634,6 @@ class TestMPLS(VppTestCase):
         # a stream with a non-zero MPLS TTL
         # PG0 is in the default table
         #
-        self.vapi.cli("clear trace")
         tx = self.create_stream_labelled_ip4(self.pg0, [0])
         self.pg0.add_stream(tx)
 
@@ -692,9 +697,9 @@ class TestMPLS(VppTestCase):
         # A de-agg route - next-hop lookup in default table
         #
         route_34_eos = MplsRoute(self, 34, 1,
-                                  [RoutePath("0.0.0.0",
-                                             0xffffffff,
-                                             nh_table_id=0)])
+                                 [RoutePath("0.0.0.0",
+                                            0xffffffff,
+                                            nh_table_id=0)])
         route_34_eos.add_vpp_config()
 
         #
@@ -716,9 +721,9 @@ class TestMPLS(VppTestCase):
         # A de-agg route - next-hop lookup in non-default table
         #
         route_35_eos = MplsRoute(self, 35, 1,
-                                  [RoutePath("0.0.0.0",
-                                             0xffffffff,
-                                             nh_table_id=1)])
+                                 [RoutePath("0.0.0.0",
+                                            0xffffffff,
+                                            nh_table_id=1)])
         route_35_eos.add_vpp_config()
 
         #
@@ -727,13 +732,15 @@ class TestMPLS(VppTestCase):
         # default table and egress unlabelled in the non-default
         #
         self.vapi.cli("clear trace")
-        tx = self.create_stream_labelled_ip4(self.pg0, [35], ping=1, ip_itf=self.pg1)
+        tx = self.create_stream_labelled_ip4(
+            self.pg0, [35], ping=1, ip_itf=self.pg1)
         self.pg0.add_stream(tx)
 
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
 
-        rx = self.pg1.get_capture()
+        packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
+        rx = self.pg1.get_capture(packet_count)
         self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
 
         route_35_eos.remove_vpp_config()
index 8985c3e..ca2e52a 100644 (file)
@@ -241,7 +241,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in
@@ -249,7 +249,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
     def test_static_in(self):
@@ -270,7 +270,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture, nat_ip, True)
 
         # out2in
@@ -278,7 +278,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
     def test_static_out(self):
@@ -299,7 +299,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
         # in2out
@@ -307,7 +307,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture, nat_ip, True)
 
     def test_static_with_port_in(self):
@@ -333,7 +333,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in
@@ -341,7 +341,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
     def test_static_with_port_out(self):
@@ -367,7 +367,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
         # in2out
@@ -375,7 +375,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
     def test_static_vrf_aware(self):
@@ -401,7 +401,7 @@ class TestSNAT(VppTestCase):
         self.pg4.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture, nat_ip1, True)
 
         # inside interface VRF don't match SNAT static mapping VRF (packets
@@ -427,7 +427,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 1st interface
@@ -435,7 +435,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
+        capture = self.pg0.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg0)
 
         # in2out 2nd interface
@@ -443,7 +443,7 @@ class TestSNAT(VppTestCase):
         self.pg1.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 2nd interface
@@ -451,7 +451,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg1.get_capture()
+        capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg1)
 
         # in2out 3rd interface
@@ -459,7 +459,7 @@ class TestSNAT(VppTestCase):
         self.pg2.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 3rd interface
@@ -467,7 +467,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg2.get_capture()
+        capture = self.pg2.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg2)
 
     def test_inside_overlapping_interfaces(self):
@@ -485,7 +485,7 @@ class TestSNAT(VppTestCase):
         self.pg4.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 1st interface
@@ -493,7 +493,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg4.get_capture()
+        capture = self.pg4.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg4)
 
         # in2out 2nd interface
@@ -501,7 +501,7 @@ class TestSNAT(VppTestCase):
         self.pg5.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 2nd interface
@@ -509,7 +509,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg5.get_capture()
+        capture = self.pg5.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg5)
 
         # in2out 3rd interface
@@ -517,7 +517,7 @@ class TestSNAT(VppTestCase):
         self.pg6.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg3.get_capture()
+        capture = self.pg3.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
         # out2in 3rd interface
@@ -525,7 +525,7 @@ class TestSNAT(VppTestCase):
         self.pg3.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg6.get_capture()
+        capture = self.pg6.get_capture(len(pkts))
         self.verify_capture_in(capture, self.pg6)
 
     def test_hairpinning(self):
@@ -553,8 +553,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
-        self.assertEqual(1, len(capture))
+        capture = self.pg0.get_capture(1)
         p = capture[0]
         try:
             ip = p[IP]
@@ -575,8 +574,7 @@ class TestSNAT(VppTestCase):
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
-        capture = self.pg0.get_capture()
-        self.assertEqual(1, len(capture))
+        capture = self.pg0.get_capture(1)
         p = capture[0]
         try:
             ip = p[IP]
@@ -613,8 +611,7 @@ class TestSNAT(VppTestCase):
         self.pg_start()
 
         # verify number of translated packet
-        capture = self.pg1.get_capture()
-        self.assertEqual(pkts_num, len(capture))
+        self.pg1.get_capture(pkts_num)
 
     def tearDown(self):
         super(TestSNAT, self).tearDown()
index e42fbd7..4150709 100644 (file)
@@ -85,8 +85,7 @@ class TestSpan(VppTestCase):
         pkts = []
         for i in range(0, TestSpan.pkts_per_burst):
             dst_if = self.flows[src_if][0]
-            pkt_info = self.create_packet_info(
-                src_if.sw_if_index, dst_if.sw_if_index)
+            pkt_info = self.create_packet_info(src_if, dst_if)
             payload = self.info_to_payload(pkt_info)
             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
                  IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
@@ -184,9 +183,11 @@ class TestSpan(VppTestCase):
         # Verify packets outgoing packet streams on mirrored interface (pg2)
         self.logger.info("Verifying capture on interfaces %s and %s" %
                          (self.pg1.name, self.pg2.name))
-        self.verify_capture(self.pg1,
-                            self.pg1.get_capture(),
-                            self.pg2.get_capture())
+        pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
+        self.verify_capture(
+            self.pg1,
+            self.pg1.get_capture(),
+            self.pg2.get_capture(pg2_expected))
 
 
 if __name__ == '__main__':
index 0ac2376..6658feb 100644 (file)
@@ -24,17 +24,14 @@ def ppc(headline, capture, limit=10):
     """
     if not capture:
         return headline
-    result = headline + "\n"
-    count = 1
-    for p in capture:
-        result.append(ppp("Packet #%s:" % count, p))
-        count += 1
-        if count >= limit:
-            break
+    tail = ""
     if limit < len(capture):
-        result.append(
-            "Capture contains %s packets in total, of which %s were printed" %
-            (len(capture), limit))
+        tail = "\nPrint limit reached, %s out of %s packets printed" % (
+            len(capture), limit)
+        limit = len(capture)
+    body = "".join([ppp("Packet #%s:" % count, p)
+                    for count, p in zip(range(0, limit), capture)])
+    return "%s\n%s%s" % (headline, body, tail)
 
 
 class NumericConstant(object):
index 634d7d3..f430527 100644 (file)
@@ -1,5 +1,6 @@
 import os
 import time
+from traceback import format_exc
 from scapy.utils import wrpcap, rdpcap, PcapReader
 from vpp_interface import VppInterface
 
@@ -130,30 +131,20 @@ class VppPGInterface(VppInterface):
         # FIXME this should be an API, but no such exists atm
         self.test.vapi.cli(self.input_cli)
 
-    def get_capture(self, remark=None, filter_fn=is_ipv6_misc):
-        """
-        Get captured packets
-
-        :param remark: remark printed into debug logs
-        :param filter_fn: filter applied to each packet, packets for which
-                          the filter returns True are removed from capture
-        :returns: iterable packets
-        """
+    def _get_capture(self, timeout, filter_out_fn=is_ipv6_misc):
+        """ Helper method to get capture and filter it """
         try:
-            self.wait_for_capture_file()
+            if not self.wait_for_capture_file(timeout):
+                return None
             output = rdpcap(self.out_path)
             self.test.logger.debug("Capture has %s packets" % len(output.res))
-        except IOError:  # TODO
-            self.test.logger.debug("File %s does not exist, probably because no"
-                                   " packets arrived" % self.out_path)
-            if remark:
-                raise Exception("No packets captured on %s(%s)" %
-                                (self.name, remark))
-            else:
-                raise Exception("No packets captured on %s" % self.name)
+        except:
+            self.test.logger.debug("Exception in scapy.rdpcap(%s): %s" %
+                                   (self.out_path, format_exc()))
+            return None
         before = len(output.res)
-        if filter_fn:
-            output.res = [p for p in output.res if not filter_fn(p)]
+        if filter_out_fn:
+            output.res = [p for p in output.res if not filter_out_fn(p)]
         removed = len(output.res) - before
         if removed:
             self.test.logger.debug(
@@ -161,21 +152,75 @@ class VppPGInterface(VppInterface):
                 (removed, len(output.res)))
         return output
 
-    def assert_nothing_captured(self, remark=None):
+    def get_capture(self, expected_count=None, remark=None, timeout=1,
+                    filter_out_fn=is_ipv6_misc):
+        """ Get captured packets
+
+        :param expected_count: expected number of packets to capture, if None,
+                               then self.test.packet_count_for_dst_pg_idx is
+                               used to lookup the expected count
+        :param remark: remark printed into debug logs
+        :param timeout: how long to wait for packets
+        :param filter_out_fn: filter applied to each packet, packets for which
+                              the filter returns True are removed from capture
+        :returns: iterable packets
+        """
+        remaining_time = timeout
+        capture = None
+        name = self.name if remark is None else "%s (%s)" % (self.name, remark)
+        based_on = "based on provided argument"
+        if expected_count is None:
+            expected_count = \
+                self.test.get_packet_count_for_if_idx(self.sw_if_index)
+            based_on = "based on stored packet_infos"
+        self.test.logger.debug("Expecting to capture %s(%s) packets on %s" % (
+            expected_count, based_on, name))
+        if expected_count == 0:
+            raise Exception(
+                "Internal error, expected packet count for %s is 0!" % name)
+        while remaining_time > 0:
+            before = time.time()
+            capture = self._get_capture(remaining_time, filter_out_fn)
+            elapsed_time = time.time() - before
+            if capture:
+                if len(capture.res) == expected_count:
+                    # bingo, got the packets we expected
+                    return capture
+            remaining_time -= elapsed_time
+        if capture:
+            raise Exception("Captured packets mismatch, captured %s packets, "
+                            "expected %s packets on %s" %
+                            (len(capture.res), expected_count, name))
+        else:
+            raise Exception("No packets captured on %s" % name)
+
+    def assert_nothing_captured(self, remark=None, filter_out_fn=is_ipv6_misc):
+        """ Assert that nothing unfiltered was captured on interface
+
+        :param remark: remark printed into debug logs
+        :param filter_out_fn: filter applied to each packet, packets for which
+                              the filter returns True are removed from capture
+        """
         if os.path.isfile(self.out_path):
             try:
-                capture = self.get_capture(remark=remark)
+                capture = self.get_capture(
+                    0, remark=remark, filter_out_fn=filter_out_fn)
+                if capture:
+                    if len(capture.res) == 0:
+                        # junk filtered out, we're good
+                        return
                 self.test.logger.error(
                     ppc("Unexpected packets captured:", capture))
             except:
                 pass
             if remark:
                 raise AssertionError(
-                    "Capture file present for interface %s(%s)" %
+                    "Non-empty capture file present for interface %s(%s)" %
                     (self.name, remark))
             else:
-                raise AssertionError("Capture file present for interface %s" %
-                                     self.name)
+                raise AssertionError(
+                    "Non-empty capture file present for interface %s" %
+                    self.name)
 
     def wait_for_capture_file(self, timeout=1):
         """
@@ -183,15 +228,17 @@ class VppPGInterface(VppInterface):
 
         :param timeout: How long to wait for the packet (default 1s)
 
-        :raises Exception: if the capture file does not appear within timeout
+        :returns: True/False if the file is present or appears within timeout
         """
         limit = time.time() + timeout
         if not os.path.isfile(self.out_path):
-            self.test.logger.debug(
-                "Waiting for capture file to appear, timeout is %ss", timeout)
+            self.test.logger.debug("Waiting for capture file %s to appear, "
+                                   "timeout is %ss" % (self.out_path, timeout))
         else:
-            self.test.logger.debug("Capture file already exists")
-            return
+            self.test.logger.debug(
+                "Capture file %s already exists" %
+                self.out_path)
+            return True
         while time.time() < limit:
             if os.path.isfile(self.out_path):
                 break
@@ -201,9 +248,10 @@ class VppPGInterface(VppInterface):
                                    (time.time() - (limit - timeout)))
         else:
             self.test.logger.debug("Timeout - capture file still nowhere")
-            raise Exception("Capture file did not appear within timeout")
+            return False
+        return True
 
-    def wait_for_packet(self, timeout):
+    def wait_for_packet(self, timeout, filter_out_fn=is_ipv6_misc):
         """
         Wait for next packet captured with a timeout
 
@@ -212,18 +260,34 @@ class VppPGInterface(VppInterface):
         :returns: Captured packet if no packet arrived within timeout
         :raises Exception: if no packet arrives within timeout
         """
-        limit = time.time() + timeout
+        deadline = time.time() + timeout
         if self._pcap_reader is None:
-            self.wait_for_capture_file(timeout)
-            self._pcap_reader = PcapReader(self.out_path)
+            if not self.wait_for_capture_file(timeout):
+                raise Exception("Capture file %s did not appear within "
+                                "timeout" % self.out_path)
+            while time.time() < deadline:
+                try:
+                    self._pcap_reader = PcapReader(self.out_path)
+                    break
+                except:
+                    self.test.logger.debug("Exception in scapy.PcapReader(%s): "
+                                           "%s" % (self.out_path, format_exc()))
+        if not self._pcap_reader:
+            raise Exception("Capture file %s did not appear within "
+                            "timeout" % self.out_path)
 
         self.test.logger.debug("Waiting for packet")
-        while time.time() < limit:
+        while time.time() < deadline:
             p = self._pcap_reader.recv()
             if p is not None:
-                self.test.logger.debug("Packet received after %fs",
-                                       (time.time() - (limit - timeout)))
-                return p
+                if filter_out_fn is not None and filter_out_fn(p):
+                    self.test.logger.debug(
+                        "Packet received after %ss was filtered out" %
+                        (time.time() - (deadline - timeout)))
+                else:
+                    self.test.logger.debug("Packet received after %fs" %
+                                           (time.time() - (deadline - timeout)))
+                    return p
             time.sleep(0)  # yield
         self.test.logger.debug("Timeout - no packets received")
         raise Exception("Packet didn't arrive within timeout")
@@ -258,12 +322,12 @@ class VppPGInterface(VppInterface):
         self.test.pg_start()
         self.test.logger.info(self.test.vapi.cli("show trace"))
         try:
-            arp_reply = pg_interface.get_capture(filter_fn=None)
+            captured_packet = pg_interface.wait_for_packet(1)
         except:
             self.test.logger.info("No ARP received on port %s" %
                                   pg_interface.name)
             return
-        arp_reply = arp_reply[0]
+        arp_reply = captured_packet.copy()  # keep original for exception
         # Make Dot1AD packet content recognizable to scapy
         if arp_reply.type == 0x88a8:
             arp_reply.type = 0x8100
@@ -274,19 +338,19 @@ class VppPGInterface(VppInterface):
                                       (self.name, arp_reply[ARP].hwsrc))
                 self._local_mac = arp_reply[ARP].hwsrc
             else:
-                self.test.logger.info(
-                    "No ARP received on port %s" %
-                    pg_interface.name)
+                self.test.logger.info("No ARP received on port %s" %
+                                      pg_interface.name)
         except:
             self.test.logger.error(
-                ppp("Unexpected response to ARP request:", arp_reply))
+                ppp("Unexpected response to ARP request:", captured_packet))
             raise
 
-    def resolve_ndp(self, pg_interface=None):
+    def resolve_ndp(self, pg_interface=None, timeout=1):
         """Resolve NDP using provided packet-generator interface
 
         :param pg_interface: interface used to resolve, if None then this
             interface is used
+        :param timeout: how long to wait for response before giving up
 
         """
         if pg_interface is None:
@@ -297,17 +361,19 @@ class VppPGInterface(VppInterface):
         pg_interface.add_stream(ndp_req)
         pg_interface.enable_capture()
         self.test.pg_start()
-        self.test.logger.info(self.test.vapi.cli("show trace"))
-        replies = pg_interface.get_capture(filter_fn=None)
-        if replies is None or len(replies) == 0:
-            self.test.logger.info(
-                "No NDP received on port %s" %
-                pg_interface.name)
-            return
+        now = time.time()
+        deadline = now + timeout
         # Enabling IPv6 on an interface can generate more than the
         # ND reply we are looking for (namely MLD). So loop through
         # the replies to look for want we want.
-        for ndp_reply in replies:
+        while now < deadline:
+            try:
+                captured_packet = pg_interface.wait_for_packet(
+                    deadline - now, filter_out_fn=None)
+            except:
+                self.test.logger.error("Timeout while waiting for NDP response")
+                raise
+            ndp_reply = captured_packet.copy()  # keep original for exception
             # Make Dot1AD packet content recognizable to scapy
             if ndp_reply.type == 0x88a8:
                 ndp_reply.type = 0x8100
@@ -318,9 +384,13 @@ class VppPGInterface(VppInterface):
                 self.test.logger.info("VPP %s MAC address is %s " %
                                       (self.name, opt.lladdr))
                 self._local_mac = opt.lladdr
+                self.test.logger.debug(self.test.vapi.cli("show trace"))
+                # we now have the MAC we've been after
+                return
             except:
                 self.test.logger.info(
-                    ppp("Unexpected response to NDP request:", ndp_reply))
-        # if no packets above provided the local MAC, then this failed.
-        if not hasattr(self, '_local_mac'):
-            raise
+                    ppp("Unexpected response to NDP request:", captured_packet))
+            now = time.time()
+
+        self.test.logger.debug(self.test.vapi.cli("show trace"))
+        raise Exception("Timeout while waiting for NDP response")