Skip to content

Commit

Permalink
[QOS - Test PFC Pause] Multi VLAN Support (sonic-net#16725)
Browse files Browse the repository at this point in the history
What is the motivation for this PR?
As new testbeds are being created with more VLANs, the assumption that a device should only contain 1 VLAN no longer holds. As such, certain helpers/parts of the framework need to be modified to allow for multiple VLANs to be present and tested.

How did you do it?
Added a get_all_vlans function to extract all vlans from the duthost object
The functions which get information related to vlans (get_active_vlan_members and get_vlan_subnet) now take a vlan configuration dictionary (which itself is taken from the get_all_vlans function)
pfc_test_setup now returns a list of VLAN configurations, instead of just one
The run_test wrapper now runs the relevant test for each VLAN supplied
Also removed gen_testbed_t0, which is not used anywhere (validated with grep)
How did you verify/test it?
Before this change, running the qos/test_pfc_pause.py on a testbed with multiple VLANs produced the following output:

@pytest.fixture(scope="module", autouse=True)
    def pfc_test_setup(duthosts, rand_one_dut_hostname, tbinfo, ptfhost):
        """
        Generate configurations for the tests
   
        Args:
            duthosts(AnsibleHost) : multi dut instance
            rand_one_dut_hostname(string) : one of the dut instances from the multi dut
   
        Yields:
            setup(dict): DUT interfaces, PTF interfaces, PTF IP addresses, and PTF MAC addresses
        """
   
        """ Get all the active physical interfaces enslaved to the Vlan """
        """ These interfaces are actually server-faced interfaces at T0 """
        duthost = duthosts[rand_one_dut_hostname]
>       vlan_members, vlan_id = get_active_vlan_members(duthost)
E       TypeError: cannot unpack non-iterable NoneType object
With these changes, it is now successfully running:
image

Any platform specific information?
Any platform with only one VLAN - as each of the new lists/dicts will only contain one VLAN, iterating through them will cause the same behaviour as before.
  • Loading branch information
matthew-soulsby authored and mssonicbld committed Feb 19, 2025
1 parent ba5001f commit 289bf62
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 179 deletions.
70 changes: 20 additions & 50 deletions tests/qos/qos_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from .qos_fixtures import lossless_prio_dscp_map, leaf_fanouts # noqa F401
import re
import os
import random

PFC_GEN_FILE = 'pfc_gen.py'
PFC_GEN_LOCAL_PATH = '../../ansible/roles/test/files/helpers/pfc_gen.py'
Expand Down Expand Up @@ -148,27 +147,32 @@ def stop_pause(host_ans, pkt_gen_path):
host_ans.host.shell(cmd)


def get_active_vlan_members(host_ans):
def get_all_vlans(host_ans):
"""
@Summary: Get all the active physical interfaces enslaved to a Vlan
@Summary: Get all vlans active on a DUT from the device's minigraph facts
@param host_ans: Ansible host instance of the device
@return: Return the list of active physical interfaces
@return: Dictionary, mapping dictionaries representing each vlan's values to the vlan name
"""
mg_facts = host_ans.minigraph_facts(
host=host_ans.hostname)['ansible_facts']
mg_vlans = mg_facts['minigraph_vlans']

if len(mg_vlans) != 1:
print('There should be only one Vlan at the DUT')
return None
return mg_vlans


def get_active_vlan_members(host_ans, vlan):
"""
@Summary: Get all the active physical interfaces enslaved to a Vlan
@param host_ans: Ansible host instance of the device
@param vlan: Dictionary containing a single vlan's `name`, `members` and `vlanid`
@return: Return the list of active physical interfaces
"""
""" Get all the Vlan memebrs """
vlan_intf = list(mg_vlans.keys())[0]
vlan_members = mg_vlans[vlan_intf]['members']
vlan_members = vlan['members']
vlan_id = None
if 'type' in mg_vlans[vlan_intf] and mg_vlans[vlan_intf]['type'] is not None \
and 'Tagged' in mg_vlans[vlan_intf]['type']:
vlan_id = mg_vlans[vlan_intf]['vlanid']
if 'type' in vlan and vlan['type'] is not None \
and 'Tagged' in vlan['type']:
vlan_id = vlan['vlanid']

""" Filter inactive Vlan members """
active_intfs = get_active_intfs(host_ans)
Expand All @@ -177,56 +181,22 @@ def get_active_vlan_members(host_ans):
return vlan_members, vlan_id


def get_vlan_subnet(host_ans):
def get_vlan_subnet(host_ans, vlan):
"""
@Summary: Get Vlan subnet of a T0 device
@param host_ans: Ansible host instance of the device
@param vlan: Dictionary containing a single vlan's `name`, `members` and `vlanid`
@return: Return Vlan subnet, e.g., "192.168.1.1/24"
"""
mg_facts = host_ans.minigraph_facts(
host=host_ans.hostname)['ansible_facts']
mg_vlans = mg_facts['minigraph_vlans']

if len(mg_vlans) != 1:
print('There should be only one Vlan at the DUT')
return None

mg_vlan_intfs = mg_facts['minigraph_vlan_interfaces']
vlan_subnet = ansible_stdout_to_str(mg_vlan_intfs[0]['subnet'])
vlan_intf = [curr_intf for curr_intf in mg_vlan_intfs if curr_intf['attachto'] == vlan['name']][0]
vlan_subnet = ansible_stdout_to_str(vlan_intf['subnet'])
return vlan_subnet


def gen_testbed_t0(duthost):
"""
@Summary: Generate a T0 testbed configuration
@param duthost: The object for interacting with DUT through ansible
@return: Return four values: DUT interfaces, PTF interfaces, PTF IP addresses, and PTF MAC addresses,
"""

""" Get all the active physical interfaces enslaved to the Vlan """
""" These interfaces are actually server-faced interfaces at T0 """
vlan_members = get_active_vlan_members(duthost)

""" Get Vlan subnet """
vlan_subnet = get_vlan_subnet(duthost)

""" Generate IP addresses for servers in the Vlan """
vlan_ip_addrs = get_addrs_in_subnet(vlan_subnet, len(vlan_members))

""" Generate MAC addresses 00:00:00:00:00:XX for servers in the Vlan """
vlan_mac_addrs = [5 * '00:' + format(k, '02x')
for k in random.sample(list(range(1, 256)), len(vlan_members))]

""" Find correspoinding interfaces on PTF """
phy_intfs = get_phy_intfs(duthost)
phy_intfs.sort(key=natural_keys)
vlan_members.sort(key=natural_keys)
vlan_members_index = [phy_intfs.index(intf) for intf in vlan_members]
ptf_intfs = ['eth' + str(i) for i in vlan_members_index]

return vlan_members, ptf_intfs, vlan_ip_addrs, vlan_mac_addrs


def setup_testbed(fanouthosts, ptfhost, leaf_fanouts): # noqa F811
"""
@Summary: Set up the testbed
Expand Down
Loading

0 comments on commit 289bf62

Please # to comment.