tests: make tests less make dependent
[vpp.git] / test / test_bfd.py
index 85b8ffe..d1c7b92 100644 (file)
@@ -4,23 +4,28 @@
 from __future__ import division
 
 import binascii
+from collections import namedtuple
 import hashlib
+import ipaddress
+import reprlib
 import time
 import unittest
 from random import randint, shuffle, getrandbits
 from socket import AF_INET, AF_INET6, inet_ntop
 from struct import pack, unpack
 
-from six import moves
 import scapy.compat
 from scapy.layers.inet import UDP, IP
 from scapy.layers.inet6 import IPv6
 from scapy.layers.l2 import Ether, GRE
 from scapy.packet import Raw
 
+from config import config
 from bfd import VppBFDAuthKey, BFD, BFDAuthType, VppBFDUDPSession, \
     BFDDiagCode, BFDState, BFD_vpp_echo
-from framework import VppTestCase, VppTestRunner, running_extended_tests
+from framework import tag_fixme_vpp_workers
+from framework import VppTestCase, VppTestRunner
+from framework import tag_run_solo
 from util import ppp
 from vpp_ip import DpoProto
 from vpp_ip_route import VppIpRoute, VppRoutePath
@@ -139,6 +144,34 @@ class BFDAPITestCase(VppTestCase):
                           "required min receive interval")
         self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
 
+    def test_upd_bfd(self):
+        """ Create/Modify w/ Update BFD session parameters """
+        session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4,
+                                   desired_min_tx=50000,
+                                   required_min_rx=10000,
+                                   detect_mult=1)
+        session.upd_vpp_config()
+        s = session.get_bfd_udp_session_dump_entry()
+        self.assert_equal(session.desired_min_tx,
+                          s.desired_min_tx,
+                          "desired min transmit interval")
+        self.assert_equal(session.required_min_rx,
+                          s.required_min_rx,
+                          "required min receive interval")
+
+        self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
+        session.upd_vpp_config(desired_min_tx=session.desired_min_tx * 2,
+                               required_min_rx=session.required_min_rx * 2,
+                               detect_mult=session.detect_mult * 2)
+        s = session.get_bfd_udp_session_dump_entry()
+        self.assert_equal(session.desired_min_tx,
+                          s.desired_min_tx,
+                          "desired min transmit interval")
+        self.assert_equal(session.required_min_rx,
+                          s.required_min_rx,
+                          "required min receive interval")
+        self.assert_equal(session.detect_mult, s.detect_mult, "detect mult")
+
     def test_add_sha1_keys(self):
         """ add SHA1 keys """
         key_count = 10
@@ -209,7 +242,7 @@ class BFDAPITestCase(VppTestCase):
             session.add_vpp_config()
 
     def test_shared_sha1_key(self):
-        """ share single SHA1 key between multiple BFD sessions """
+        """ single SHA1 key shared by multiple BFD sessions """
         key = self.factory.create_random_key(self)
         key.add_vpp_config()
         sessions = [
@@ -283,8 +316,8 @@ class BFDAPITestCase(VppTestCase):
         self.assertFalse(echo_source.have_usable_ip6)
 
         self.loopback0.config_ip4()
-        unpacked = unpack("!L", self.loopback0.local_ip4n)
-        echo_ip4 = pack("!L", unpacked[0] ^ 1)
+        echo_ip4 = ipaddress.IPv4Address(int(ipaddress.IPv4Address(
+            self.loopback0.local_ip4)) ^ 1).packed
         echo_source = self.vapi.bfd_udp_get_echo_source()
         self.assertTrue(echo_source.is_set)
         self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
@@ -293,9 +326,9 @@ class BFDAPITestCase(VppTestCase):
         self.assertFalse(echo_source.have_usable_ip6)
 
         self.loopback0.config_ip6()
-        unpacked = unpack("!LLLL", self.loopback0.local_ip6n)
-        echo_ip6 = pack("!LLLL", unpacked[0], unpacked[1], unpacked[2],
-                        unpacked[3] ^ 1)
+        echo_ip6 = ipaddress.IPv6Address(int(ipaddress.IPv6Address(
+            self.loopback0.local_ip6)) ^ 1).packed
+
         echo_source = self.vapi.bfd_udp_get_echo_source()
         self.assertTrue(echo_source.is_set)
         self.assertEqual(echo_source.sw_if_index, self.loopback0.sw_if_index)
@@ -342,6 +375,10 @@ class BFDTestSession(object):
         self.state = BFDState.down
         self.auth_type = BFDAuthType.no_auth
         self.tunnel_header = tunnel_header
+        self.tx_packets = 0
+        self.rx_packets = 0
+        self.tx_packets_echo = 0
+        self.rx_packets_echo = 0
 
     def inc_seq_num(self):
         """ increment sequence number, wrapping if needed """
@@ -464,6 +501,7 @@ class BFDTestSession(object):
             interface = self.phy_interface
         self.test.logger.debug(ppp("Sending packet:", packet))
         interface.add_stream(packet)
+        self.tx_packets += 1
         self.test.pg_start()
 
     def verify_sha1_auth(self, packet):
@@ -546,7 +584,7 @@ def bfd_session_up(test):
         test.test_session.inc_seq_num()
     test.test_session.send_packet()
     test.logger.info("BFD: Waiting for event")
-    e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
+    e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
     verify_event(test, e, expected_state=BFDState.up)
     test.logger.info("BFD: Session is Up")
     test.test_session.update(state=BFDState.up)
@@ -566,7 +604,7 @@ def bfd_session_down(test):
         test.test_session.inc_seq_num()
     test.test_session.send_packet()
     test.logger.info("BFD: Waiting for event")
-    e = test.vapi.wait_for_event(1, "bfd_udp_session_details")
+    e = test.vapi.wait_for_event(1, "bfd_udp_session_event")
     verify_event(test, e, expected_state=BFDState.down)
     test.logger.info("BFD: Session is Down")
     test.assert_equal(test.vpp_session.state, BFDState.down, BFDState)
@@ -623,7 +661,7 @@ def verify_udp(test, packet):
 def verify_event(test, event, expected_state):
     """ Verify correctness of event values. """
     e = event
-    test.logger.debug("BFD: Event: %s" % moves.reprlib.repr(e))
+    test.logger.debug("BFD: Event: %s" % reprlib.repr(e))
     test.assert_equal(e.sw_if_index,
                       test.vpp_session.interface.sw_if_index,
                       "BFD interface index")
@@ -654,6 +692,7 @@ def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
         if time_left < 0:
             raise CaptureTimeoutError("Packet did not arrive within timeout")
         p = test.pg0.wait_for_packet(timeout=time_left)
+        test.test_session.rx_packets += 1
         test.logger.debug(ppp("BFD: Got packet:", p))
         if pcap_time_min is not None and p.time < pcap_time_min:
             test.logger.debug(ppp("BFD: ignoring packet (pcap time %s < "
@@ -676,6 +715,34 @@ def wait_for_bfd_packet(test, timeout=1, pcap_time_min=None, is_tunnel=False):
     return p
 
 
+BFDStats = namedtuple("BFDStats", "rx rx_echo tx tx_echo")
+
+
+def bfd_grab_stats_snapshot(test, bs_idx=0, thread_index=None):
+    s = test.statistics
+    ti = thread_index
+    if ti is None:
+        rx = s['/bfd/rx-session-counters'][:, bs_idx].sum_packets()
+        rx_echo = s['/bfd/rx-session-echo-counters'][:, bs_idx].sum_packets()
+        tx = s['/bfd/tx-session-counters'][:, bs_idx].sum_packets()
+        tx_echo = s['/bfd/tx-session-echo-counters'][:, bs_idx].sum_packets()
+    else:
+        rx = s['/bfd/rx-session-counters'][ti, bs_idx].sum_packets()
+        rx_echo = s['/bfd/rx-session-echo-counters'][ti, bs_idx].sum_packets()
+        tx = s['/bfd/tx-session-counters'][ti, bs_idx].sum_packets()
+        tx_echo = s['/bfd/tx-session-echo-counters'][ti, bs_idx].sum_packets()
+    return BFDStats(rx, rx_echo, tx, tx_echo)
+
+
+def bfd_stats_diff(stats_before, stats_after):
+    rx = stats_after.rx - stats_before.rx
+    rx_echo = stats_after.rx_echo - stats_before.rx_echo
+    tx = stats_after.tx - stats_before.tx
+    tx_echo = stats_after.tx_echo - stats_before.tx_echo
+    return BFDStats(rx, rx_echo, tx, tx_echo)
+
+
+@tag_run_solo
 class BFD4TestCase(VppTestCase):
     """Bidirectional Forwarding Detection (BFD)"""
 
@@ -713,6 +780,8 @@ class BFD4TestCase(VppTestCase):
         self.vapi.want_bfd_events()
         self.pg0.enable_capture()
         try:
+            self.bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions']
+            self.bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions']
             self.vpp_session = VppBFDUDPSession(self, self.pg0,
                                                 self.pg0.remote_ip4)
             self.vpp_session.add_vpp_config()
@@ -731,6 +800,10 @@ class BFD4TestCase(VppTestCase):
     def test_session_up(self):
         """ bring BFD session up """
         bfd_session_up(self)
+        bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions']
+        bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions']
+        self.assert_equal(bfd_udp4_sessions - self.bfd_udp4_sessions, 1)
+        self.assert_equal(bfd_udp6_sessions, self.bfd_udp6_sessions)
 
     def test_session_up_by_ip(self):
         """ bring BFD session up - first frame looked up by address pair """
@@ -746,12 +819,12 @@ class BFD4TestCase(VppTestCase):
         self.test_session.update(your_discriminator=p[BFD].my_discriminator,
                                  state=BFDState.up)
         self.logger.info("BFD: Waiting for event")
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.init)
         self.logger.info("BFD: Sending Up")
         self.test_session.send_packet()
         self.logger.info("BFD: Waiting for event")
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.up)
         self.logger.info("BFD: Session is Up")
         self.test_session.update(state=BFDState.up)
@@ -816,7 +889,7 @@ class BFD4TestCase(VppTestCase):
         detection_time = self.test_session.detect_mult *\
             self.vpp_session.required_min_rx / USEC_IN_SEC
         self.sleep(detection_time, "waiting for BFD session time-out")
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.down)
 
     def test_peer_discr_reset_sess_down(self):
@@ -913,7 +986,7 @@ class BFD4TestCase(VppTestCase):
                 self.vpp_session.required_min_rx) / USEC_IN_SEC
         self.test_session.send_packet(final)
         time_mark = time.time()
-        e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(2 * timeout, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.down)
         time_to_event = time.time() - time_mark
         self.assert_in_range(time_to_event, .9 * timeout,
@@ -953,7 +1026,7 @@ class BFD4TestCase(VppTestCase):
             self.vpp_session.required_min_rx / USEC_IN_SEC
         before = time.time()
         e = self.vapi.wait_for_event(
-            2 * detection_time, "bfd_udp_session_details")
+            2 * detection_time, "bfd_udp_session_event")
         after = time.time()
         self.assert_in_range(after - before,
                              0.9 * detection_time,
@@ -1050,7 +1123,7 @@ class BFD4TestCase(VppTestCase):
                          "Poll bit set in BFD packet")
 
     # returning inconsistent results requiring retries in per-patch tests
-    @unittest.skipUnless(running_extended_tests, "part of extended tests")
+    @unittest.skipUnless(config.extended, "part of extended tests")
     def test_poll_response(self):
         """ test correct response to control frame with poll bit set """
         bfd_session_up(self)
@@ -1089,8 +1162,8 @@ class BFD4TestCase(VppTestCase):
 
     def test_echo_looped_back(self):
         """ echo packets looped back """
-        # don't need a session in this case..
-        self.vpp_session.remove_vpp_config()
+        bfd_session_up(self)
+        stats_before = bfd_grab_stats_snapshot(self)
         self.pg0.enable_capture()
         echo_packet_count = 10
         # random source port low enough to increment a few times..
@@ -1109,7 +1182,10 @@ class BFD4TestCase(VppTestCase):
             self.logger.debug(ppp("Sending packet:", echo_packet))
             self.pg0.add_stream(echo_packet)
             self.pg_start()
-        for dummy in range(echo_packet_count):
+            self.logger.debug(self.vapi.ppcli("show trace"))
+        counter = 0
+        bfd_control_packets_rx = 0
+        while counter < echo_packet_count:
             p = self.pg0.wait_for_packet(1)
             self.logger.debug(ppp("Got packet:", p))
             ether = p[Ether]
@@ -1118,8 +1194,11 @@ class BFD4TestCase(VppTestCase):
             self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
             ip = p[IP]
             self.assert_equal(self.pg0.remote_ip4, ip.dst, "Destination IP")
-            self.assert_equal(self.pg0.remote_ip4, ip.src, "Destination IP")
             udp = p[UDP]
+            if udp.dport == BFD.udp_dport:
+                bfd_control_packets_rx += 1
+                continue
+            self.assert_equal(self.pg0.remote_ip4, ip.src, "Source IP")
             self.assert_equal(udp.dport, BFD.udp_dport_echo,
                               "UDP destination port")
             self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
@@ -1129,12 +1208,23 @@ class BFD4TestCase(VppTestCase):
             self.assertEqual(scapy.compat.raw(p[UDP].payload),
                              scapy.compat.raw(echo_packet[UDP].payload),
                              "Received packet is not the echo packet sent")
+            counter += 1
         self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
                           "ECHO packet identifier for test purposes)")
+        stats_after = bfd_grab_stats_snapshot(self)
+        diff = bfd_stats_diff(stats_before, stats_after)
+        self.assertEqual(
+            0, diff.rx, "RX counter bumped but no BFD packets sent")
+        self.assertEqual(
+            bfd_control_packets_rx, diff.tx, "TX counter incorrect")
+        self.assertEqual(0, diff.rx_echo,
+                         "RX echo counter bumped but no BFD session exists")
+        self.assertEqual(0, diff.tx_echo,
+                         "TX echo counter bumped but no BFD session exists")
 
-    @unittest.skip("Test fails sporadically, BFD rework required to fix it")
     def test_echo(self):
         """ echo function """
+        stats_before = bfd_grab_stats_snapshot(self)
         bfd_session_up(self)
         self.test_session.update(required_min_echo_rx=150000)
         self.test_session.send_packet()
@@ -1170,9 +1260,12 @@ class BFD4TestCase(VppTestCase):
                                       "ECHO packet destination MAC address")
                     p[Ether].dst = self.pg0.local_mac
                     self.pg0.add_stream(p)
+                    self.test_session.rx_packets_echo += 1
+                    self.test_session.tx_packets_echo += 1
                     self.pg_start()
                     echo_seen = True
                 elif p.haslayer(BFD):
+                    self.test_session.rx_packets += 1
                     if echo_seen:
                         self.assertGreaterEqual(
                             p[BFD].required_min_rx_interval,
@@ -1189,7 +1282,20 @@ class BFD4TestCase(VppTestCase):
             self.test_session.send_packet()
         self.assertTrue(echo_seen, "No echo packets received")
 
-    @unittest.skip("Test fails sporadically, BFD rework required to fix it")
+        stats_after = bfd_grab_stats_snapshot(self)
+        diff = bfd_stats_diff(stats_before, stats_after)
+        # our rx is vpp tx and vice versa, also tolerate one packet off
+        self.assert_in_range(self.test_session.tx_packets,
+                             diff.rx - 1, diff.rx + 1, "RX counter")
+        self.assert_in_range(self.test_session.rx_packets,
+                             diff.tx - 1, diff.tx + 1, "TX counter")
+        self.assert_in_range(self.test_session.tx_packets_echo,
+                             diff.rx_echo - 1, diff.rx_echo + 1,
+                             "RX echo counter")
+        self.assert_in_range(self.test_session.rx_packets_echo,
+                             diff.tx_echo - 1, diff.tx_echo + 1,
+                             "TX echo counter")
+
     def test_echo_fail(self):
         """ session goes down if echo function fails """
         bfd_session_up(self)
@@ -1402,7 +1508,7 @@ class BFD4TestCase(VppTestCase):
         bfd_session_up(self)
         self.vpp_session.admin_down()
         self.pg0.enable_capture()
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.admin_down)
         for dummy in range(2):
             p = wait_for_bfd_packet(self)
@@ -1415,7 +1521,7 @@ class BFD4TestCase(VppTestCase):
             self.assert_equal(p[BFD].state, BFDState.admin_down, BFDState)
         self.vpp_session.admin_up()
         self.test_session.update(state=BFDState.down)
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.down)
         p = wait_for_bfd_packet(
             self, pcap_time_min=time.time() - self.vpp_clock_offset)
@@ -1424,14 +1530,14 @@ class BFD4TestCase(VppTestCase):
         p = wait_for_bfd_packet(
             self, pcap_time_min=time.time() - self.vpp_clock_offset)
         self.assert_equal(p[BFD].state, BFDState.init, BFDState)
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.init)
         self.test_session.update(state=BFDState.up)
         self.test_session.send_packet()
         p = wait_for_bfd_packet(
             self, pcap_time_min=time.time() - self.vpp_clock_offset)
         self.assert_equal(p[BFD].state, BFDState.up, BFDState)
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.up)
 
     def test_config_change_remote_demand(self):
@@ -1481,11 +1587,13 @@ class BFD4TestCase(VppTestCase):
         vpp_session.add_vpp_config()
         vpp_session.admin_up()
         intf.remove_vpp_config()
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
         self.assertFalse(vpp_session.query_vpp_config())
 
 
+@tag_run_solo
+@tag_fixme_vpp_workers
 class BFD6TestCase(VppTestCase):
     """Bidirectional Forwarding Detection (BFD) (IPv6) """
 
@@ -1523,6 +1631,8 @@ class BFD6TestCase(VppTestCase):
         self.vapi.want_bfd_events()
         self.pg0.enable_capture()
         try:
+            self.bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions']
+            self.bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions']
             self.vpp_session = VppBFDUDPSession(self, self.pg0,
                                                 self.pg0.remote_ip6,
                                                 af=AF_INET6)
@@ -1543,6 +1653,10 @@ class BFD6TestCase(VppTestCase):
     def test_session_up(self):
         """ bring BFD session up """
         bfd_session_up(self)
+        bfd_udp4_sessions = self.statistics['/bfd/udp4/sessions']
+        bfd_udp6_sessions = self.statistics['/bfd/udp6/sessions']
+        self.assert_equal(bfd_udp4_sessions, self.bfd_udp4_sessions)
+        self.assert_equal(bfd_udp6_sessions - self.bfd_udp6_sessions, 1)
 
     def test_session_up_by_ip(self):
         """ bring BFD session up - first frame looked up by address pair """
@@ -1558,12 +1672,12 @@ class BFD6TestCase(VppTestCase):
         self.test_session.update(your_discriminator=p[BFD].my_discriminator,
                                  state=BFDState.up)
         self.logger.info("BFD: Waiting for event")
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.init)
         self.logger.info("BFD: Sending Up")
         self.test_session.send_packet()
         self.logger.info("BFD: Waiting for event")
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         verify_event(self, e, expected_state=BFDState.up)
         self.logger.info("BFD: Session is Up")
         self.test_session.update(state=BFDState.up)
@@ -1582,8 +1696,8 @@ class BFD6TestCase(VppTestCase):
 
     def test_echo_looped_back(self):
         """ echo packets looped back """
-        # don't need a session in this case..
-        self.vpp_session.remove_vpp_config()
+        bfd_session_up(self)
+        stats_before = bfd_grab_stats_snapshot(self)
         self.pg0.enable_capture()
         echo_packet_count = 10
         # random source port low enough to increment a few times..
@@ -1602,7 +1716,9 @@ class BFD6TestCase(VppTestCase):
             self.logger.debug(ppp("Sending packet:", echo_packet))
             self.pg0.add_stream(echo_packet)
             self.pg_start()
-        for dummy in range(echo_packet_count):
+        counter = 0
+        bfd_control_packets_rx = 0
+        while counter < echo_packet_count:
             p = self.pg0.wait_for_packet(1)
             self.logger.debug(ppp("Got packet:", p))
             ether = p[Ether]
@@ -1611,8 +1727,11 @@ class BFD6TestCase(VppTestCase):
             self.assert_equal(self.pg0.local_mac, ether.src, "Source MAC")
             ip = p[IPv6]
             self.assert_equal(self.pg0.remote_ip6, ip.dst, "Destination IP")
-            self.assert_equal(self.pg0.remote_ip6, ip.src, "Destination IP")
             udp = p[UDP]
+            if udp.dport == BFD.udp_dport:
+                bfd_control_packets_rx += 1
+                continue
+            self.assert_equal(self.pg0.remote_ip6, ip.src, "Source IP")
             self.assert_equal(udp.dport, BFD.udp_dport_echo,
                               "UDP destination port")
             self.assert_equal(udp.sport, udp_sport_rx, "UDP source port")
@@ -1622,13 +1741,23 @@ class BFD6TestCase(VppTestCase):
             self.assertEqual(scapy.compat.raw(p[UDP].payload),
                              scapy.compat.raw(echo_packet[UDP].payload),
                              "Received packet is not the echo packet sent")
+            counter += 1
         self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
                           "ECHO packet identifier for test purposes)")
-        self.assert_equal(udp_sport_tx, udp_sport_rx, "UDP source port (== "
-                          "ECHO packet identifier for test purposes)")
+        stats_after = bfd_grab_stats_snapshot(self)
+        diff = bfd_stats_diff(stats_before, stats_after)
+        self.assertEqual(
+            0, diff.rx, "RX counter bumped but no BFD packets sent")
+        self.assertEqual(bfd_control_packets_rx,
+                         diff.tx, "TX counter incorrect")
+        self.assertEqual(0, diff.rx_echo,
+                         "RX echo counter bumped but no BFD session exists")
+        self.assertEqual(0, diff.tx_echo,
+                         "TX echo counter bumped but no BFD session exists")
 
     def test_echo(self):
         """ echo function """
+        stats_before = bfd_grab_stats_snapshot(self)
         bfd_session_up(self)
         self.test_session.update(required_min_echo_rx=150000)
         self.test_session.send_packet()
@@ -1662,11 +1791,14 @@ class BFD6TestCase(VppTestCase):
                     self.logger.debug(ppp("Looping back packet:", p))
                     self.assert_equal(p[Ether].dst, self.pg0.remote_mac,
                                       "ECHO packet destination MAC address")
+                    self.test_session.rx_packets_echo += 1
+                    self.test_session.tx_packets_echo += 1
                     p[Ether].dst = self.pg0.local_mac
                     self.pg0.add_stream(p)
                     self.pg_start()
                     echo_seen = True
                 elif p.haslayer(BFD):
+                    self.test_session.rx_packets += 1
                     if echo_seen:
                         self.assertGreaterEqual(
                             p[BFD].required_min_rx_interval,
@@ -1683,6 +1815,20 @@ class BFD6TestCase(VppTestCase):
             self.test_session.send_packet()
         self.assertTrue(echo_seen, "No echo packets received")
 
+        stats_after = bfd_grab_stats_snapshot(self)
+        diff = bfd_stats_diff(stats_before, stats_after)
+        # our rx is vpp tx and vice versa, also tolerate one packet off
+        self.assert_in_range(self.test_session.tx_packets,
+                             diff.rx - 1, diff.rx + 1, "RX counter")
+        self.assert_in_range(self.test_session.rx_packets,
+                             diff.tx - 1, diff.tx + 1, "TX counter")
+        self.assert_in_range(self.test_session.tx_packets_echo,
+                             diff.rx_echo - 1, diff.rx_echo + 1,
+                             "RX echo counter")
+        self.assert_in_range(self.test_session.rx_packets_echo,
+                             diff.tx_echo - 1, diff.tx_echo + 1,
+                             "TX echo counter")
+
     def test_intf_deleted(self):
         """ interface with bfd session deleted """
         intf = VppLoInterface(self)
@@ -1694,11 +1840,12 @@ class BFD6TestCase(VppTestCase):
         vpp_session.add_vpp_config()
         vpp_session.admin_up()
         intf.remove_vpp_config()
-        e = self.vapi.wait_for_event(1, "bfd_udp_session_details")
+        e = self.vapi.wait_for_event(1, "bfd_udp_session_event")
         self.assert_equal(e.sw_if_index, sw_if_index, "sw_if_index")
         self.assertFalse(vpp_session.query_vpp_config())
 
 
+@tag_run_solo
 class BFDFIBTestCase(VppTestCase):
     """ BFD-FIB interactions (IPv6) """
 
@@ -1804,7 +1951,7 @@ class BFDFIBTestCase(VppTestCase):
                              packet[IPv6].dst)
 
 
-@unittest.skipUnless(running_extended_tests, "part of extended tests")
+@unittest.skipUnless(config.extended, "part of extended tests")
 class BFDTunTestCase(VppTestCase):
     """ BFD over GRE tunnel """
 
@@ -1885,6 +2032,7 @@ class BFDTunTestCase(VppTestCase):
         bfd_session_down(self)
 
 
+@tag_run_solo
 class BFDSHA1TestCase(VppTestCase):
     """Bidirectional Forwarding Detection (BFD) (SHA1 auth) """
 
@@ -2116,6 +2264,7 @@ class BFDSHA1TestCase(VppTestCase):
         bfd_session_up(self)
 
 
+@tag_run_solo
 class BFDAuthOnOffTestCase(VppTestCase):
     """Bidirectional Forwarding Detection (BFD) (changing auth) """
 
@@ -2328,6 +2477,7 @@ class BFDAuthOnOffTestCase(VppTestCase):
                           "number of bfd events")
 
 
+@tag_run_solo
 class BFDCLITestCase(VppTestCase):
     """Bidirectional Forwarding Detection (BFD) (CLI) """
     pg0 = None
@@ -2730,16 +2880,15 @@ class BFDCLITestCase(VppTestCase):
                                  "IPv6 address usable as echo source: none" %
                                  self.loopback0.name)
         self.loopback0.config_ip4()
-        unpacked = unpack("!L", self.loopback0.local_ip4n)
-        echo_ip4 = inet_ntop(AF_INET, pack("!L", unpacked[0] ^ 1))
+        echo_ip4 = str(ipaddress.IPv4Address(int(ipaddress.IPv4Address(
+            self.loopback0.local_ip4)) ^ 1))
         self.cli_verify_response("show bfd echo-source",
                                  "UDP echo source is: %s\n"
                                  "IPv4 address usable as echo source: %s\n"
                                  "IPv6 address usable as echo source: none" %
                                  (self.loopback0.name, echo_ip4))
-        unpacked = unpack("!LLLL", self.loopback0.local_ip6n)
-        echo_ip6 = inet_ntop(AF_INET6, pack("!LLLL", unpacked[0], unpacked[1],
-                                            unpacked[2], unpacked[3] ^ 1))
+        echo_ip6 = str(ipaddress.IPv6Address(int(ipaddress.IPv6Address(
+            self.loopback0.local_ip6)) ^ 1))
         self.loopback0.config_ip6()
         self.cli_verify_response("show bfd echo-source",
                                  "UDP echo source is: %s\n"