From patchwork Wed Apr 3 02:34:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 785614 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0089014AA9; Wed, 3 Apr 2024 02:34:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111673; cv=none; b=TMp5HvJSQv3hMHfOeMUG2ZCktfhIQdMJdYS7dPog8bcgqP9UB11h5Zt6RX12+tRSU2J0XJz1Wo8XfM9LNHwdTgMMrf+Yvqh00+YGV4vq/VHzynomrafsKxn4zT/1SYjbKs4j2c8qz7ScvCgAclHyrl8nayIy0KtrH+HTwyu3jW4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111673; c=relaxed/simple; bh=EojVAvAl6ixmWSth1szeL7sQLEPA7JGoyhvWivDYq0A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q5oD9C4CTnTkFLSmp6sFmS3WGkO2Bp8Lp1qIUdhG8aom3IHG+kvbGzMJ5d6xjxYkpB3xafNQ5PGoaB7XBwwBNxRgYPYUyn6KJy3f9pUsS0k0K/s4+SJG5uDs6bAejWxz+aoPCL6hYERiaYgHYBSAaGDaDKykNZTI4+jz4nkV1JI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UTyHyuD5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UTyHyuD5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 251D1C433C7; Wed, 3 Apr 2024 02:34:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712111672; bh=EojVAvAl6ixmWSth1szeL7sQLEPA7JGoyhvWivDYq0A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UTyHyuD5JAJBK2MZe0vcL4i+Z8Gf848mK9tWdBKW+So98zOW7VgxZCwXsPDaL38bw mfcpnmVF9meWbvkuESSYo1pZA7+no8BxZrN62c8v6G8PqrymleVg1/K3f9E0PDePyu VhGj0raHyxS4TfV5aYkziwG3VBhpzUpAYgAvfymLQwhukB+IE9s8E9j482ilVXnHWu O7fwRxR0le3g1JjqIKzI9u6DOLcOkCdMaFKYty11uRo+3GfhK9kjIRjpnqc3LGVJtk 9eRX6spL4D+7V0sw2L/L2CEql5zmd+wpHTXZFg/9aicp9Bny8XsnuEzsz7DNPLg55C iE+sMWcIwWokA== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, shuah@kernel.org, sdf@google.com, donald.hunter@gmail.com, linux-kselftest@vger.kernel.org, petrm@nvidia.com, Jakub Kicinski Subject: [PATCH net-next v2 1/7] netlink: specs: define ethtool header flags Date: Tue, 2 Apr 2024 19:34:20 -0700 Message-ID: <20240403023426.1762996-2-kuba@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240403023426.1762996-1-kuba@kernel.org> References: <20240403023426.1762996-1-kuba@kernel.org> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When interfacing with the ethtool commands it's handy to be able to use the names of the flags. Example: ethnl.pause_get({"header": {"dev-index": cfg.ifindex, "flags": {'stats'}}}) Note that not all commands accept all the flags, but the meaning of the bits does not change command to command. Signed-off-by: Jakub Kicinski --- v2: - make sure we don't try to code gen enum (add enum-name:) --- Documentation/netlink/specs/ethtool.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 197208f419dc..d0e4a47e0f21 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -16,6 +16,11 @@ doc: Partial family for Ethtool Netlink. name: stringset type: enum entries: [] + - + name: header-flags + enum-name: + type: flags + entries: [ compact-bitsets, omit-reply, stats ] attribute-sets: - @@ -30,6 +35,7 @@ doc: Partial family for Ethtool Netlink. - name: flags type: u32 + enum: header-flags - name: bitset-bit From patchwork Wed Apr 3 02:34:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 785613 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95B451BC4B; Wed, 3 Apr 2024 02:34:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111674; cv=none; b=bOKI9Apf16IqNTaoPFqiPcwYWWP7n6uCWi6PeNDuXHWQqJRpUPElN+TrJS5KcX3gsbTgWIFDLUfPkWqLDMxxfjwdOJufWdu34zTRna5eHsAJa/mEezFg4MP6+tV0vLeHeyIgqmFRlOuKJwqROvm3yZPPBalUTEgGeszXrMTWyp8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111674; c=relaxed/simple; bh=Wp1mJ+/VMRy8bmRXRjIwUCMM+WMqxsU+whvPqKHddKQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VW7sN8NpL53FMiCfE/Xu63AhT+pr79jlgnaVJf1LSgFdaok9q3KQpQGrZcl4TZvu1TB2+vlN39HTbeyMCyHeo9K/2T9IkClmMlA4R6dZ4SQjAaZ2o7qucAjPrxaZVHDVBbc2AerqpkebogcpJq1aBBHNMRwQUGjANVpMoPdGMy0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=suEnnMZz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="suEnnMZz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 81DDAC4167E; Wed, 3 Apr 2024 02:34:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712111674; bh=Wp1mJ+/VMRy8bmRXRjIwUCMM+WMqxsU+whvPqKHddKQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=suEnnMZzEYXiG0P12hYSpM5NMjvjDX39EahA5izKtzpRxe/lFgX2jWJWTRpoZrol9 tOOBXg0OuZlwGwTMFUqMdU2Q9pFUep/cbHcztsC87hkBKUy1c7uo5uz2W8rJ1x4Ph9 sGintNfpbKSAHBPo/rhIMvSX6kiVvE/eZCZoc1iANOaWTAVUfU9yUYBGyL7X3LXM1q wKp9eX7UMz9XEAokV5PMOFuicFrLQ1XNSxQQftt0QC8Ban+jAlRPC1Gi9/tZXyUo1s w5RJvUYcYbhhu0wW/9CufnZFpxMVJ2Pq5hywmKMUPiDLyjOvllPomL9vFUmSD3s+85 OEMe0Qt3QcgHg== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, shuah@kernel.org, sdf@google.com, donald.hunter@gmail.com, linux-kselftest@vger.kernel.org, petrm@nvidia.com, Jakub Kicinski Subject: [PATCH net-next v2 3/7] selftests: net: add scaffolding for Netlink tests in Python Date: Tue, 2 Apr 2024 19:34:22 -0700 Message-ID: <20240403023426.1762996-4-kuba@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240403023426.1762996-1-kuba@kernel.org> References: <20240403023426.1762996-1-kuba@kernel.org> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add glue code for accessing the YNL library which lives under tools/net and YAML spec files from under Documentation/. Automatically figure out if tests are run in tree or not. Since we'll want to use this library both from net and drivers/net test targets make the library a target as well, and automatically include it when net or drivers/net are included. Making net/lib a target ensures that we end up with only one copy of it, and saves us some path guessing. Add a tiny bit of formatting support to be able to output KTAP from the start. Signed-off-by: Jakub Kicinski --- v2: - include the net/lib only in install - support passing state to tests - don't apply Path() on what's already a Path() - fix spacing in Makefile's filter() - sort imports CC: shuah@kernel.org CC: linux-kselftest@vger.kernel.org --- tools/testing/selftests/Makefile | 9 +- tools/testing/selftests/net/lib/Makefile | 8 ++ .../testing/selftests/net/lib/py/__init__.py | 6 ++ tools/testing/selftests/net/lib/py/consts.py | 9 ++ tools/testing/selftests/net/lib/py/ksft.py | 96 +++++++++++++++++++ tools/testing/selftests/net/lib/py/utils.py | 47 +++++++++ tools/testing/selftests/net/lib/py/ynl.py | 49 ++++++++++ 7 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/lib/Makefile create mode 100644 tools/testing/selftests/net/lib/py/__init__.py create mode 100644 tools/testing/selftests/net/lib/py/consts.py create mode 100644 tools/testing/selftests/net/lib/py/ksft.py create mode 100644 tools/testing/selftests/net/lib/py/utils.py create mode 100644 tools/testing/selftests/net/lib/py/ynl.py diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index e1504833654d..f533eb7054fe 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -116,6 +116,13 @@ TARGETS += zram TARGETS_HOTPLUG = cpu-hotplug TARGETS_HOTPLUG += memory-hotplug +# Networking tests want the net/lib target, include it automatically +ifneq ($(filter net,$(TARGETS)),) +ifeq ($(filter net/lib,$(TARGETS)),) + INSTALL_DEP_TARGETS := net/lib +endif +endif + # User can optionally provide a TARGETS skiplist. By default we skip # BPF since it has cutting edge build time dependencies which require # more effort to install. @@ -245,7 +252,7 @@ ifdef INSTALL_PATH install -m 744 run_kselftest.sh $(INSTALL_PATH)/ rm -f $(TEST_LIST) @ret=1; \ - for TARGET in $(TARGETS); do \ + for TARGET in $(TARGETS) $(INSTALL_DEP_TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET install \ INSTALL_PATH=$(INSTALL_PATH)/$$TARGET \ diff --git a/tools/testing/selftests/net/lib/Makefile b/tools/testing/selftests/net/lib/Makefile new file mode 100644 index 000000000000..5730682aeffb --- /dev/null +++ b/tools/testing/selftests/net/lib/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_FILES := ../../../../../Documentation/netlink/s* +TEST_FILES += ../../../../net/* + +TEST_INCLUDES := $(wildcard py/*.py) + +include ../../lib.mk diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py new file mode 100644 index 000000000000..7823b5c1f8d7 --- /dev/null +++ b/tools/testing/selftests/net/lib/py/__init__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +from .consts import KSRC +from .ksft import * +from .utils import * +from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily diff --git a/tools/testing/selftests/net/lib/py/consts.py b/tools/testing/selftests/net/lib/py/consts.py new file mode 100644 index 000000000000..f518ce79d82c --- /dev/null +++ b/tools/testing/selftests/net/lib/py/consts.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +import sys +from pathlib import Path + +KSFT_DIR = (Path(__file__).parent / "../../..").resolve() +KSRC = (Path(__file__).parent / "../../../../../..").resolve() + +KSFT_MAIN_NAME = Path(sys.argv[0]).with_suffix("").name diff --git a/tools/testing/selftests/net/lib/py/ksft.py b/tools/testing/selftests/net/lib/py/ksft.py new file mode 100644 index 000000000000..c7210525981c --- /dev/null +++ b/tools/testing/selftests/net/lib/py/ksft.py @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0 + +import builtins +from .consts import KSFT_MAIN_NAME + +KSFT_RESULT = None + + +class KsftSkipEx(Exception): + pass + + +class KsftXfailEx(Exception): + pass + + +def ksft_pr(*objs, **kwargs): + print("#", *objs, **kwargs) + + +def ksft_eq(a, b, comment=""): + global KSFT_RESULT + if a != b: + KSFT_RESULT = False + ksft_pr("Check failed", a, "!=", b, comment) + + +def ksft_true(a, comment=""): + global KSFT_RESULT + if not a: + KSFT_RESULT = False + ksft_pr("Check failed", a, "does not eval to True", comment) + + +def ksft_in(a, b, comment=""): + global KSFT_RESULT + if a not in b: + KSFT_RESULT = False + ksft_pr("Check failed", a, "not in", b, comment) + + +def ksft_ge(a, b, comment=""): + global KSFT_RESULT + if a < b: + KSFT_RESULT = False + ksft_pr("Check failed", a, "<", b, comment) + + +def ktap_result(ok, cnt=1, case="", comment=""): + res = "" + if not ok: + res += "not " + res += "ok " + res += str(cnt) + " " + res += KSFT_MAIN_NAME + if case: + res += "." + str(case.__name__) + if comment: + res += " # " + comment + print(res) + + +def ksft_run(cases, args=()): + totals = {"pass": 0, "fail": 0, "skip": 0, "xfail": 0} + + print("KTAP version 1") + print("1.." + str(len(cases))) + + global KSFT_RESULT + cnt = 0 + for case in cases: + KSFT_RESULT = True + cnt += 1 + try: + case(*args) + except KsftSkipEx as e: + ktap_result(True, cnt, case, comment="SKIP " + str(e)) + totals['skip'] += 1 + continue + except KsftXfailEx as e: + ktap_result(True, cnt, case, comment="XFAIL " + str(e)) + totals['xfail'] += 1 + continue + except Exception as e: + for line in str(e).split('\n'): + ksft_pr("Exception|", line) + ktap_result(False, cnt, case) + totals['fail'] += 1 + continue + + ktap_result(KSFT_RESULT, cnt, case) + totals['pass'] += 1 + + print( + f"# Totals: pass:{totals['pass']} fail:{totals['fail']} xfail:{totals['xfail']} xpass:0 skip:{totals['skip']} error:0" + ) diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py new file mode 100644 index 000000000000..f0d425731fd4 --- /dev/null +++ b/tools/testing/selftests/net/lib/py/utils.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0 + +import json as _json +import subprocess + +class cmd: + def __init__(self, comm, shell=True, fail=True, ns=None, background=False): + if ns: + if isinstance(ns, NetNS): + ns = ns.name + comm = f'ip netns exec {ns} ' + comm + + self.stdout = None + self.stderr = None + self.ret = None + + self.comm = comm + self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + if not background: + self.process(terminate=False, fail=fail) + + def process(self, terminate=True, fail=None): + if terminate: + self.proc.terminate() + stdout, stderr = self.proc.communicate() + self.stdout = stdout.decode("utf-8") + self.stderr = stderr.decode("utf-8") + self.proc.stdout.close() + self.proc.stderr.close() + self.ret = self.proc.returncode + + if self.proc.returncode != 0 and fail: + if len(stderr) > 0 and stderr[-1] == "\n": + stderr = stderr[:-1] + raise Exception("Command failed: %s\n%s" % (self.proc.args, stderr)) + + +def ip(args, json=None, ns=None): + cmd_str = "ip " + if json: + cmd_str += '-j ' + cmd_str += args + cmd_obj = cmd(cmd_str, ns=ns) + if json: + return _json.loads(cmd_obj.stdout) + return cmd_obj diff --git a/tools/testing/selftests/net/lib/py/ynl.py b/tools/testing/selftests/net/lib/py/ynl.py new file mode 100644 index 000000000000..1ace58370c06 --- /dev/null +++ b/tools/testing/selftests/net/lib/py/ynl.py @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0 + +import sys +from pathlib import Path +from .consts import KSRC, KSFT_DIR +from .ksft import ksft_pr, ktap_result + +# Resolve paths +try: + if (KSFT_DIR / "kselftest-list.txt").exists(): + # Running in "installed" selftests + tools_full_path = KSFT_DIR + SPEC_PATH = KSFT_DIR / "net/lib/specs" + + sys.path.append(tools_full_path.as_posix()) + from net.lib.ynl.lib import YnlFamily, NlError + else: + # Running in tree + tools_full_path = KSRC / "tools" + SPEC_PATH = KSRC / "Documentation/netlink/specs" + + sys.path.append(tools_full_path.as_posix()) + from net.ynl.lib import YnlFamily, NlError +except ModuleNotFoundError as e: + ksft_pr("Failed importing `ynl` library from kernel sources") + ksft_pr(str(e)) + ktap_result(True, comment="SKIP") + sys.exit(4) + +# +# Wrapper classes, loading the right specs +# Set schema='' to avoid jsonschema validation, it's slow +# +class EthtoolFamily(YnlFamily): + def __init__(self): + super().__init__((SPEC_PATH / Path('ethtool.yaml')).as_posix(), + schema='') + + +class RtnlFamily(YnlFamily): + def __init__(self): + super().__init__((SPEC_PATH / Path('rt_link.yaml')).as_posix(), + schema='') + + +class NetdevFamily(YnlFamily): + def __init__(self): + super().__init__((SPEC_PATH / Path('netdev.yaml')).as_posix(), + schema='') From patchwork Wed Apr 3 02:34:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 785612 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A52191F94B; Wed, 3 Apr 2024 02:34:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111675; cv=none; b=sZ9Bud96dBDGzaJPrNvvXb0ALA27nRCxbwQ2Wka/sNyS0t2jEs+g9st8mhO/9HCcmBBQvT8obXZ77KBEapRpj1RFbUGK375XCHFMlERQAcrH6g0dFMGcJwhCZe81GhElywW45f75dhLkT23UGOS4lpkqparSsmht0wyiDI+xjDA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111675; c=relaxed/simple; bh=mB0I4kjtTnexpmnvDZ8oN+gQdUayrzeuXIYIsr+D/5c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n1akaeaj5kHD470m+nkhI8teyF7MQiIrO+13hxj42XX8mk5SocPyO5nCngT0DPEk06e9a8hVtLvvXoOccl0bDm/D/0SpT20Ca/lJbeIq23yDFw5YsTFs4Wfayeuk16CCPfzO5gCPOfxF3Ie2zgAXzpOlDN/Da0yQvIbPhEQuA8E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D9E03IQE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D9E03IQE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CA887C433C7; Wed, 3 Apr 2024 02:34:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712111675; bh=mB0I4kjtTnexpmnvDZ8oN+gQdUayrzeuXIYIsr+D/5c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D9E03IQEW25TS6cdQgWsVeSXYJGNcuLOHhV2jxkil4geunqCyUEQoa89ez9PANoYg a/yUxz9bDYjsy2KltiojM21Cvhsrv4N3iti/CyK7Z9uZ+hg51aPFuZl9jX0PkTcgx1 GLFW0uO/7feGzlyg1HJmNvMDsgee+F+sE/AfeKqmMp5rOGMuQtr/LOIoaX71oSpe13 ff7LfyIzlmAqfR8R7yUY47pY8VHNroegQXuVI0QTX8llrd7j1akX28TJvBCR5cEWUW 3PbEhfTMq2X2OwLXldSb3xBvkM9jxY1uIelXGzq8iCWKswSQ1T5eDHkEFFwSeKTprL FikgZX4zIXjrg== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, shuah@kernel.org, sdf@google.com, donald.hunter@gmail.com, linux-kselftest@vger.kernel.org, petrm@nvidia.com, Jakub Kicinski Subject: [PATCH net-next v2 5/7] netdevsim: report stats by default, like a real device Date: Tue, 2 Apr 2024 19:34:24 -0700 Message-ID: <20240403023426.1762996-6-kuba@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240403023426.1762996-1-kuba@kernel.org> References: <20240403023426.1762996-1-kuba@kernel.org> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Real devices should implement qstats. Devices which support pause or FEC configuration should also report the relevant stats. nsim was missing FEC stats completely, some of the qstats and pause stats required toggling a debugfs knob. Note that the tests which used pause always initialize the setting so they shouldn't be affected by the different starting value. Signed-off-by: Jakub Kicinski Reviewed-by: Petr Machata --- drivers/net/netdevsim/ethtool.c | 11 ++++++++ drivers/net/netdevsim/netdev.c | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index bd546d4d26c6..3f9c9327f149 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -140,6 +140,13 @@ nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam) return 0; } +static void +nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats) +{ + fec_stats->corrected_blocks.total = 123; + fec_stats->uncorrectable_blocks.total = 4; +} + static int nsim_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { @@ -163,6 +170,7 @@ static const struct ethtool_ops nsim_ethtool_ops = { .set_channels = nsim_set_channels, .get_fecparam = nsim_get_fecparam, .set_fecparam = nsim_set_fecparam, + .get_fec_stats = nsim_get_fec_stats, .get_ts_info = nsim_get_ts_info, }; @@ -182,6 +190,9 @@ void nsim_ethtool_init(struct netdevsim *ns) nsim_ethtool_ring_init(ns); + ns->ethtool.pauseparam.report_stats_rx = true; + ns->ethtool.pauseparam.report_stats_tx = true; + ns->ethtool.fec.fec = ETHTOOL_FEC_NONE; ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE; diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 8330bc0bcb7e..096ac0abbc02 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -330,6 +331,49 @@ static const struct net_device_ops nsim_vf_netdev_ops = { .ndo_set_features = nsim_set_features, }; +/* We don't have true par-queue stats, yet, so do some random fakery here. */ +static void nsim_get_queue_stats_rx(struct net_device *dev, int idx, + struct netdev_queue_stats_rx *stats) +{ + struct rtnl_link_stats64 rtstats = {}; + + nsim_get_stats64(dev, &rtstats); + + stats->packets = rtstats.rx_packets - !!rtstats.rx_packets; + stats->bytes = rtstats.rx_bytes; +} + +static void nsim_get_queue_stats_tx(struct net_device *dev, int idx, + struct netdev_queue_stats_tx *stats) +{ + struct rtnl_link_stats64 rtstats = {}; + + nsim_get_stats64(dev, &rtstats); + + stats->packets = rtstats.tx_packets - !!rtstats.tx_packets; + stats->bytes = rtstats.tx_bytes; +} + +static void nsim_get_base_stats(struct net_device *dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + struct rtnl_link_stats64 rtstats = {}; + + nsim_get_stats64(dev, &rtstats); + + rx->packets = !!rtstats.rx_packets; + rx->bytes = 0; + tx->packets = !!rtstats.tx_packets; + tx->bytes = 0; +} + +static const struct netdev_stat_ops nsim_stat_ops = { + .get_queue_stats_tx = nsim_get_queue_stats_tx, + .get_queue_stats_rx = nsim_get_queue_stats_rx, + .get_base_stats = nsim_get_base_stats, +}; + static void nsim_setup(struct net_device *dev) { ether_setup(dev); @@ -360,6 +404,7 @@ static int nsim_init_netdevsim(struct netdevsim *ns) ns->phc = phc; ns->netdev->netdev_ops = &nsim_netdev_ops; + ns->netdev->stat_ops = &nsim_stat_ops; err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev); if (err) From patchwork Wed Apr 3 02:34:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 785611 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA90C3C6A4; Wed, 3 Apr 2024 02:34:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111676; cv=none; b=KPdo3pFrItCjOd5LATUPC3W8mEXh+4X3Do0zFXUxy6Y0Ql8TEHC060OwLpW76izMawb8uueLWJnnitxKkNQLJF59k2uhYTWvkK3blRJ0aGHZ+mQtW3dJk1cZLopF+JjXD+/itlm2jTjUpYvUu2V2LbxpSd7WgE/HyulHOwdbZG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712111676; c=relaxed/simple; bh=8hIRahLfJ1A+yfucAwb1LVgvvKA1r+H9v75vdhnDdgE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jQtCCBIo/4hfmcY5SR/BG6wp4tE2Xx7masC5ouoZqagkqO9RQ1kJOi0hj4ZD/iJVYCZscY7CzXH+XPRpJ+OGy4d3lxDBk5MAAce94FJldDsDhXpKHxluLqfFfu+fm9dWgxtzNdFGo3aXHYsWw/EucWinx8luKYDfDZh3ES4KfDo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YAgtCQ+s; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YAgtCQ+s" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 379F1C433F1; Wed, 3 Apr 2024 02:34:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712111676; bh=8hIRahLfJ1A+yfucAwb1LVgvvKA1r+H9v75vdhnDdgE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YAgtCQ+sYOsHPnwF7BZZqZwccxYs49hBwJDd5+xj59Uuh4SBPfo+ERxG7glR5Y6Cj ETHfBjHrvlHYtPOrxgBgN619kx43CKU9C6FtkV4VhDtbenm1cgAxMyrdhmM/2IfFRC wncBe4xM20xT/CwBNkYUcnWrDcGHIM4XwZS6lRhWM83AsGJMPfhxRS/WiakosExh0Q lshJo5iXlsEruCFwcMTzntWmNhZ6IdWcc6dg95ooRTlDYSZqe46gK0BnBkbwEhZ41T XZDjU++ZHfVWZHVq4GP/FaYrfAQxrUrwRSld6nQK1+7M0pAclOPwUCGkyRRfHUxxi5 GjA6Nn8grSGzw== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, shuah@kernel.org, sdf@google.com, donald.hunter@gmail.com, linux-kselftest@vger.kernel.org, petrm@nvidia.com, Jakub Kicinski Subject: [PATCH net-next v2 7/7] testing: net-drv: add a driver test for stats reporting Date: Tue, 2 Apr 2024 19:34:26 -0700 Message-ID: <20240403023426.1762996-8-kuba@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240403023426.1762996-1-kuba@kernel.org> References: <20240403023426.1762996-1-kuba@kernel.org> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a very simple test to make sure drivers report expected stats. Drivers which implement FEC or pause configuration should report relevant stats. Qstats must be reported, at least packet and byte counts, and they must match total device stats. Tested with netdevsim, bnxt, in-tree and installed. Signed-off-by: Jakub Kicinski --- v2: - pass cfg as argument - use with --- tools/testing/selftests/drivers/net/stats.py | 86 ++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/stats.py diff --git a/tools/testing/selftests/drivers/net/stats.py b/tools/testing/selftests/drivers/net/stats.py new file mode 100755 index 000000000000..5a9d4e56b28b --- /dev/null +++ b/tools/testing/selftests/drivers/net/stats.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +from lib.py import ksft_run, ksft_in, ksft_true, KsftSkipEx, KsftXfailEx +from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError +from lib.py import NetDrvEnv + +ethnl = EthtoolFamily() +netfam = NetdevFamily() +rtnl = RtnlFamily() + + +def check_pause(cfg) -> None: + global ethnl + + try: + ethnl.pause_get({"header": {"dev-index": cfg.ifindex}}) + except NlError as e: + if e.error == 95: + raise KsftXfailEx("pause not supported by the device") + raise + + data = ethnl.pause_get({"header": {"dev-index": cfg.ifindex, + "flags": {'stats'}}}) + ksft_true(data['stats'], "driver does not report stats") + + +def check_fec(cfg) -> None: + global ethnl + + try: + ethnl.fec_get({"header": {"dev-index": cfg.ifindex}}) + except NlError as e: + if e.error == 95: + raise KsftXfailEx("FEC not supported by the device") + raise + + data = ethnl.fec_get({"header": {"dev-index": cfg.ifindex, + "flags": {'stats'}}}) + ksft_true(data['stats'], "driver does not report stats") + + +def pkt_byte_sum(cfg) -> None: + global netfam, rtnl + + def get_qstat(test): + global netfam + stats = netfam.qstats_get({}, dump=True) + if stats: + for qs in stats: + if qs["ifindex"]== test.ifindex: + return qs + + qstat = get_qstat(cfg) + if qstat is None: + raise KsftSkipEx("qstats not supported by the device") + + for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']: + ksft_in(key, qstat, "Drivers should always report basic keys") + + # Compare stats, rtnl stats and qstats must match, + # but the interface may be up, so do a series of dumps + # each time the more "recent" stats must be higher or same. + def stat_cmp(rstat, qstat): + for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']: + if rstat[key] != qstat[key]: + return rstat[key] - qstat[key] + return 0 + + for _ in range(10): + rtstat = rtnl.getlink({"ifi-index": cfg.ifindex})['stats'] + if stat_cmp(rtstat, qstat) < 0: + raise Exception("RTNL stats are lower, fetched later") + qstat = get_qstat(cfg) + if stat_cmp(rtstat, qstat) > 0: + raise Exception("Qstats are lower, fetched later") + + +def main() -> None: + with NetDrvEnv(__file__) as cfg: + ksft_run([check_pause, check_fec, pkt_byte_sum], + args=(cfg, )) + + +if __name__ == "__main__": + main()