~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/drivers/net/mlxsw/sharedbuffer_configuration.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/usr/bin/env python
  2 # SPDX-License-Identifier: GPL-2.0
  3 
  4 import subprocess
  5 import json as j
  6 import random
  7 
  8 
  9 class SkipTest(Exception):
 10     pass
 11 
 12 
 13 class RandomValuePicker:
 14     """
 15     Class for storing shared buffer configuration. Can handle 3 different
 16     objects, pool, tcbind and portpool. Provide an interface to get random
 17     values for a specific object type as the follow:
 18       1. Pool:
 19          - random size
 20 
 21       2. TcBind:
 22          - random pool number
 23          - random threshold
 24 
 25       3. PortPool:
 26          - random threshold
 27     """
 28     def __init__(self, pools):
 29         self._pools = []
 30         for pool in pools:
 31             self._pools.append(pool)
 32 
 33     def _cell_size(self):
 34         return self._pools[0]["cell_size"]
 35 
 36     def _get_static_size(self, th):
 37         # For threshold of 16, this works out to be about 12MB on Spectrum-1,
 38         # and about 17MB on Spectrum-2.
 39         return th * 8000 * self._cell_size()
 40 
 41     def _get_size(self):
 42         return self._get_static_size(16)
 43 
 44     def _get_thtype(self):
 45         return "static"
 46 
 47     def _get_th(self, pool):
 48         # Threshold value could be any integer between 3 to 16
 49         th = random.randint(3, 16)
 50         if pool["thtype"] == "dynamic":
 51             return th
 52         else:
 53             return self._get_static_size(th)
 54 
 55     def _get_pool(self, direction):
 56         ing_pools = []
 57         egr_pools = []
 58         for pool in self._pools:
 59             if pool["type"] == "ingress":
 60                 ing_pools.append(pool)
 61             else:
 62                 egr_pools.append(pool)
 63         if direction == "ingress":
 64             arr = ing_pools
 65         else:
 66             arr = egr_pools
 67         return arr[random.randint(0, len(arr) - 1)]
 68 
 69     def get_value(self, objid):
 70         if isinstance(objid, Pool):
 71             if objid["pool"] in [4, 8, 9, 10]:
 72                 # The threshold type of pools 4, 8, 9 and 10 cannot be changed
 73                 raise SkipTest()
 74             else:
 75                 return (self._get_size(), self._get_thtype())
 76         if isinstance(objid, TcBind):
 77             if objid["tc"] >= 8:
 78                 # Multicast TCs cannot be changed
 79                 raise SkipTest()
 80             else:
 81                 pool = self._get_pool(objid["type"])
 82                 th = self._get_th(pool)
 83                 pool_n = pool["pool"]
 84                 return (pool_n, th)
 85         if isinstance(objid, PortPool):
 86             pool_n = objid["pool"]
 87             pool = self._pools[pool_n]
 88             assert pool["pool"] == pool_n
 89             th = self._get_th(pool)
 90             return (th,)
 91 
 92 
 93 class RecordValuePickerException(Exception):
 94     pass
 95 
 96 
 97 class RecordValuePicker:
 98     """
 99     Class for storing shared buffer configuration. Can handle 2 different
100     objects, pool and tcbind. Provide an interface to get the stored values per
101     object type.
102     """
103     def __init__(self, objlist):
104         self._recs = []
105         for item in objlist:
106             self._recs.append({"objid": item, "value": item.var_tuple()})
107 
108     def get_value(self, objid):
109         if isinstance(objid, Pool) and objid["pool"] in [4, 8, 9, 10]:
110             # The threshold type of pools 4, 8, 9 and 10 cannot be changed
111             raise SkipTest()
112         if isinstance(objid, TcBind) and objid["tc"] >= 8:
113             # Multicast TCs cannot be changed
114             raise SkipTest()
115         for rec in self._recs:
116             if rec["objid"].weak_eq(objid):
117                 return rec["value"]
118         raise RecordValuePickerException()
119 
120 
121 def run_cmd(cmd, json=False):
122     out = subprocess.check_output(cmd, shell=True)
123     if json:
124         return j.loads(out)
125     return out
126 
127 
128 def run_json_cmd(cmd):
129     return run_cmd(cmd, json=True)
130 
131 
132 def log_test(test_name, err_msg=None):
133     if err_msg:
134         print("\t%s" % err_msg)
135         print("TEST: %-80s  [FAIL]" % test_name)
136     else:
137         print("TEST: %-80s  [ OK ]" % test_name)
138 
139 
140 class CommonItem(dict):
141     varitems = []
142 
143     def var_tuple(self):
144         ret = []
145         self.varitems.sort()
146         for key in self.varitems:
147             ret.append(self[key])
148         return tuple(ret)
149 
150     def weak_eq(self, other):
151         for key in self:
152             if key in self.varitems:
153                 continue
154             if self[key] != other[key]:
155                 return False
156         return True
157 
158 
159 class CommonList(list):
160     def get_by(self, by_obj):
161         for item in self:
162             if item.weak_eq(by_obj):
163                 return item
164         return None
165 
166     def del_by(self, by_obj):
167         for item in self:
168             if item.weak_eq(by_obj):
169                 self.remove(item)
170 
171 
172 class Pool(CommonItem):
173     varitems = ["size", "thtype"]
174 
175     def dl_set(self, dlname, size, thtype):
176         run_cmd("devlink sb pool set {} sb {} pool {} size {} thtype {}".format(dlname, self["sb"],
177                                                                                 self["pool"],
178                                                                                 size, thtype))
179 
180 
181 class PoolList(CommonList):
182     pass
183 
184 
185 def get_pools(dlname, direction=None):
186     d = run_json_cmd("devlink sb pool show -j")
187     pools = PoolList()
188     for pooldict in d["pool"][dlname]:
189         if not direction or direction == pooldict["type"]:
190             pools.append(Pool(pooldict))
191     return pools
192 
193 
194 def do_check_pools(dlname, pools, vp):
195     for pool in pools:
196         pre_pools = get_pools(dlname)
197         try:
198             (size, thtype) = vp.get_value(pool)
199         except SkipTest:
200             continue
201         pool.dl_set(dlname, size, thtype)
202         post_pools = get_pools(dlname)
203         pool = post_pools.get_by(pool)
204 
205         err_msg = None
206         if pool["size"] != size:
207             err_msg = "Incorrect pool size (got {}, expected {})".format(pool["size"], size)
208         if pool["thtype"] != thtype:
209             err_msg = "Incorrect pool threshold type (got {}, expected {})".format(pool["thtype"], thtype)
210 
211         pre_pools.del_by(pool)
212         post_pools.del_by(pool)
213         if pre_pools != post_pools:
214             err_msg = "Other pool setup changed as well"
215         log_test("pool {} of sb {} set verification".format(pool["pool"],
216                                                             pool["sb"]), err_msg)
217 
218 
219 def check_pools(dlname, pools):
220     # Save defaults
221     record_vp = RecordValuePicker(pools)
222 
223     # For each pool, set random size and static threshold type
224     do_check_pools(dlname, pools, RandomValuePicker(pools))
225 
226     # Restore defaults
227     do_check_pools(dlname, pools, record_vp)
228 
229 
230 class TcBind(CommonItem):
231     varitems = ["pool", "threshold"]
232 
233     def __init__(self, port, d):
234         super(TcBind, self).__init__(d)
235         self["dlportname"] = port.name
236 
237     def dl_set(self, pool, th):
238         run_cmd("devlink sb tc bind set {} sb {} tc {} type {} pool {} th {}".format(self["dlportname"],
239                                                                                      self["sb"],
240                                                                                      self["tc"],
241                                                                                      self["type"],
242                                                                                      pool, th))
243 
244 
245 class TcBindList(CommonList):
246     pass
247 
248 
249 def get_tcbinds(ports, verify_existence=False):
250     d = run_json_cmd("devlink sb tc bind show -j -n")
251     tcbinds = TcBindList()
252     for port in ports:
253         err_msg = None
254         if port.name not in d["tc_bind"] or len(d["tc_bind"][port.name]) == 0:
255             err_msg = "No tc bind for port"
256         else:
257             for tcbinddict in d["tc_bind"][port.name]:
258                 tcbinds.append(TcBind(port, tcbinddict))
259         if verify_existence:
260             log_test("tc bind existence for port {} verification".format(port.name), err_msg)
261     return tcbinds
262 
263 
264 def do_check_tcbind(ports, tcbinds, vp):
265     for tcbind in tcbinds:
266         pre_tcbinds = get_tcbinds(ports)
267         try:
268             (pool, th) = vp.get_value(tcbind)
269         except SkipTest:
270             continue
271         tcbind.dl_set(pool, th)
272         post_tcbinds = get_tcbinds(ports)
273         tcbind = post_tcbinds.get_by(tcbind)
274 
275         err_msg = None
276         if tcbind["pool"] != pool:
277             err_msg = "Incorrect pool (got {}, expected {})".format(tcbind["pool"], pool)
278         if tcbind["threshold"] != th:
279             err_msg = "Incorrect threshold (got {}, expected {})".format(tcbind["threshold"], th)
280 
281         pre_tcbinds.del_by(tcbind)
282         post_tcbinds.del_by(tcbind)
283         if pre_tcbinds != post_tcbinds:
284             err_msg = "Other tc bind setup changed as well"
285         log_test("tc bind {}-{} of sb {} set verification".format(tcbind["dlportname"],
286                                                                   tcbind["tc"],
287                                                                   tcbind["sb"]), err_msg)
288 
289 
290 def check_tcbind(dlname, ports, pools):
291     tcbinds = get_tcbinds(ports, verify_existence=True)
292 
293     # Save defaults
294     record_vp = RecordValuePicker(tcbinds)
295 
296     # Bind each port and unicast TC (TCs < 8) to a random pool and a random
297     # threshold
298     do_check_tcbind(ports, tcbinds, RandomValuePicker(pools))
299 
300     # Restore defaults
301     do_check_tcbind(ports, tcbinds, record_vp)
302 
303 
304 class PortPool(CommonItem):
305     varitems = ["threshold"]
306 
307     def __init__(self, port, d):
308         super(PortPool, self).__init__(d)
309         self["dlportname"] = port.name
310 
311     def dl_set(self, th):
312         run_cmd("devlink sb port pool set {} sb {} pool {} th {}".format(self["dlportname"],
313                                                                          self["sb"],
314                                                                          self["pool"], th))
315 
316 
317 class PortPoolList(CommonList):
318     pass
319 
320 
321 def get_portpools(ports, verify_existence=False):
322     d = run_json_cmd("devlink sb port pool -j -n")
323     portpools = PortPoolList()
324     for port in ports:
325         err_msg = None
326         if port.name not in d["port_pool"] or len(d["port_pool"][port.name]) == 0:
327             err_msg = "No port pool for port"
328         else:
329             for portpooldict in d["port_pool"][port.name]:
330                 portpools.append(PortPool(port, portpooldict))
331         if verify_existence:
332             log_test("port pool existence for port {} verification".format(port.name), err_msg)
333     return portpools
334 
335 
336 def do_check_portpool(ports, portpools, vp):
337     for portpool in portpools:
338         pre_portpools = get_portpools(ports)
339         (th,) = vp.get_value(portpool)
340         portpool.dl_set(th)
341         post_portpools = get_portpools(ports)
342         portpool = post_portpools.get_by(portpool)
343 
344         err_msg = None
345         if portpool["threshold"] != th:
346             err_msg = "Incorrect threshold (got {}, expected {})".format(portpool["threshold"], th)
347 
348         pre_portpools.del_by(portpool)
349         post_portpools.del_by(portpool)
350         if pre_portpools != post_portpools:
351             err_msg = "Other port pool setup changed as well"
352         log_test("port pool {}-{} of sb {} set verification".format(portpool["dlportname"],
353                                                                     portpool["pool"],
354                                                                     portpool["sb"]), err_msg)
355 
356 
357 def check_portpool(dlname, ports, pools):
358     portpools = get_portpools(ports, verify_existence=True)
359 
360     # Save defaults
361     record_vp = RecordValuePicker(portpools)
362 
363     # For each port pool, set a random threshold
364     do_check_portpool(ports, portpools, RandomValuePicker(pools))
365 
366     # Restore defaults
367     do_check_portpool(ports, portpools, record_vp)
368 
369 
370 class Port:
371     def __init__(self, name):
372         self.name = name
373 
374 
375 class PortList(list):
376     pass
377 
378 
379 def get_ports(dlname):
380     d = run_json_cmd("devlink port show -j")
381     ports = PortList()
382     for name in d["port"]:
383         if name.find(dlname) == 0 and d["port"][name]["flavour"] == "physical":
384             ports.append(Port(name))
385     return ports
386 
387 
388 def get_device():
389     devices_info = run_json_cmd("devlink -j dev info")["info"]
390     for d in devices_info:
391         if "mlxsw_spectrum" in devices_info[d]["driver"]:
392             return d
393     return None
394 
395 
396 class UnavailableDevlinkNameException(Exception):
397     pass
398 
399 
400 def test_sb_configuration():
401     # Use static seed
402     random.seed(0)
403 
404     dlname = get_device()
405     if not dlname:
406         raise UnavailableDevlinkNameException()
407 
408     ports = get_ports(dlname)
409     pools = get_pools(dlname)
410 
411     check_pools(dlname, pools)
412     check_tcbind(dlname, ports, pools)
413     check_portpool(dlname, ports, pools)
414 
415 
416 test_sb_configuration()

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php