From: Jiri Pirko jiri@mellanox.com
This recipe utilizes devlink app to test setup of all shared buffer configuration options.
Signed-off-by: Jiri Pirko jiri@mellanox.com --- recipes/switchdev/sharedbuffer.py | 305 +++++++++++++++++++++++++++++++++++++ recipes/switchdev/sharedbuffer.xml | 22 +++ 2 files changed, 327 insertions(+) create mode 100644 recipes/switchdev/sharedbuffer.py create mode 100644 recipes/switchdev/sharedbuffer.xml
diff --git a/recipes/switchdev/sharedbuffer.py b/recipes/switchdev/sharedbuffer.py new file mode 100644 index 0000000..28a6f44 --- /dev/null +++ b/recipes/switchdev/sharedbuffer.py @@ -0,0 +1,305 @@ +""" +Copyright 2016 Mellanox Technologies. All rights reserved. +Licensed under the GNU General Public License, version 2 as +published by the Free Software Foundation; see COPYING for details. +""" + +__author__ = """ +jiri@mellanox.com (Jiri Pirko) +""" + +from lnst.Controller.Task import ctl +from TestLib import TestLib +from time import sleep +import random + +class RandomValuePicker: + def __init__(self, pools): + self._pools = {"ingress": [], "egress": []} + for pool in pools: + self._pools[pool["type"]].append(pool["pool"]) + + def _get_size(self): + # support only this fixed size for now + return 12401088 + + def _get_thtype(self): + # support static threshold only for now + return "static" + + def _get_th(self): + # support dynamic threshold only for now + return random.randint(3,16) + + def _get_pool(self, direction): + arr = self._pools[direction] + return arr[random.randint(0, len(arr) - 1)] + + def get_value(self, objid): + if isinstance(objid, Pool): + return (self._get_size(), self._get_thtype()) + if isinstance(objid, TcBind): + pool = self._get_pool(objid["type"]) + th = self._get_th() + return (pool, th) + if isinstance(objid, PortPool): + return (self._get_th(),) + +class RecordValuePickerException(Exception): + pass + +class RecordValuePicker: + def __init__(self, objlist): + self._recs = [] + for item in objlist: + self._recs.append({"objid": item, "value": item.var_tuple()}) + + def get_value(self, objid): + for rec in self._recs: + if rec["objid"].weak_eq(objid): + return rec["value"] + raise RecordValuePickerException() + +class RunCmdException(Exception): + pass + +def run_cmd(host, cmd, json=False): + cmd = host.run(cmd, json=json) + if not cmd.passed(): + raise RunCmdException(cmd.get_result()["res_data"]["stderr"]) + return cmd.out() + +def run_json_cmd(host, cmd): + return run_cmd(host, cmd, json=True) + +class CommonItem(dict): + varitems = [] + + def var_tuple(self): + ret = [] + self.varitems.sort() + for key in self.varitems: + ret.append(self[key]) + return tuple(ret) + + def weak_eq(self, other): + for key in self: + if key in self.varitems: + continue + if self[key] != other[key]: + return False + return True + +class CommonList(list): + def get_by(self, by_obj): + for item in self: + if item.weak_eq(by_obj): + return item + return None + + def del_by(self, by_obj): + for item in self: + if item.weak_eq(by_obj): + self.remove(item) + +class Pool(CommonItem): + varitems = ["size", "thtype"] + + def dl_set(self, sw, dlname, size, thtype): + run_cmd(sw, "devlink sb pool set {} sb {} pool {} size {} thtype {}".format(dlname, self["sb"], + self["pool"], + size, thtype)) + +class PoolList(CommonList): + pass + +def get_pools(sw, dlname, direction=None): + d = run_json_cmd(sw, "devlink sb pool show -j") + pools = PoolList() + for pooldict in d["pool"][dlname]: + if not direction or direction == pooldict["type"]: + pools.append(Pool(pooldict)) + return pools + +def do_check_pools(tl, sw, dlname, pools, vp): + for pool in pools: + pre_pools = get_pools(sw, dlname) + (size, thtype) = vp.get_value(pool) + pool.dl_set(sw, dlname, size, thtype) + post_pools = get_pools(sw, dlname) + pool = post_pools.get_by(pool) + + err_msg = None + if pool["size"] != size: + err_msg = "Incorrect pool size (got {}, expected {})".format(pool["size"], size) + if pool["thtype"] != thtype: + err_msg = "Incorrect pool threshold type (got {}, expected {})".format(pool["thtype"], thtype) + + pre_pools.del_by(pool) + post_pools.del_by(pool) + if pre_pools != post_pools: + err_msg = "Other pool setup changed as well" + tl.custom(sw, "pool {} of sb {} set verification".format(pool["pool"], + pool["sb"]), err_msg) + +def check_pools(tl, sw, dlname, pools): + record_vp = RecordValuePicker(pools) + do_check_pools(tl, sw, dlname, pools, RandomValuePicker(pools)) + do_check_pools(tl, sw, dlname, pools, record_vp) + +class TcBind(CommonItem): + varitems = ["pool", "threshold"] + + def __init__(self, port, d): + super(TcBind, self).__init__(d) + self["dlportname"] = port.name + + def dl_set(self, sw, pool, th): + run_cmd(sw, "devlink sb tc bind set {} sb {} tc {} type {} pool {} th {}".format(self["dlportname"], + self["sb"], + self["tc"], + self["type"], + pool, th)) + +class TcBindList(CommonList): + pass + +def get_tcbinds(tl, sw, ports, verify_existence=False): + d = run_json_cmd(sw, "devlink sb tc bind show -j -n") + tcbinds = TcBindList() + for port in ports: + err_msg = None + if not port.name in d["tc_bind"] or len(d["tc_bind"][port.name]) == 0: + err_msg = "No tc bind for port" + else: + for tcbinddict in d["tc_bind"][port.name]: + tcbinds.append(TcBind(port, tcbinddict)) + if verify_existence: + tl.custom(sw, "tc bind existence for port {} verification".format(port.name, err_msg)) + return tcbinds + +def do_check_tcbind(tl, sw, ports, tcbinds, vp): + for tcbind in tcbinds: + pre_tcbinds = get_tcbinds(tl, sw, ports) + (pool, th) = vp.get_value(tcbind) + tcbind.dl_set(sw, pool, th) + post_tcbinds = get_tcbinds(tl, sw, ports) + tcbind = post_tcbinds.get_by(tcbind) + + err_msg = None + if tcbind["pool"] != pool: + err_msg = "Incorrect pool (got {}, expected {})".format(tcbind["pool"], pool) + if tcbind["threshold"] != th: + err_msg = "Incorrect threshold (got {}, expected {})".format(tcbind["threshold"], th) + + pre_tcbinds.del_by(tcbind) + post_tcbinds.del_by(tcbind) + if pre_tcbinds != post_tcbinds: + err_msg = "Other tc bind setup changed as well" + tl.custom(sw, "tc bind {}-{} of sb {} set verification".format(tcbind["dlportname"], + tcbind["tc"], + tcbind["sb"]), err_msg) + +def check_tcbind(tl, sw, dlname, ports, pools): + tcbinds = get_tcbinds(tl, sw, ports, verify_existence=True) + record_vp = RecordValuePicker(tcbinds) + do_check_tcbind(tl, sw, ports, tcbinds, RandomValuePicker(pools)) + do_check_tcbind(tl, sw, ports, tcbinds, record_vp) + +class PortPool(CommonItem): + varitems = ["threshold"] + + def __init__(self, port, d): + super(PortPool, self).__init__(d) + self["dlportname"] = port.name + + def dl_set(self, sw, th): + run_cmd(sw, "devlink sb port pool set {} sb {} pool {} th {}".format(self["dlportname"], + self["sb"], + self["pool"], th)) + +class PortPoolList(CommonList): + pass + +def get_portpools(tl, sw, ports, verify_existence=False): + d = run_json_cmd(sw, "devlink sb port pool -j -n") + portpools = PortPoolList() + for port in ports: + err_msg = None + if not port.name in d["port_pool"] or len(d["port_pool"][port.name]) == 0: + err_msg = "No port pool for port" + else: + for portpooldict in d["port_pool"][port.name]: + portpools.append(PortPool(port, portpooldict)) + if verify_existence: + tl.custom(sw, "port pool existence for port {} verification".format(port.name, err_msg)) + return portpools + +def do_check_portpool(tl, sw, ports, portpools, vp): + for portpool in portpools: + pre_portpools = get_portpools(tl, sw, ports) + (th,) = vp.get_value(portpool) + portpool.dl_set(sw, th) + post_portpools = get_portpools(tl, sw, ports) + portpool = post_portpools.get_by(portpool) + + err_msg = None + if portpool["threshold"] != th: + err_msg = "Incorrect threshold (got {}, expected {})".format(portpool["threshold"], th) + + pre_portpools.del_by(portpool) + post_portpools.del_by(portpool) + if pre_portpools != post_portpools: + err_msg = "Other port pool setup changed as well" + tl.custom(sw, "port pool {}-{} of sb {} set verification".format(portpool["dlportname"], + portpool["pool"], + portpool["sb"]), err_msg) + +def check_portpool(tl, sw, dlname, ports, pools): + portpools = get_portpools(tl, sw, ports, verify_existence=True) + record_vp = RecordValuePicker(portpools) + do_check_portpool(tl, sw, ports, portpools, RandomValuePicker(pools)) + do_check_portpool(tl, sw, ports, portpools, record_vp) + +class Port: + def __init__(self, name): + self.name = name + +class PortList(list): + pass + +def get_ports(sw, dlname): + d = run_json_cmd(sw, "devlink port show -j") + ports = PortList() + for name in d["port"]: + if name.find(dlname) == 0: + ports.append(Port(name)) + return ports + +class UnavailableDevlinkNameException(Exception): + pass + +def do_task(ctl, hosts, ifaces, aliases): + m1, m2, sw = hosts + m1_if1, m2_if1, sw_if1, sw_if2 = ifaces + + tl = TestLib(ctl, aliases) + + dlname = sw_if1.get_devlink_name() + if not dlname: + raise UnavailableDevlinkNameException() + + ports = get_ports(sw, dlname) + pools = get_pools(sw, dlname) + check_pools(tl, sw, dlname, pools) + check_tcbind(tl, sw, dlname, ports, pools) + check_portpool(tl, sw, dlname, ports, pools) + +do_task(ctl, [ctl.get_host("machine1"), + ctl.get_host("machine2"), + ctl.get_host("switch")], + [ctl.get_host("machine1").get_interface("if1"), + ctl.get_host("machine2").get_interface("if1"), + ctl.get_host("switch").get_interface("if1"), + ctl.get_host("switch").get_interface("if2")], + ctl.get_aliases()) diff --git a/recipes/switchdev/sharedbuffer.xml b/recipes/switchdev/sharedbuffer.xml new file mode 100644 index 0000000..cfdb973 --- /dev/null +++ b/recipes/switchdev/sharedbuffer.xml @@ -0,0 +1,22 @@ +<lnstrecipe xmlns:xi="http://www.w3.org/2003/XInclude"> + <xi:include href="default_aliases.xml" /> + <network> + <host id="machine1"> + <interfaces> + <eth id="if1" label="A" /> + </interfaces> + </host> + <host id="machine2"> + <interfaces> + <eth id="if1" label="B" /> + </interfaces> + </host> + <host id="switch"> + <interfaces> + <eth id="if1" label="A" /> + <eth id="if2" label="B" /> + </interfaces> + </host> + </network> + <task python="sharedbuffer.py" /> +</lnstrecipe>
On Wed, Aug 24, 2016 at 04:59:19PM +0200, Jiri Pirko wrote:
From: Jiri Pirko jiri@mellanox.com
This recipe utilizes devlink app to test setup of all shared buffer configuration options.
Signed-off-by: Jiri Pirko jiri@mellanox.com
recipes/switchdev/sharedbuffer.py | 305 +++++++++++++++++++++++++++++++++++++ recipes/switchdev/sharedbuffer.xml | 22 +++ 2 files changed, 327 insertions(+) create mode 100644 recipes/switchdev/sharedbuffer.py create mode 100644 recipes/switchdev/sharedbuffer.xml
diff --git a/recipes/switchdev/sharedbuffer.py b/recipes/switchdev/sharedbuffer.py new file mode 100644 index 0000000..28a6f44 --- /dev/null +++ b/recipes/switchdev/sharedbuffer.py @@ -0,0 +1,305 @@ +""" +Copyright 2016 Mellanox Technologies. All rights reserved. +Licensed under the GNU General Public License, version 2 as +published by the Free Software Foundation; see COPYING for details. +"""
+__author__ = """ +jiri@mellanox.com (Jiri Pirko) +"""
+from lnst.Controller.Task import ctl +from TestLib import TestLib +from time import sleep +import random
+class RandomValuePicker:
- def __init__(self, pools):
self._pools = {"ingress": [], "egress": []}
for pool in pools:
self._pools[pool["type"]].append(pool["pool"])
- def _get_size(self):
# support only this fixed size for now
return 12401088
- def _get_thtype(self):
# support static threshold only for now
return "static"
- def _get_th(self):
# support dynamic threshold only for now
return random.randint(3,16)
- def _get_pool(self, direction):
arr = self._pools[direction]
return arr[random.randint(0, len(arr) - 1)]
- def get_value(self, objid):
if isinstance(objid, Pool):
return (self._get_size(), self._get_thtype())
if isinstance(objid, TcBind):
pool = self._get_pool(objid["type"])
th = self._get_th()
return (pool, th)
if isinstance(objid, PortPool):
return (self._get_th(),)
+class RecordValuePickerException(Exception):
- pass
+class RecordValuePicker:
- def __init__(self, objlist):
self._recs = []
for item in objlist:
self._recs.append({"objid": item, "value": item.var_tuple()})
- def get_value(self, objid):
for rec in self._recs:
if rec["objid"].weak_eq(objid):
return rec["value"]
raise RecordValuePickerException()
+class RunCmdException(Exception):
- pass
+def run_cmd(host, cmd, json=False):
- cmd = host.run(cmd, json=json)
- if not cmd.passed():
raise RunCmdException(cmd.get_result()["res_data"]["stderr"])
- return cmd.out()
+def run_json_cmd(host, cmd):
- return run_cmd(host, cmd, json=True)
+class CommonItem(dict):
- varitems = []
- def var_tuple(self):
ret = []
self.varitems.sort()
for key in self.varitems:
ret.append(self[key])
return tuple(ret)
- def weak_eq(self, other):
for key in self:
if key in self.varitems:
continue
if self[key] != other[key]:
return False
return True
+class CommonList(list):
- def get_by(self, by_obj):
for item in self:
if item.weak_eq(by_obj):
return item
return None
- def del_by(self, by_obj):
for item in self:
if item.weak_eq(by_obj):
self.remove(item)
+class Pool(CommonItem):
- varitems = ["size", "thtype"]
- def dl_set(self, sw, dlname, size, thtype):
run_cmd(sw, "devlink sb pool set {} sb {} pool {} size {} thtype {}".format(dlname, self["sb"],
self["pool"],
size, thtype))
+class PoolList(CommonList):
- pass
+def get_pools(sw, dlname, direction=None):
- d = run_json_cmd(sw, "devlink sb pool show -j")
- pools = PoolList()
- for pooldict in d["pool"][dlname]:
if not direction or direction == pooldict["type"]:
pools.append(Pool(pooldict))
- return pools
+def do_check_pools(tl, sw, dlname, pools, vp):
- for pool in pools:
pre_pools = get_pools(sw, dlname)
(size, thtype) = vp.get_value(pool)
pool.dl_set(sw, dlname, size, thtype)
post_pools = get_pools(sw, dlname)
pool = post_pools.get_by(pool)
err_msg = None
if pool["size"] != size:
err_msg = "Incorrect pool size (got {}, expected {})".format(pool["size"], size)
if pool["thtype"] != thtype:
err_msg = "Incorrect pool threshold type (got {}, expected {})".format(pool["thtype"], thtype)
pre_pools.del_by(pool)
post_pools.del_by(pool)
if pre_pools != post_pools:
err_msg = "Other pool setup changed as well"
tl.custom(sw, "pool {} of sb {} set verification".format(pool["pool"],
pool["sb"]), err_msg)
+def check_pools(tl, sw, dlname, pools):
- record_vp = RecordValuePicker(pools)
- do_check_pools(tl, sw, dlname, pools, RandomValuePicker(pools))
- do_check_pools(tl, sw, dlname, pools, record_vp)
+class TcBind(CommonItem):
- varitems = ["pool", "threshold"]
- def __init__(self, port, d):
super(TcBind, self).__init__(d)
self["dlportname"] = port.name
- def dl_set(self, sw, pool, th):
run_cmd(sw, "devlink sb tc bind set {} sb {} tc {} type {} pool {} th {}".format(self["dlportname"],
self["sb"],
self["tc"],
self["type"],
pool, th))
+class TcBindList(CommonList):
- pass
+def get_tcbinds(tl, sw, ports, verify_existence=False):
- d = run_json_cmd(sw, "devlink sb tc bind show -j -n")
- tcbinds = TcBindList()
- for port in ports:
err_msg = None
if not port.name in d["tc_bind"] or len(d["tc_bind"][port.name]) == 0:
err_msg = "No tc bind for port"
else:
for tcbinddict in d["tc_bind"][port.name]:
tcbinds.append(TcBind(port, tcbinddict))
if verify_existence:
tl.custom(sw, "tc bind existence for port {} verification".format(port.name, err_msg))
- return tcbinds
+def do_check_tcbind(tl, sw, ports, tcbinds, vp):
- for tcbind in tcbinds:
pre_tcbinds = get_tcbinds(tl, sw, ports)
(pool, th) = vp.get_value(tcbind)
tcbind.dl_set(sw, pool, th)
post_tcbinds = get_tcbinds(tl, sw, ports)
tcbind = post_tcbinds.get_by(tcbind)
err_msg = None
if tcbind["pool"] != pool:
err_msg = "Incorrect pool (got {}, expected {})".format(tcbind["pool"], pool)
if tcbind["threshold"] != th:
err_msg = "Incorrect threshold (got {}, expected {})".format(tcbind["threshold"], th)
pre_tcbinds.del_by(tcbind)
post_tcbinds.del_by(tcbind)
if pre_tcbinds != post_tcbinds:
err_msg = "Other tc bind setup changed as well"
tl.custom(sw, "tc bind {}-{} of sb {} set verification".format(tcbind["dlportname"],
tcbind["tc"],
tcbind["sb"]), err_msg)
+def check_tcbind(tl, sw, dlname, ports, pools):
- tcbinds = get_tcbinds(tl, sw, ports, verify_existence=True)
- record_vp = RecordValuePicker(tcbinds)
- do_check_tcbind(tl, sw, ports, tcbinds, RandomValuePicker(pools))
- do_check_tcbind(tl, sw, ports, tcbinds, record_vp)
+class PortPool(CommonItem):
- varitems = ["threshold"]
- def __init__(self, port, d):
super(PortPool, self).__init__(d)
self["dlportname"] = port.name
- def dl_set(self, sw, th):
run_cmd(sw, "devlink sb port pool set {} sb {} pool {} th {}".format(self["dlportname"],
self["sb"],
self["pool"], th))
+class PortPoolList(CommonList):
- pass
+def get_portpools(tl, sw, ports, verify_existence=False):
- d = run_json_cmd(sw, "devlink sb port pool -j -n")
- portpools = PortPoolList()
- for port in ports:
err_msg = None
if not port.name in d["port_pool"] or len(d["port_pool"][port.name]) == 0:
err_msg = "No port pool for port"
else:
for portpooldict in d["port_pool"][port.name]:
portpools.append(PortPool(port, portpooldict))
if verify_existence:
tl.custom(sw, "port pool existence for port {} verification".format(port.name, err_msg))
- return portpools
+def do_check_portpool(tl, sw, ports, portpools, vp):
- for portpool in portpools:
pre_portpools = get_portpools(tl, sw, ports)
(th,) = vp.get_value(portpool)
portpool.dl_set(sw, th)
post_portpools = get_portpools(tl, sw, ports)
portpool = post_portpools.get_by(portpool)
err_msg = None
if portpool["threshold"] != th:
err_msg = "Incorrect threshold (got {}, expected {})".format(portpool["threshold"], th)
pre_portpools.del_by(portpool)
post_portpools.del_by(portpool)
if pre_portpools != post_portpools:
err_msg = "Other port pool setup changed as well"
tl.custom(sw, "port pool {}-{} of sb {} set verification".format(portpool["dlportname"],
portpool["pool"],
portpool["sb"]), err_msg)
+def check_portpool(tl, sw, dlname, ports, pools):
- portpools = get_portpools(tl, sw, ports, verify_existence=True)
- record_vp = RecordValuePicker(portpools)
- do_check_portpool(tl, sw, ports, portpools, RandomValuePicker(pools))
- do_check_portpool(tl, sw, ports, portpools, record_vp)
+class Port:
- def __init__(self, name):
self.name = name
+class PortList(list):
- pass
+def get_ports(sw, dlname):
- d = run_json_cmd(sw, "devlink port show -j")
- ports = PortList()
- for name in d["port"]:
if name.find(dlname) == 0:
ports.append(Port(name))
- return ports
+class UnavailableDevlinkNameException(Exception):
- pass
+def do_task(ctl, hosts, ifaces, aliases):
- m1, m2, sw = hosts
- m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
- tl = TestLib(ctl, aliases)
- dlname = sw_if1.get_devlink_name()
- if not dlname:
raise UnavailableDevlinkNameException()
- ports = get_ports(sw, dlname)
- pools = get_pools(sw, dlname)
- check_pools(tl, sw, dlname, pools)
- check_tcbind(tl, sw, dlname, ports, pools)
- check_portpool(tl, sw, dlname, ports, pools)
+do_task(ctl, [ctl.get_host("machine1"),
ctl.get_host("machine2"),
ctl.get_host("switch")],
[ctl.get_host("machine1").get_interface("if1"),
ctl.get_host("machine2").get_interface("if1"),
ctl.get_host("switch").get_interface("if1"),
ctl.get_host("switch").get_interface("if2")],
ctl.get_aliases())
diff --git a/recipes/switchdev/sharedbuffer.xml b/recipes/switchdev/sharedbuffer.xml new file mode 100644 index 0000000..cfdb973 --- /dev/null +++ b/recipes/switchdev/sharedbuffer.xml @@ -0,0 +1,22 @@ +<lnstrecipe xmlns:xi="http://www.w3.org/2003/XInclude">
- <xi:include href="default_aliases.xml" />
<network>
<host id="machine1">
<interfaces>
<eth id="if1" label="A" />
</interfaces>
</host>
<host id="machine2">
<interfaces>
<eth id="if1" label="B" />
</interfaces>
</host>
<host id="switch">
<interfaces>
<eth id="if1" label="A" />
<eth id="if2" label="B" />
</interfaces>
</host>
</network>
<task python="sharedbuffer.py" />
+</lnstrecipe>
2.5.5
ack
lnst-developers@lists.fedorahosted.org