Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env python3
0002 # SPDX-License-Identifier: GPL-2.0
0003 
0004 from subprocess import PIPE, Popen
0005 import json
0006 import time
0007 import argparse
0008 import collections
0009 import sys
0010 
0011 #
0012 # Test port split configuration using devlink-port lanes attribute.
0013 # The test is skipped in case the attribute is not available.
0014 #
0015 # First, check that all the ports with 1 lane fail to split.
0016 # Second, check that all the ports with more than 1 lane can be split
0017 # to all valid configurations (e.g., split to 2, split to 4 etc.)
0018 #
0019 
0020 
0021 # Kselftest framework requirement - SKIP code is 4
0022 KSFT_SKIP=4
0023 Port = collections.namedtuple('Port', 'bus_info name')
0024 
0025 
0026 def run_command(cmd, should_fail=False):
0027     """
0028     Run a command in subprocess.
0029     Return: Tuple of (stdout, stderr).
0030     """
0031 
0032     p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
0033     stdout, stderr = p.communicate()
0034     stdout, stderr = stdout.decode(), stderr.decode()
0035 
0036     if stderr != "" and not should_fail:
0037         print("Error sending command: %s" % cmd)
0038         print(stdout)
0039         print(stderr)
0040     return stdout, stderr
0041 
0042 
0043 class devlink_ports(object):
0044     """
0045     Class that holds information on the devlink ports, required to the tests;
0046     if_names: A list of interfaces in the devlink ports.
0047     """
0048 
0049     def get_if_names(dev):
0050         """
0051         Get a list of physical devlink ports.
0052         Return: Array of tuples (bus_info/port, if_name).
0053         """
0054 
0055         arr = []
0056 
0057         cmd = "devlink -j port show"
0058         stdout, stderr = run_command(cmd)
0059         assert stderr == ""
0060         ports = json.loads(stdout)['port']
0061 
0062         for port in ports:
0063             if dev in port:
0064                 if ports[port]['flavour'] == 'physical':
0065                     arr.append(Port(bus_info=port, name=ports[port]['netdev']))
0066 
0067         return arr
0068 
0069     def __init__(self, dev):
0070         self.if_names = devlink_ports.get_if_names(dev)
0071 
0072 
0073 def get_max_lanes(port):
0074     """
0075     Get the $port's maximum number of lanes.
0076     Return: number of lanes, e.g. 1, 2, 4 and 8.
0077     """
0078 
0079     cmd = "devlink -j port show %s" % port
0080     stdout, stderr = run_command(cmd)
0081     assert stderr == ""
0082     values = list(json.loads(stdout)['port'].values())[0]
0083 
0084     if 'lanes' in values:
0085         lanes = values['lanes']
0086     else:
0087         lanes = 0
0088     return lanes
0089 
0090 
0091 def get_split_ability(port):
0092     """
0093     Get the $port split ability.
0094     Return: split ability, true or false.
0095     """
0096 
0097     cmd = "devlink -j port show %s" % port.name
0098     stdout, stderr = run_command(cmd)
0099     assert stderr == ""
0100     values = list(json.loads(stdout)['port'].values())[0]
0101 
0102     return values['splittable']
0103 
0104 
0105 def split(k, port, should_fail=False):
0106     """
0107     Split $port into $k ports.
0108     If should_fail == True, the split should fail. Otherwise, should pass.
0109     Return: Array of sub ports after splitting.
0110             If the $port wasn't split, the array will be empty.
0111     """
0112 
0113     cmd = "devlink port split %s count %s" % (port.bus_info, k)
0114     stdout, stderr = run_command(cmd, should_fail=should_fail)
0115 
0116     if should_fail:
0117         if not test(stderr != "", "%s is unsplittable" % port.name):
0118             print("split an unsplittable port %s" % port.name)
0119             return create_split_group(port, k)
0120     else:
0121         if stderr == "":
0122             return create_split_group(port, k)
0123         print("didn't split a splittable port %s" % port.name)
0124 
0125     return []
0126 
0127 
0128 def unsplit(port):
0129     """
0130     Unsplit $port.
0131     """
0132 
0133     cmd = "devlink port unsplit %s" % port
0134     stdout, stderr = run_command(cmd)
0135     test(stderr == "", "Unsplit port %s" % port)
0136 
0137 
0138 def exists(port, dev):
0139     """
0140     Check if $port exists in the devlink ports.
0141     Return: True is so, False otherwise.
0142     """
0143 
0144     return any(dev_port.name == port
0145                for dev_port in devlink_ports.get_if_names(dev))
0146 
0147 
0148 def exists_and_lanes(ports, lanes, dev):
0149     """
0150     Check if every port in the list $ports exists in the devlink ports and has
0151     $lanes number of lanes after splitting.
0152     Return: True if both are True, False otherwise.
0153     """
0154 
0155     for port in ports:
0156         max_lanes = get_max_lanes(port)
0157         if not exists(port, dev):
0158             print("port %s doesn't exist in devlink ports" % port)
0159             return False
0160         if max_lanes != lanes:
0161             print("port %s has %d lanes, but %s were expected"
0162                   % (port, lanes, max_lanes))
0163             return False
0164     return True
0165 
0166 
0167 def test(cond, msg):
0168     """
0169     Check $cond and print a message accordingly.
0170     Return: True is pass, False otherwise.
0171     """
0172 
0173     if cond:
0174         print("TEST: %-60s [ OK ]" % msg)
0175     else:
0176         print("TEST: %-60s [FAIL]" % msg)
0177 
0178     return cond
0179 
0180 
0181 def create_split_group(port, k):
0182     """
0183     Create the split group for $port.
0184     Return: Array with $k elements, which are the split port group.
0185     """
0186 
0187     return list(port.name + "s" + str(i) for i in range(k))
0188 
0189 
0190 def split_unsplittable_port(port, k):
0191     """
0192     Test that splitting of unsplittable port fails.
0193     """
0194 
0195     # split to max
0196     new_split_group = split(k, port, should_fail=True)
0197 
0198     if new_split_group != []:
0199         unsplit(port.bus_info)
0200 
0201 
0202 def split_splittable_port(port, k, lanes, dev):
0203     """
0204     Test that splitting of splittable port passes correctly.
0205     """
0206 
0207     new_split_group = split(k, port)
0208 
0209     # Once the split command ends, it takes some time to the sub ifaces'
0210     # to get their names. Use udevadm to continue only when all current udev
0211     # events are handled.
0212     cmd = "udevadm settle"
0213     stdout, stderr = run_command(cmd)
0214     assert stderr == ""
0215 
0216     if new_split_group != []:
0217         test(exists_and_lanes(new_split_group, lanes/k, dev),
0218              "split port %s into %s" % (port.name, k))
0219 
0220     unsplit(port.bus_info)
0221 
0222 
0223 def make_parser():
0224     parser = argparse.ArgumentParser(description='A test for port splitting.')
0225     parser.add_argument('--dev',
0226                         help='The devlink handle of the device under test. ' +
0227                              'The default is the first registered devlink ' +
0228                              'handle.')
0229 
0230     return parser
0231 
0232 
0233 def main(cmdline=None):
0234     parser = make_parser()
0235     args = parser.parse_args(cmdline)
0236 
0237     dev = args.dev
0238     if not dev:
0239         cmd = "devlink -j dev show"
0240         stdout, stderr = run_command(cmd)
0241         assert stderr == ""
0242 
0243         devs = json.loads(stdout)['dev']
0244         if devs:
0245             dev = list(devs.keys())[0]
0246         else:
0247             print("no devlink device was found, test skipped")
0248             sys.exit(KSFT_SKIP)
0249 
0250     cmd = "devlink dev show %s" % dev
0251     stdout, stderr = run_command(cmd)
0252     if stderr != "":
0253         print("devlink device %s can not be found" % dev)
0254         sys.exit(1)
0255 
0256     ports = devlink_ports(dev)
0257 
0258     for port in ports.if_names:
0259         max_lanes = get_max_lanes(port.name)
0260 
0261         # If max lanes is 0, do not test port splitting at all
0262         if max_lanes == 0:
0263             continue
0264 
0265         # If 1 lane, shouldn't be able to split
0266         elif max_lanes == 1:
0267             test(not get_split_ability(port),
0268                  "%s should not be able to split" % port.name)
0269             split_unsplittable_port(port, max_lanes)
0270 
0271         # Else, splitting should pass and all the split ports should exist.
0272         else:
0273             lane = max_lanes
0274             test(get_split_ability(port),
0275                  "%s should be able to split" % port.name)
0276             while lane > 1:
0277                 split_splittable_port(port, lane, max_lanes, dev)
0278 
0279                 lane //= 2
0280 
0281 
0282 if __name__ == "__main__":
0283     main()