From e2ece0bc5ab1f7e0bb00f3b81fd4132b774d880d Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Mon, 29 Jan 2024 22:34:46 +0000 Subject: tools/net/ynl: Add --output-json arg to ynl cli The ynl cli currently emits python pretty printed structures which is hard to consume. Add a new --output-json argument to emit JSON. Signed-off-by: Donald Hunter Reviewed-by: Breno Leitao Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20240129223458.52046-2-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/cli.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'tools/net/ynl/cli.py') diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index 2ad9ec0f5545..0f8239979670 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -9,6 +9,15 @@ import time from lib import YnlFamily, Netlink +class YnlEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, bytes): + return bytes.hex(obj) + if isinstance(obj, set): + return list(obj) + return json.JSONEncoder.default(self, obj) + + def main(): parser = argparse.ArgumentParser(description='YNL CLI sample') parser.add_argument('--spec', dest='spec', type=str, required=True) @@ -28,8 +37,15 @@ def main(): parser.add_argument('--append', dest='flags', action='append_const', const=Netlink.NLM_F_APPEND) parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) + parser.add_argument('--output-json', action='store_true') args = parser.parse_args() + def output(msg): + if args.output_json: + print(json.dumps(msg, cls=YnlEncoder)) + else: + pprint.PrettyPrinter().pprint(msg) + if args.no_schema: args.schema = '' @@ -47,14 +63,14 @@ def main(): if args.do: reply = ynl.do(args.do, attrs, args.flags) - pprint.PrettyPrinter().pprint(reply) + output(reply) if args.dump: reply = ynl.dump(args.dump, attrs) - pprint.PrettyPrinter().pprint(reply) + output(reply) if args.ntf: ynl.check_ntf() - pprint.PrettyPrinter().pprint(ynl.async_msg_queue) + output(ynl.async_msg_queue) if __name__ == "__main__": -- cgit v1.2.3 From c0111878d45e3bb8779886fbf956b574bac8a3aa Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 4 Mar 2024 21:33:10 -0800 Subject: tools: ynl: add --dbg-small-recv for easier kernel testing Most "production" netlink clients use large buffers to make dump efficient, which means that handling of dump continuation in the kernel is not very well tested. Add an option for debugging / testing handling of dumps. It enables printing of extra netlink-level debug and lowers the recv() buffer size in one go. When used without any argument (--dbg-small-recv) it picks a very small default (4000), explicit size can be set, too (--dbg-small-recv 5000). Example: $ ./cli.py [...] --dbg-small-recv Recv: read 3712 bytes, 29 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 Recv: read 3968 bytes, 31 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 Recv: read 532 bytes, 5 messages nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 [...] nl_len = 128 (112) nl_flags = 0x0 nl_type = 19 nl_len = 20 (4) nl_flags = 0x2 nl_type = 3 (the [...] are edits to shorten the commit message). Note that the first message of the dump is sized conservatively by the kernel. Signed-off-by: Jakub Kicinski Reviewed-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/cli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/net/ynl/cli.py') diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index 0f8239979670..e8a65fbc3698 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -38,6 +38,8 @@ def main(): const=Netlink.NLM_F_APPEND) parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) parser.add_argument('--output-json', action='store_true') + parser.add_argument('--dbg-small-recv', default=0, const=4000, + action='store', nargs='?', type=int) args = parser.parse_args() def output(msg): @@ -53,7 +55,10 @@ def main(): if args.json_text: attrs = json.loads(args.json_text) - ynl = YnlFamily(args.spec, args.schema, args.process_unknown) + ynl = YnlFamily(args.spec, args.schema, args.process_unknown, + recv_size=args.dbg_small_recv) + if args.dbg_small_recv: + ynl.set_recv_dbg(True) if args.ntf: ynl.ntf_subscribe(args.ntf) -- cgit v1.2.3 From 771b7012e5f3a49739dab4be60b87517a249a1df Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Wed, 6 Mar 2024 23:10:42 +0000 Subject: tools/net/ynl: Report netlink errors without stacktrace ynl does not handle NlError exceptions so they get reported like program failures. Handle the NlError exceptions and report the netlink errors more cleanly. Example now: Netlink error: No such file or directory nl_len = 44 (28) nl_flags = 0x300 nl_type = 2 error: -2 extack: {'bad-attr': '.op'} Example before: Traceback (most recent call last): File "/home/donaldh/net-next/./tools/net/ynl/cli.py", line 81, in main() File "/home/donaldh/net-next/./tools/net/ynl/cli.py", line 69, in main reply = ynl.dump(args.dump, attrs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/donaldh/net-next/tools/net/ynl/lib/ynl.py", line 906, in dump return self._op(method, vals, [], dump=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/donaldh/net-next/tools/net/ynl/lib/ynl.py", line 872, in _op raise NlError(nl_msg) lib.ynl.NlError: Netlink error: No such file or directory nl_len = 44 (28) nl_flags = 0x300 nl_type = 2 error: -2 extack: {'bad-attr': '.op'} Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20240306231046.97158-3-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/cli.py | 18 +++++++++++------- tools/net/ynl/lib/__init__.py | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'tools/net/ynl/cli.py') diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index e8a65fbc3698..f131e33ac3ee 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -6,7 +6,7 @@ import json import pprint import time -from lib import YnlFamily, Netlink +from lib import YnlFamily, Netlink, NlError class YnlEncoder(json.JSONEncoder): @@ -66,12 +66,16 @@ def main(): if args.sleep: time.sleep(args.sleep) - if args.do: - reply = ynl.do(args.do, attrs, args.flags) - output(reply) - if args.dump: - reply = ynl.dump(args.dump, attrs) - output(reply) + try: + if args.do: + reply = ynl.do(args.do, attrs, args.flags) + output(reply) + if args.dump: + reply = ynl.dump(args.dump, attrs) + output(reply) + except NlError as e: + print(e) + exit(1) if args.ntf: ynl.check_ntf() diff --git a/tools/net/ynl/lib/__init__.py b/tools/net/ynl/lib/__init__.py index f7eaa07783e7..9137b83e580a 100644 --- a/tools/net/ynl/lib/__init__.py +++ b/tools/net/ynl/lib/__init__.py @@ -2,7 +2,7 @@ from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ SpecFamily, SpecOperation -from .ynl import YnlFamily, Netlink +from .ynl import YnlFamily, Netlink, NlError __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", - "SpecFamily", "SpecOperation", "YnlFamily", "Netlink"] + "SpecFamily", "SpecOperation", "YnlFamily", "Netlink", "NlError"] -- cgit v1.2.3