2 # SPDX-License-Identifier: GPL-2.0
9 class SkipTest(Exception):
13 class RandomValuePicker
:
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:
28 def __init__(self
, pools
):
31 self
._pools
.append(pool
)
34 return self
._pools
[0]["cell_size"]
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
()
42 return self
._get
_static
_size
(16)
44 def _get_thtype(self
):
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":
53 return self
._get
_static
_size
(th
)
55 def _get_pool(self
, direction
):
58 for pool
in self
._pools
:
59 if pool
["type"] == "ingress":
60 ing_pools
.append(pool
)
62 egr_pools
.append(pool
)
63 if direction
== "ingress":
67 return arr
[random
.randint(0, len(arr
) - 1)]
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
75 return (self
._get
_size
(), self
._get
_thtype
())
76 if isinstance(objid
, TcBind
):
78 # Multicast TCs cannot be changed
81 pool
= self
._get
_pool
(objid
["type"])
82 th
= self
._get
_th
(pool
)
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
)
93 class RecordValuePickerException(Exception):
97 class RecordValuePicker
:
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
103 def __init__(self
, objlist
):
106 self
._recs
.append({"objid": item
, "value": item
.var_tuple()})
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
112 if isinstance(objid
, TcBind
) and objid
["tc"] >= 8:
113 # Multicast TCs cannot be changed
115 for rec
in self
._recs
:
116 if rec
["objid"].weak_eq(objid
):
118 raise RecordValuePickerException()
121 def run_cmd(cmd
, json
=False):
122 out
= subprocess
.check_output(cmd
, shell
=True)
128 def run_json_cmd(cmd
):
129 return run_cmd(cmd
, json
=True)
132 def log_test(test_name
, err_msg
=None):
134 print("\t%s" % err_msg
)
135 print("TEST: %-80s [FAIL]" % test_name
)
137 print("TEST: %-80s [ OK ]" % test_name
)
140 class CommonItem(dict):
146 for key
in self
.varitems
:
147 ret
.append(self
[key
])
150 def weak_eq(self
, other
):
152 if key
in self
.varitems
:
154 if self
[key
] != other
[key
]:
159 class CommonList(list):
160 def get_by(self
, by_obj
):
162 if item
.weak_eq(by_obj
):
166 def del_by(self
, by_obj
):
168 if item
.weak_eq(by_obj
):
172 class Pool(CommonItem
):
173 varitems
= ["size", "thtype"]
175 def dl_set(self
, dlname
, size
, thtype
):
176 run_cmd("devlink sb pool set {} sb {} pool {} size {} thtype {}".format(dlname
, self
["sb"],
181 class PoolList(CommonList
):
185 def get_pools(dlname
, direction
=None):
186 d
= run_json_cmd("devlink sb pool show -j")
188 for pooldict
in d
["pool"][dlname
]:
189 if not direction
or direction
== pooldict
["type"]:
190 pools
.append(Pool(pooldict
))
194 def do_check_pools(dlname
, pools
, vp
):
196 pre_pools
= get_pools(dlname
)
198 (size
, thtype
) = vp
.get_value(pool
)
201 pool
.dl_set(dlname
, size
, thtype
)
202 post_pools
= get_pools(dlname
)
203 pool
= post_pools
.get_by(pool
)
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
)
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
)
219 def check_pools(dlname
, pools
):
221 record_vp
= RecordValuePicker(pools
)
223 # For each pool, set random size and static threshold type
224 do_check_pools(dlname
, pools
, RandomValuePicker(pools
))
227 do_check_pools(dlname
, pools
, record_vp
)
230 class TcBind(CommonItem
):
231 varitems
= ["pool", "threshold"]
233 def __init__(self
, port
, d
):
234 super(TcBind
, self
).__init
__(d
)
235 self
["dlportname"] = port
.name
237 def dl_set(self
, pool
, th
):
238 run_cmd("devlink sb tc bind set {} sb {} tc {} type {} pool {} th {}".format(self
["dlportname"],
245 class TcBindList(CommonList
):
249 def get_tcbinds(ports
, verify_existence
=False):
250 d
= run_json_cmd("devlink sb tc bind show -j -n")
251 tcbinds
= TcBindList()
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"
257 for tcbinddict
in d
["tc_bind"][port
.name
]:
258 tcbinds
.append(TcBind(port
, tcbinddict
))
260 log_test("tc bind existence for port {} verification".format(port
.name
), err_msg
)
264 def do_check_tcbind(ports
, tcbinds
, vp
):
265 for tcbind
in tcbinds
:
266 pre_tcbinds
= get_tcbinds(ports
)
268 (pool
, th
) = vp
.get_value(tcbind
)
271 tcbind
.dl_set(pool
, th
)
272 post_tcbinds
= get_tcbinds(ports
)
273 tcbind
= post_tcbinds
.get_by(tcbind
)
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
)
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"],
287 tcbind
["sb"]), err_msg
)
290 def check_tcbind(dlname
, ports
, pools
):
291 tcbinds
= get_tcbinds(ports
, verify_existence
=True)
294 record_vp
= RecordValuePicker(tcbinds
)
296 # Bind each port and unicast TC (TCs < 8) to a random pool and a random
298 do_check_tcbind(ports
, tcbinds
, RandomValuePicker(pools
))
301 do_check_tcbind(ports
, tcbinds
, record_vp
)
304 class PortPool(CommonItem
):
305 varitems
= ["threshold"]
307 def __init__(self
, port
, d
):
308 super(PortPool
, self
).__init
__(d
)
309 self
["dlportname"] = port
.name
311 def dl_set(self
, th
):
312 run_cmd("devlink sb port pool set {} sb {} pool {} th {}".format(self
["dlportname"],
317 class PortPoolList(CommonList
):
321 def get_portpools(ports
, verify_existence
=False):
322 d
= run_json_cmd("devlink sb port pool -j -n")
323 portpools
= PortPoolList()
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"
329 for portpooldict
in d
["port_pool"][port
.name
]:
330 portpools
.append(PortPool(port
, portpooldict
))
332 log_test("port pool existence for port {} verification".format(port
.name
), err_msg
)
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
)
341 post_portpools
= get_portpools(ports
)
342 portpool
= post_portpools
.get_by(portpool
)
345 if portpool
["threshold"] != th
:
346 err_msg
= "Incorrect threshold (got {}, expected {})".format(portpool
["threshold"], th
)
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"],
354 portpool
["sb"]), err_msg
)
357 def check_portpool(dlname
, ports
, pools
):
358 portpools
= get_portpools(ports
, verify_existence
=True)
361 record_vp
= RecordValuePicker(portpools
)
363 # For each port pool, set a random threshold
364 do_check_portpool(ports
, portpools
, RandomValuePicker(pools
))
367 do_check_portpool(ports
, portpools
, record_vp
)
371 def __init__(self
, name
):
375 class PortList(list):
379 def get_ports(dlname
):
380 d
= run_json_cmd("devlink port show -j")
382 for name
in d
["port"]:
383 if name
.find(dlname
) == 0 and d
["port"][name
]["flavour"] == "physical":
384 ports
.append(Port(name
))
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"]:
396 class UnavailableDevlinkNameException(Exception):
400 def test_sb_configuration():
404 dlname
= get_device()
406 raise UnavailableDevlinkNameException()
408 ports
= get_ports(dlname
)
409 pools
= get_pools(dlname
)
411 check_pools(dlname
, pools
)
412 check_tcbind(dlname
, ports
, pools
)
413 check_portpool(dlname
, ports
, pools
)
416 test_sb_configuration()