From ba00ab1fba67cde1d8942a05753cb7192c1ce01c Mon Sep 17 00:00:00 2001 From: Aaron Bernardino Date: Thu, 30 Jul 2026 20:05:42 +0000 Subject: [PATCH 1/2] [packet_trimming] Enable the suite on sonic-vpp and make it self-sufficient - packet_trimming_helper.py: create queue{1,3}_{uplink,downlink}_lossy_profile BUFFER_PROFILEs when absent (they ship only in real SN5640/7060X6 QoS templates), so block-queue setup works on the VPP Force10-S6000 config; add delete_buffer_queue_for_trim_queue to remove test-created BUFFER_QUEUE trim-queue references. - conftest.py: call delete_buffer_queue_for_trim_queue in teardown before deleting trim_queue_test_profile, so `config load` (a merge) does not leave a dangling BUFFER_QUEUE -> BUFFER_PROFILE leafref that fails post-test YANG validation on platforms whose base config lacks the trim queue (VPP). - tests_mark_conditions.yaml: exempt asic_type == 'vpp' from the hwsku skip and add asic_type in ['vpp'] skips for the deferred asymmetric module and symmetric cases (ACL, SRv6, counters x2, mirror, reload/reboot, stability and port-admin toggles), so only the three in-scope symmetric cases run on VPP. Validated on vms-kvm-vpp-t1-lag: the three in-scope cases pass with zero setup/teardown errors and no manual redis-cli. Tracking: sonic-net/sonic-buildimage#25789 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Aaron Bernardino --- .../tests_mark_conditions.yaml | 58 ++++++++++++++++- tests/packet_trimming/conftest.py | 10 +++ .../packet_trimming/packet_trimming_helper.py | 63 ++++++++++++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml index 1e7af47cfc9..2d018cb276b 100644 --- a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml +++ b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml @@ -3969,12 +3969,12 @@ override_config_table/test_override_config_table.py::test_load_minigraph_with_go ######################################## packet_trimming: skip: - reason: "Packet trimming is not supported on 202505. Packet trimming cases require PR https://github.com/sonic-net/sonic-buildimage/pull/22869, but KVM does not support it, so skip trimming case on KVM. Packet-trimming tests are only supported on certain Mellanox SN5640 and Arista 7060X6 SKUs." + reason: "Packet trimming is not supported on 202505. Packet trimming cases require PR https://github.com/sonic-net/sonic-buildimage/pull/22869, but KVM does not support it, so skip trimming case on KVM. Packet-trimming tests are only supported on certain Mellanox SN5640 and Arista 7060X6 SKUs. On sonic-vpp (asic_type 'vpp') the symmetric core trimming cases are enabled; deferred cases are skipped per-test (tracking sonic-net/sonic-buildimage#25789)." conditions_logical_operator: or conditions: - "release in ['202505']" - "asic_type in ['vs']" - - "hwsku not in ['Arista-7060X6-64PE-B-C448O16', 'Arista-7060X6-64PE-B-C512S2', 'Mellanox-SN5640-C448O16', 'Mellanox-SN5640-C512S2']" + - "hwsku not in ['Arista-7060X6-64PE-B-C448O16', 'Arista-7060X6-64PE-B-C512S2', 'Mellanox-SN5640-C448O16', 'Mellanox-SN5640-C512S2'] and asic_type != 'vpp'" xfail: reason: "Test case has issue on the t0-isolated-d256u256s2 topo." conditions: @@ -3994,16 +3994,68 @@ packet_trimming/test_packet_trimming_asymmetric.py::TestPacketTrimmingAsymmetric packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_trimming_counters_with_feature_toggle: skip: - reason: "TH5 clears trim counters when packet trimming is turned off, skipping until trim counter persistance is supported." + reason: "TH5 clears trim counters when packet trimming is turned off, skipping until trim counter persistance is supported. Trim counters are also deferred on sonic-vpp (tracking sonic-net/sonic-buildimage#25789)." + conditions_logical_operator: or conditions: - "asic_gen in ['th5']" + - "asic_type in ['vpp']" packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_trimming_with_srv6: + skip: + reason: "SRv6 with packet trimming is deferred on sonic-vpp; the SRv6 trim path is not yet implemented in the VPP dataplane (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" xfail: reason: "vlan decap is disabled in 202412 image" conditions: - "'isolated' in topo_name and release in ['202412']" +################################################# +## sonic-vpp: deferred packet_trimming cases ## +## (symmetric core cases run; see HLD §13/§14) ## +################################################# +packet_trimming/test_packet_trimming_asymmetric.py: + skip: + reason: "Asymmetric (per-port DSCP) packet trimming is deferred on sonic-vpp; only symmetric core trimming is enabled (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_acl_action_with_trimming: + skip: + reason: "ACL DISABLE_TRIM action with packet trimming is deferred on sonic-vpp; not yet implemented in the VPP dataplane (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_stability_during_feature_toggles: + skip: + reason: "Feature-toggle stability with packet trimming is deferred on sonic-vpp; not yet validated (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_trimming_during_port_admin_toggle: + skip: + reason: "Port admin-toggle with packet trimming is deferred on sonic-vpp; not yet validated (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_trimming_with_reload_and_reboot: + skip: + reason: "Reload/reboot persistence of packet trimming is deferred on sonic-vpp; config persistence not yet validated (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_trimming_counters: + skip: + reason: "Trim counters are deferred on sonic-vpp; trim drop/sent counters are not yet implemented (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_port_mirror_with_trimming: + skip: + reason: "Port mirroring with packet trimming is deferred on sonic-vpp; the mirror trim path is not yet implemented (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + ####################################### ##### pc ##### ####################################### diff --git a/tests/packet_trimming/conftest.py b/tests/packet_trimming/conftest.py index 4e7e796acd4..f9f7fc2fe78 100644 --- a/tests/packet_trimming/conftest.py +++ b/tests/packet_trimming/conftest.py @@ -16,6 +16,7 @@ configure_tc_to_dscp_map, set_buffer_profile_for_block_queue, set_buffer_profile_for_trim_queue, create_blocking_scheduler, configure_trimming_action, cleanup_trimming_acl, get_queue_id_by_dscp, get_test_ports, create_trim_queue_test_buffer_profile, delete_trim_queue_test_buffer_profile, + delete_buffer_queue_for_trim_queue, is_queue_level_trim_sent_drop_supported) @@ -256,6 +257,15 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): for buffer_profile in trim_counter_params['trim_buffer_profiles']: configure_trimming_action(duthost, trim_counter_params['trim_buffer_profiles'][buffer_profile], "off") + with allure.step("Remove trim queue buffer profile references"): + # config load merges the backup and does not delete BUFFER_QUEUE keys added on + # platforms whose base config lacks them (e.g. VPP). Clear them before deleting + # the profile so teardown does not leave a dangling BUFFER_QUEUE -> BUFFER_PROFILE + # leafref that fails post-test YANG validation. + delete_buffer_queue_for_trim_queue(duthost, test_params['egress_ports'][0]['dut_members']) + if len(test_params['egress_ports']) > 1: + delete_buffer_queue_for_trim_queue(duthost, test_params['egress_ports'][1]['dut_members']) + with allure.step("Delete trim queue test buffer profile"): delete_trim_queue_test_buffer_profile(duthost) diff --git a/tests/packet_trimming/packet_trimming_helper.py b/tests/packet_trimming/packet_trimming_helper.py index 39fb3c5fabd..9a6c528d270 100644 --- a/tests/packet_trimming/packet_trimming_helper.py +++ b/tests/packet_trimming/packet_trimming_helper.py @@ -30,7 +30,7 @@ MIRROR_SESSION_SRC_IP, MIRROR_SESSION_DST_IP, MIRROR_SESSION_DSCP, MIRROR_SESSION_TTL, MIRROR_SESSION_GRE, MIRROR_SESSION_QUEUE, SCHEDULER_CIR, SCHEDULER_METER_TYPE, PACKET_SIZE_MARGIN, - TRIMMING_COUNTER_INTERVAL, + TRIMMING_COUNTER_INTERVAL, DYNAMIC_TH, QUEUE_LEVEL_TRIM_SENT_DROP_SUPPORTED_PLATFORMS) from tests.packet_trimming.packet_trimming_config import PacketTrimmingConfig @@ -1574,6 +1574,34 @@ def cleanup_trimming_acl(duthost): logger.info("ACL rules cleanup completed successfully") +def ensure_block_queue_buffer_profile(duthost, block_queue_profile): + """ + Ensure the buffer profile referenced by a blocking queue exists in CONFIG_DB. + + The suite references per-queue profiles named ``queue__lossy_profile``. + On the SKUs packet trimming normally targets (Mellanox SN5640, Arista 7060X6) those + profiles are supplied by the platform ``buffers_defaults_objects.j2`` template. Minimal + buffer configurations - such as the VPP virtual switch on the shared Force10-S6000 hwsku - + do not define them, so the ``BUFFER_QUEUE`` reference would dangle and the subsequent + ``config mmu -p -t on`` trimming-action configuration would fail. Create a lossy + profile bound to the egress lossy pool on demand when the profile is missing. This is a + no-op on platforms that already define the profile, so behavior on those SKUs is unchanged. + + Args: + duthost: DUT host object + block_queue_profile (str): Buffer profile name referenced by the blocking queue + """ + exists = duthost.shell( + f"redis-cli -n 4 exists 'BUFFER_PROFILE|{block_queue_profile}'")["stdout"].strip() + if exists == "1": + return + + pool = TRIM_QUEUE_PROFILE_CONFIG["pool"] + fields = f"pool {pool} size 1518 dynamic_th {DYNAMIC_TH}" + duthost.shell(f"redis-cli -n 4 hset 'BUFFER_PROFILE|{block_queue_profile}' {fields}") + logger.info(f"Created missing blocking-queue buffer profile '{block_queue_profile}': {fields}") + + def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, block_queue_profile): """ Set buffer profile for the blocked queue of interfaces. @@ -1593,6 +1621,10 @@ def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, bloc logger.info(f"Setting blocking queue ({block_queue_id}) buffer profile to '{block_queue_profile}', " f"ports: {interfaces}") + # Create the referenced buffer profile when the platform does not already define it + # (for example the VPP virtual switch), so blocking-queue setup is self-sufficient. + ensure_block_queue_buffer_profile(duthost, block_queue_profile) + # Convert single interface to list if isinstance(interfaces, str): interfaces = [interfaces] @@ -1675,6 +1707,35 @@ def set_buffer_profile_for_trim_queue(duthost, interfaces, trim_queue_id=None, t raise +def delete_buffer_queue_for_trim_queue(duthost, interfaces, trim_queue_id=None): + """ + Remove the BUFFER_QUEUE entries created for the trimming queue during setup. + + Teardown restores configuration with ``config load``, which merges the pre-test + backup and does not delete BUFFER_QUEUE keys the test added on platforms whose base + configuration does not already define them (for example the VPP virtual switch on + the shared Force10-S6000 hwsku). Once ``trim_queue_test_profile`` is deleted, those + leftover keys become a dangling BUFFER_QUEUE -> BUFFER_PROFILE leafref that fails the + post-test YANG validation. Delete the entries explicitly, before the profile is + removed, so teardown leaves a YANG-valid configuration on every platform. Platforms + whose base configuration defines the queue restore it from the backup on ``config + load``, so behavior there is unchanged. + + Args: + duthost: DUT host object + interfaces (list or str): Port names whose trimming-queue reference should be removed + trim_queue_id (int): Queue index used for packet trimming (default: trim queue from config) + """ + trim_queue_id = str(trim_queue_id) if trim_queue_id else str(PacketTrimmingConfig.get_trim_queue(duthost)) + + if isinstance(interfaces, str): + interfaces = [interfaces] + + for interface in interfaces: + duthost.shell(f"redis-cli -n 4 del 'BUFFER_QUEUE|{interface}|{trim_queue_id}'") + logger.info(f"Removed trimming-queue BUFFER_QUEUE|{interface}|{trim_queue_id} during teardown") + + def prepare_service_port(duthost, service_port): """ Prepare service port for packet trimming tests by checking existence, From 2adcedf4bc0a08eeb176bc8f5ad7d64dc8c69730 Mon Sep 17 00:00:00 2001 From: Aaron Bernardino Date: Thu, 30 Jul 2026 22:43:21 +0000 Subject: [PATCH 2/2] [packet_trimming] Harden conditional-mark skips and blocking-queue teardown Address code-review gaps M3 and M4 in the packet-trimming suite: - M3 (conditional_mark): add file-level "asic_type in ['vpp']" skips for test_packet_trimming_config_asymmetric.py and test_packet_trimming_config_symmetric.py so the config variants are skipped on sonic-vpp the same way the folder-level rule already skips the rest of the suite. A longer file-level key whose condition is false does not shadow the shorter folder-level rule, so non-VPP platforms are unaffected. - M4 (teardown cleanup): setup_trimming now records the blocking-queue BUFFER_QUEUE bindings it adds and the buffer profiles it creates on demand, and teardown removes the bindings unconditionally and deletes only the profiles it created. config load merges rather than replaces, so without this the added keys dangled on platforms (e.g. the VPP vs on the shared Force10-S6000 hwsku) whose base config lacks them. set_buffer_profile_for_block_queue / ensure_block_queue_buffer_profile now return whether they created the profile to drive this. Validated on the dev-VM: conditional_mark decisions correct across four platform scenarios (no shadowing regression); teardown leaves no leftover trim/block profiles or BUFFER_QUEUE bindings. Tracking: sonic-net/sonic-buildimage#25789 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Aaron Bernardino --- .../tests_mark_conditions.yaml | 12 ++++ tests/packet_trimming/conftest.py | 39 +++++++++--- .../packet_trimming/packet_trimming_helper.py | 60 ++++++++++++++++++- 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml index 2d018cb276b..45712fcdf9b 100644 --- a/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml +++ b/tests/common/plugins/conditional_mark/tests_mark_conditions.yaml @@ -4020,6 +4020,18 @@ packet_trimming/test_packet_trimming_asymmetric.py: conditions: - "asic_type in ['vpp']" +packet_trimming/test_packet_trimming_config_asymmetric.py: + skip: + reason: "Asymmetric (FROM_TC) packet-trimming GCU config validation is deferred on sonic-vpp; only symmetric core trimming is enabled (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + +packet_trimming/test_packet_trimming_config_symmetric.py: + skip: + reason: "Symmetric packet-trimming GCU config validation is deferred on sonic-vpp; out of scope for the initial dataplane enablement (tracking sonic-net/sonic-buildimage#25789)." + conditions: + - "asic_type in ['vpp']" + packet_trimming/test_packet_trimming_symmetric.py::TestPacketTrimmingSymmetric::test_acl_action_with_trimming: skip: reason: "ACL DISABLE_TRIM action with packet trimming is deferred on sonic-vpp; not yet implemented in the VPP dataplane (tracking sonic-net/sonic-buildimage#25789)." diff --git a/tests/packet_trimming/conftest.py b/tests/packet_trimming/conftest.py index f9f7fc2fe78..fc470248166 100644 --- a/tests/packet_trimming/conftest.py +++ b/tests/packet_trimming/conftest.py @@ -17,6 +17,7 @@ create_blocking_scheduler, configure_trimming_action, cleanup_trimming_acl, get_queue_id_by_dscp, get_test_ports, create_trim_queue_test_buffer_profile, delete_trim_queue_test_buffer_profile, delete_buffer_queue_for_trim_queue, + delete_buffer_queue_for_block_queue, delete_created_block_queue_buffer_profiles, is_queue_level_trim_sent_drop_supported) @@ -185,6 +186,12 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): logger.info("Prepare packet trimming related configurations") platform = duthost.facts['platform'] + # Track the blocking-queue buffer config this fixture adds so teardown can + # remove exactly what it created. On platforms whose base config already + # defines these profiles nothing is created and nothing is torn down. + created_block_profiles = set() + block_queue_bindings = [] + with allure.step("Backup configuration"): logger.info("Backup configuration before trimming test") duthost.shell("sudo config save -y /etc/sonic/config_db_before_trimming_test.json") @@ -210,10 +217,14 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): counter_uplink_port = trim_counter_params['egress_ports'][0] counter_block_interface = counter_uplink_port['dut_members'] logger.info(f"Apply uplink buffer profile to interfaces: {block_interface}") - set_buffer_profile_for_block_queue(duthost, block_interface, test_params['block_queue'], - test_params['trim_buffer_profiles']['uplink']) - set_buffer_profile_for_block_queue(duthost, counter_block_interface, trim_counter_params['block_queue'], - trim_counter_params['trim_buffer_profiles']['uplink']) + created_block_profiles.add( + set_buffer_profile_for_block_queue(duthost, block_interface, test_params['block_queue'], + test_params['trim_buffer_profiles']['uplink'])) + block_queue_bindings.append((block_interface, test_params['block_queue'])) + created_block_profiles.add( + set_buffer_profile_for_block_queue(duthost, counter_block_interface, trim_counter_params['block_queue'], + trim_counter_params['trim_buffer_profiles']['uplink'])) + block_queue_bindings.append((counter_block_interface, trim_counter_params['block_queue'])) create_trim_queue_test_buffer_profile(duthost) set_buffer_profile_for_trim_queue(duthost, block_interface) @@ -222,8 +233,10 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): downlink_port = test_params['egress_ports'][1] block_interface = downlink_port['dut_members'] logger.info(f"Apply downlink buffer profile to {block_interface}:{test_params['block_queue']}") - set_buffer_profile_for_block_queue(duthost, block_interface, test_params['block_queue'], - test_params['trim_buffer_profiles']['downlink']) + created_block_profiles.add( + set_buffer_profile_for_block_queue(duthost, block_interface, test_params['block_queue'], + test_params['trim_buffer_profiles']['downlink'])) + block_queue_bindings.append((block_interface, test_params['block_queue'])) set_buffer_profile_for_trim_queue(duthost, block_interface) # Also set the downlink buffer profile for the block queue used in counter tests, if applicable. @@ -232,8 +245,10 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): counter_block_interface = counter_downlink_port['dut_members'] logger.info(f"Apply downlink buffer profile to " f"{counter_block_interface}:{trim_counter_params['block_queue']}") - set_buffer_profile_for_block_queue(duthost, counter_block_interface, trim_counter_params['block_queue'], - trim_counter_params['trim_buffer_profiles']['downlink']) + created_block_profiles.add( + set_buffer_profile_for_block_queue(duthost, counter_block_interface, trim_counter_params['block_queue'], + trim_counter_params['trim_buffer_profiles']['downlink'])) + block_queue_bindings.append((counter_block_interface, trim_counter_params['block_queue'])) with allure.step("Create scheduler used for blocking egress queues"): create_blocking_scheduler(duthost) @@ -266,6 +281,14 @@ def setup_trimming(duthost, test_params, trim_counter_params, request): if len(test_params['egress_ports']) > 1: delete_buffer_queue_for_trim_queue(duthost, test_params['egress_ports'][1]['dut_members']) + with allure.step("Remove blocking-queue buffer config added during setup"): + # Same rationale as the trim queue: clear the BUFFER_QUEUE bindings this fixture + # added and delete the buffer profiles it created on demand, so teardown leaves a + # clean, YANG-valid CONFIG_DB on platforms (e.g. VPP) whose base config lacks them. + for interfaces, block_queue_id in block_queue_bindings: + delete_buffer_queue_for_block_queue(duthost, interfaces, block_queue_id) + delete_created_block_queue_buffer_profiles(duthost, created_block_profiles) + with allure.step("Delete trim queue test buffer profile"): delete_trim_queue_test_buffer_profile(duthost) diff --git a/tests/packet_trimming/packet_trimming_helper.py b/tests/packet_trimming/packet_trimming_helper.py index 9a6c528d270..5a8828b7979 100644 --- a/tests/packet_trimming/packet_trimming_helper.py +++ b/tests/packet_trimming/packet_trimming_helper.py @@ -1590,16 +1590,21 @@ def ensure_block_queue_buffer_profile(duthost, block_queue_profile): Args: duthost: DUT host object block_queue_profile (str): Buffer profile name referenced by the blocking queue + + Returns: + bool: True if this call created the profile (so teardown should remove it), + False if the platform already defined it. """ exists = duthost.shell( f"redis-cli -n 4 exists 'BUFFER_PROFILE|{block_queue_profile}'")["stdout"].strip() if exists == "1": - return + return False pool = TRIM_QUEUE_PROFILE_CONFIG["pool"] fields = f"pool {pool} size 1518 dynamic_th {DYNAMIC_TH}" duthost.shell(f"redis-cli -n 4 hset 'BUFFER_PROFILE|{block_queue_profile}' {fields}") logger.info(f"Created missing blocking-queue buffer profile '{block_queue_profile}': {fields}") + return True def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, block_queue_profile): @@ -1612,6 +1617,10 @@ def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, bloc block_queue_id: Queue index used for blocking traffic block_queue_profile (str): Buffer profile name to apply for blocking queue + Returns: + str or None: The buffer profile name if this call created it on demand (so teardown + must delete it), otherwise None (the platform already defined it). + Raises: RuntimeError: If any interface fails to be configured with the specified profile. """ @@ -1623,7 +1632,7 @@ def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, bloc # Create the referenced buffer profile when the platform does not already define it # (for example the VPP virtual switch), so blocking-queue setup is self-sufficient. - ensure_block_queue_buffer_profile(duthost, block_queue_profile) + created_profile = ensure_block_queue_buffer_profile(duthost, block_queue_profile) # Convert single interface to list if isinstance(interfaces, str): @@ -1644,6 +1653,53 @@ def set_buffer_profile_for_block_queue(duthost, interfaces, block_queue_id, bloc raise RuntimeError(f"Exception while configuring interface {interface} blocking queue: {str(e)}") from e raise + return block_queue_profile if created_profile else None + + +def delete_buffer_queue_for_block_queue(duthost, interfaces, block_queue_id): + """ + Remove the BUFFER_QUEUE entries created for a blocking queue during setup. + + Mirrors ``delete_buffer_queue_for_trim_queue``: ``config load`` of the pre-test backup + merges rather than replaces, so BUFFER_QUEUE keys the test added on platforms whose base + configuration does not define them (for example the VPP virtual switch on the shared + Force10-S6000 hwsku) survive teardown and dangle once the on-demand blocking-queue profile + is removed. Delete them explicitly, before the profile is removed, so teardown leaves a + YANG-valid configuration on every platform. Platforms whose base configuration defines the + queue restore it from the backup on ``config load``, so behavior there is unchanged. + + Args: + duthost: DUT host object + interfaces (list or str): Port names whose blocking-queue reference should be removed + block_queue_id: Queue index used for blocking traffic + """ + block_queue_id = str(block_queue_id) + + if isinstance(interfaces, str): + interfaces = [interfaces] + + for interface in interfaces: + duthost.shell(f"redis-cli -n 4 del 'BUFFER_QUEUE|{interface}|{block_queue_id}'") + logger.info(f"Removed blocking-queue BUFFER_QUEUE|{interface}|{block_queue_id} during teardown") + + +def delete_created_block_queue_buffer_profiles(duthost, profiles): + """ + Delete the blocking-queue buffer profiles created on demand during setup. + + Only profiles that ``set_buffer_profile_for_block_queue`` created (platforms whose base + configuration lacked them, such as the VPP virtual switch) are passed here; on SKUs that + already define these profiles nothing is created and nothing is deleted, so behavior there + is unchanged. Removing them keeps CONFIG_DB clean and preserves test isolation across runs. + + Args: + duthost: DUT host object + profiles (set or list): Buffer profile names created during setup + """ + for profile in sorted(set(p for p in profiles if p)): + duthost.shell(f"redis-cli -n 4 del 'BUFFER_PROFILE|{profile}'") + logger.info(f"Deleted on-demand blocking-queue buffer profile '{profile}' during teardown") + def create_trim_queue_test_buffer_profile(duthost): """