Improve stability of APFv{4,6} multi-device tests

This commit enhances the stability of the APFv{4,6} multi-device tests by addressing several sources of flakiness and improving the test setup and validation.

Specifically, this commit:

* Increased sleep time in the test setup. This ensures APF is activated before each test, preventing unexpected behavior.
* Added sleep time in `ApfV4Test` to ensure APF remains enabled and is not disabled due to high throughput scenarios.
* Changed the validation order to first check received packets and then APF counters. This helps to more easily identify the root cause of test failures.
* Changed the Ethernet destination address from multicast to unicast in `ApfV6Test` to prevent packets from being filtered due to DTIM skip.
* Removed the `test_broadcast_arp_request_offload()` test, which was flaky due to DTIM skip and is adequately covered by the `test_unicast_arp_request_offload()` test.

Bug: 406570694
Flag: TEST_ONLY
Test: atest CtsConnectivityMultiDevicesTestCases:ApfV4Test
Test: atest CtsConnectivityMultiDevicesTestCases:ApfV6Test
Test: run cts -m CtsConnectivityMultiDevicesTestCases --skip-preconditions -t ApfV4Test --shard-count 2
Test: run cts -m CtsConnectivityMultiDevicesTestCases --skip-preconditions -t ApfV6Test --shard-count 2
Change-Id: I053509459078d0bd94e16a6bf7349b948f930e6c
This commit is contained in:
Jimi Chen 2025-04-02 03:07:56 +00:00 • committed by Yuyang Huang
commit 744a17443a
3 changed files with 29 additions and 32 deletions

View file

@ -70,8 +70,8 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase):
# Enable doze mode to activate APF.
adb_utils.set_doze_mode(self.clientDevice, True)
# wait for APF to become active.
time.sleep(3)
# Longer wait time is required for APF to become active in CTS test suite.
time.sleep(5)
def teardown_class(self):
adb_utils.set_doze_mode(self.clientDevice, False)
@ -106,7 +106,15 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase):
try:
apf_utils.start_capture_packets(self.serverDevice, self.server_iface_name)
self.send_packet_and_expect_counter_increased(send_packet, counter_name)
count_before_test = apf_utils.get_apf_counter(
self.clientDevice,
self.client_iface_name,
counter_name,
)
apf_utils.send_raw_packet_downstream(
self.serverDevice, self.server_iface_name, send_packet
)
assert_utils.expect_with_retry(
lambda: apf_utils.get_matched_packet_counts(
@ -114,5 +122,15 @@ class ApfTestBase(multi_devices_test_base.MultiDevicesTestBase):
)
== 1
)
assert_utils.expect_with_retry(
lambda: apf_utils.get_apf_counter(
self.clientDevice,
self.client_iface_name,
counter_name,
)
> count_before_test
)
finally:
apf_utils.stop_capture_packets(self.serverDevice, self.server_iface_name)

View file

@ -16,6 +16,7 @@ from absl.testing import parameterized
from mobly import asserts
from net_tests_utils.host.python import apf_test_base, apf_utils
from scapy.layers.l2 import Ether
import time
# Constants.
COUNTER_DROPPED_ETHERTYPE_NOT_ALLOWED = "DROPPED_ETHERTYPE_NOT_ALLOWED"
@ -59,6 +60,9 @@ class ApfV4Test(apf_test_base.ApfTestBase, parameterized.TestCase):
# Add zero padding up to minimum ethernet frame length
packet = packet.ljust(MIN_PACKET_SIZE * 2, "0")
# Pause packet sending between tests to avoid APF disablement due to high throughput.
time.sleep(3)
self.send_packet_and_expect_counter_increased(
packet, COUNTER_DROPPED_ETHERTYPE_NOT_ALLOWED
)

View file

@ -79,33 +79,6 @@ class ApfV6Test(apf_test_base.ApfTestBase):
arp_request, "DROPPED_ARP_REQUEST_REPLIED", expected_arp_reply
)
def test_broadcast_arp_request_offload(self):
eth = Ether(src=self.server_mac_address, dst='ff:ff:ff:ff:ff:ff')
arp = ARP(
op=1,
psrc=self.server_ipv4_addresses[0],
pdst=self.client_ipv4_addresses[0],
hwsrc=self.server_mac_address
)
arp_request = bytes(eth/arp).hex()
eth = Ether(src=self.client_mac_address, dst=self.server_mac_address)
arp = ARP(
op=2,
psrc=self.client_ipv4_addresses[0],
pdst=self.server_ipv4_addresses[0],
hwsrc=self.client_mac_address,
hwdst=self.server_mac_address
)
expected_arp_reply = bytes(eth/arp).hex()
# Add zero padding up to 60 bytes, since APFv6 ARP offload always sent out 60 bytes reply
expected_arp_reply = expected_arp_reply.ljust(ARP_OFFLOAD_REPLY_LEN * 2, "0")
self.send_packet_and_expect_reply_received(
arp_request, "DROPPED_ARP_REQUEST_REPLIED", expected_arp_reply
)
def test_non_dad_ipv6_neighbor_solicitation_offload(self):
eth = Ether(src=self.server_mac_address, dst=self.client_mac_address)
ip = IPv6(src=self.server_ipv6_addresses[0], dst=self.client_ipv6_addresses[0])
@ -158,7 +131,8 @@ class ApfV6Test(apf_test_base.ApfTestBase):
@apf_utils.at_least_B()
def test_igmpv3_general_query_offload(self):
ether = Ether(src=self.server_mac_address, dst='01:00:5e:00:00:01')
# use unicast to replace multicast ether dst to prevent flaky due to DTIM skip
ether = Ether(src=self.server_mac_address, dst=self.client_mac_address)
ip = IP(
src=self.server_ipv4_addresses[0],
dst='224.0.0.1',
@ -206,7 +180,8 @@ class ApfV6Test(apf_test_base.ApfTestBase):
@apf_utils.at_least_B()
@apf_utils.apf_ram_at_least(3000)
def test_mldv2_general_query_offload(self):
ether = Ether(src=self.server_mac_address, dst='33:33:00:00:00:01')
# use unicast to replace multicast ether dst to prevent flaky due to DTIM skip
ether = Ether(src=self.server_mac_address, dst=self.client_mac_address)
ip = IPv6(src=self.server_ipv6_addresses[0], dst='ff02::1', hlim=1)
hopOpts = IPv6ExtHdrHopByHop(options=[RouterAlert(otype=5)])
mld = ICMPv6MLQuery2()