From 6bbaef204833dcb0f008a98df71f56a8f36eaa3a Mon Sep 17 00:00:00 2001 From: rick-arista <148895369+rick-arista@users.noreply.github.com> Date: Mon, 16 Feb 2026 18:18:10 -0800 Subject: [PATCH] Add trimmed packet size margin (#22322) What is the motivation for this PR? In some cases a small difference in the expected trimmed packet size has been observed (+/- 4 bytes). The trimmed packet's size depends on the asic's cell size, minus any metadata contained in the first cell. Since the variable number of trailing bytes is part of the packet's payload we can ignore this difference and add a margin to any size checks. How did you do it? Expected packets are now matched by prefix minus the margin size, and an additional assertion was added that the size is within +/- the packet size margin value. How did you verify/test it? Manually tested --- tests/packet_trimming/constants.py | 1 + .../packet_trimming/packet_trimming_helper.py | 100 ++++++++---------- 2 files changed, 43 insertions(+), 58 deletions(-) diff --git a/tests/packet_trimming/constants.py b/tests/packet_trimming/constants.py index 0ebbd45a1..bbfcc74e3 100644 --- a/tests/packet_trimming/constants.py +++ b/tests/packet_trimming/constants.py @@ -28,6 +28,7 @@ PACKET_COUNT = 1000 BATCH_PACKET_COUNT = 10000 ECN = 2 # ECN Capable Transport(0), ECT(0) +PACKET_SIZE_MARGIN = 4 # Buffer configuration constants TRIM_QUEUE_PROFILE = "egress_lossy_profile" diff --git a/tests/packet_trimming/packet_trimming_helper.py b/tests/packet_trimming/packet_trimming_helper.py index 91012c2b6..abcbbd89f 100644 --- a/tests/packet_trimming/packet_trimming_helper.py +++ b/tests/packet_trimming/packet_trimming_helper.py @@ -25,7 +25,8 @@ SRV6_INNER_SRC_IP, SRV6_INNER_DST_IP, DEFAULT_QUEUE_SCHEDULER_CONFIG, SRV6_UNIFORM_MODE, SRV6_OUTER_SRC_IPV6, SRV6_INNER_SRC_IPV6, ECN, SRV6_INNER_DST_IPV6, SRV6_UN, ASYM_PORT_1_DSCP, ASYM_PORT_2_DSCP, - SCHEDULER_TYPE, SCHEDULER_WEIGHT, SCHEDULER_PIR, SCHEDULER_METER_TYPE) + SCHEDULER_TYPE, SCHEDULER_WEIGHT, SCHEDULER_PIR, SCHEDULER_METER_TYPE, + PACKET_SIZE_MARGIN) from tests.packet_trimming.packet_trimming_config import PacketTrimmingConfig logger = logging.getLogger(__name__) @@ -254,7 +255,7 @@ def generate_packet(duthost, packet_type, dst_addr, send_pkt_size, send_pkt_dscp exp_packet = testutils.simple_udpv6_packet(**recv_params) # Create masked expected packet - masked_exp_packet = Mask(exp_packet) + masked_exp_packet = Mask(exp_packet, ignore_extra_bytes=True) # Set fields to ignore in packet matching # Common Ethernet header fields to ignore @@ -426,6 +427,18 @@ def delete_blocking_scheduler(duthost): logger.info(f"Successfully deleted blocking scheduler: {BLOCK_DATA_PLANE_SCHEDULER_NAME}") +def validate_packet_size(pkt_size, pkt_size_exp): + """ + Validate packet size against expected size +/- PACKET_SIZE_MARGIN + + Args: + pkt_size: the packet's actual size + pkt_size_exp: the packet's expected size + """ + pytest_assert(pkt_size_exp - PACKET_SIZE_MARGIN <= pkt_size <= pkt_size_exp + PACKET_SIZE_MARGIN, + f"Packet size expected {pkt_size_exp} +/- {PACKET_SIZE_MARGIN}, was: {pkt_size} ") + + def validate_scheduler_configuration(duthost, dut_port, queue, expected_scheduler): """ Validate that the scheduler configuration is applied correctly for a specific queue. @@ -875,7 +888,7 @@ def verify_packet_trimming(duthost, ptfadapter, ingress_port, egress_port, block dst_addr, send_pkt_size, send_pkt_dscp, - recv_pkt_size, + recv_pkt_size - PACKET_SIZE_MARGIN, recv_pkt_dscp ) @@ -905,12 +918,13 @@ def verify_packet_trimming(duthost, ptfadapter, ingress_port, egress_port, block if expect_packets: logger.info( f"Expecting packets on ports {verify_ports} with size {recv_pkt_size} and DSCP {recv_pkt_dscp}") - testutils.verify_packet_any_port( + _, matched = testutils.verify_packet_any_port( ptfadapter, exp_pkt, ports=verify_ports, timeout=timeout ) + validate_packet_size(len(matched), recv_pkt_size) logger.info( f"Successfully verified {packet_type} packet trimming with size {recv_pkt_size} " f"and DSCP {recv_pkt_dscp}") @@ -2045,7 +2059,7 @@ def validate_srv6_function(duthost, ptfadapter, dscp_mode, ingress_port, egress_ # - SRv6 packet without SRH: IPv6 (40) + IPv4 (20) + UDP (8) + Payload = 256 # - SRv6 packet with SRH: IPv6 (40) + SRH (40) + IPv4 (20) + UDP (8) + Payload = 256 - actual_recv_pkt_size = recv_pkt_size - ipv6_header_len + actual_recv_pkt_size = recv_pkt_size - ipv6_header_len - PACKET_SIZE_MARGIN srv6_pkt, exp_pkt = create_srv6_packet_for_trimming( outer_src_mac=DUMMY_MAC, @@ -2077,15 +2091,25 @@ def validate_srv6_function(duthost, ptfadapter, dscp_mode, ingress_port, egress_ else: verify_ports = [egress_port['ptf_id']] - send_verify_srv6_packet_for_trimming( - ptfadapter=ptfadapter, - pkt=srv6_pkt, - exp_pkt=exp_pkt, - exp_pro=srv6_packet["exp_process_result"], - ptf_src_port_id=ingress_port['ptf_id'], - ptf_dst_port_ids=verify_ports, - packet_num=PACKET_COUNT - ) + ptfadapter.dataplane.flush() + + logger.info(f"Send SRv6 packet(s) from PTF port {ingress_port['ptf_id']} to upstream") + testutils.send(ptfadapter, ingress_port['ptf_id'], srv6_pkt, count=PACKET_COUNT) + + logger.info('SRv6 packet format:\n ---------------------------') + logger.info(f'{dump_packet_detail(srv6_pkt)}\n---------------------------') + logger.info('Expect receive SRv6 packet format:\n ---------------------------') + logger.info(f'{dump_packet_detail(exp_pkt.exp_pkt)}\n---------------------------') + + if srv6_packet['exp_process_result'] == 'forward': + _, matched = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=verify_ports) + validate_packet_size(len(matched), recv_pkt_size) + logger.info('Successfully received packets') + elif srv6_packet['exp_process_result'] == 'drop': + testutils.verify_no_packet_any(ptfadapter, exp_pkt, ports=verify_ports) + logger.info(f'No packet received on {verify_ports}') + else: + logger.error(f"Wrong expected process result: {srv6_packet['exp_process_result']}") def create_srv6_packet_for_trimming( @@ -2233,7 +2257,7 @@ def create_srv6_packet_for_trimming( ) exp_pkt['IPv6'].hlim -= 1 - exp_pkt = Mask(exp_pkt) + exp_pkt = Mask(exp_pkt, ignore_extra_bytes=True) logger.info('Do not care packet ethernet destination address') exp_pkt.set_do_not_care_packet(scapy.Ether, 'dst') @@ -2285,47 +2309,6 @@ def create_srv6_packet_for_trimming( return srv6_pkt, exp_pkt -def send_verify_srv6_packet_for_trimming( - ptfadapter, - pkt, - exp_pkt, - exp_pro, - ptf_src_port_id, - ptf_dst_port_ids, - packet_num=10): - """ - Send and verify SRv6 packets - - Args: - ptfadapter: PTF adapter object - pkt: Packet to send - exp_pkt: Expected packet - exp_pro (str): Expected process result ('forward' or 'drop') - ptf_src_port_id (int): Source PTF port ID - ptf_dst_port_ids: - packet_num (int): Number of packets to send (default: 10) - """ - ptfadapter.dataplane.flush() - logger.info(f'Send SRv6 packet(s) from PTF port {ptf_src_port_id} to upstream') - testutils.send(ptfadapter, ptf_src_port_id, pkt, count=packet_num) - logger.info('SRv6 packet format:\n ---------------------------') - logger.info(f'{dump_packet_detail(pkt)}\n---------------------------') - logger.info('Expect receive SRv6 packet format:\n ---------------------------') - logger.info(f'{dump_packet_detail(exp_pkt.exp_pkt)}\n---------------------------') - - try: - if exp_pro == 'forward': - testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=ptf_dst_port_ids) - logger.info('Successfully received packets') - elif exp_pro == 'drop': - testutils.verify_no_packet_any(ptfadapter, exp_pkt, ports=ptf_dst_port_ids) - logger.info(f'No packet received on {ptf_dst_port_ids}') - else: - logger.error(f'Wrong expected process result: {exp_pro}') - except AssertionError as detail: - raise detail - - def check_connected_route_ready(duthost, egress_port): """ Check if the route for the specified interface is ready. @@ -2575,7 +2558,7 @@ def verify_normal_packet(duthost, ptfadapter, ingress_port, egress_port, send_pk dst_addr, send_pkt_size, send_pkt_dscp, - recv_pkt_size, + recv_pkt_size - PACKET_SIZE_MARGIN, recv_pkt_dscp ) @@ -2605,12 +2588,13 @@ def verify_normal_packet(duthost, ptfadapter, ingress_port, egress_port, send_pk # Verify packet if expect_packets: logger.info(f"Expecting packets on ports {verify_ports} with size {recv_pkt_size} and DSCP {recv_pkt_dscp}") - testutils.verify_packet_any_port( + _, matched = testutils.verify_packet_any_port( ptfadapter, exp_pkt, ports=verify_ports, timeout=timeout ) + validate_packet_size(len(matched), recv_pkt_size) logger.info(f"Successfully verified normal packet with size {recv_pkt_size}") else: logger.info(f"Expecting NO packets on ports {verify_ports}")