1981cbcb0SJakub Kicinski#!/usr/bin/env python3 237d9df22SJakub Kicinski# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 34e4480e8SJakub Kicinski 44e4480e8SJakub Kicinskiimport argparse 54e4480e8SJakub Kicinskiimport json 64e4480e8SJakub Kicinskiimport pprint 74e4480e8SJakub Kicinskiimport time 84e4480e8SJakub Kicinski 9771b7012SDonald Hunterfrom lib import YnlFamily, Netlink, NlError 104e4480e8SJakub Kicinski 114e4480e8SJakub Kicinski 12e2ece0bcSDonald Hunterclass YnlEncoder(json.JSONEncoder): 13e2ece0bcSDonald Hunter def default(self, obj): 14e2ece0bcSDonald Hunter if isinstance(obj, bytes): 15e2ece0bcSDonald Hunter return bytes.hex(obj) 16e2ece0bcSDonald Hunter if isinstance(obj, set): 17e2ece0bcSDonald Hunter return list(obj) 18e2ece0bcSDonald Hunter return json.JSONEncoder.default(self, obj) 19e2ece0bcSDonald Hunter 20e2ece0bcSDonald Hunter 214e4480e8SJakub Kicinskidef main(): 22ba8be00fSDonald Hunter description = """ 23ba8be00fSDonald Hunter YNL CLI utility - a general purpose netlink utility that uses YAML 24ba8be00fSDonald Hunter specs to drive protocol encoding and decoding. 25ba8be00fSDonald Hunter """ 26ba8be00fSDonald Hunter epilog = """ 27ba8be00fSDonald Hunter The --multi option can be repeated to include several do operations 28ba8be00fSDonald Hunter in the same netlink payload. 29ba8be00fSDonald Hunter """ 30ba8be00fSDonald Hunter 31ba8be00fSDonald Hunter parser = argparse.ArgumentParser(description=description, 32ba8be00fSDonald Hunter epilog=epilog) 334e4480e8SJakub Kicinski parser.add_argument('--spec', dest='spec', type=str, required=True) 344e4480e8SJakub Kicinski parser.add_argument('--schema', dest='schema', type=str) 355c6674f6SJakub Kicinski parser.add_argument('--no-schema', action='store_true') 364e4480e8SJakub Kicinski parser.add_argument('--json', dest='json_text', type=str) 37ba8be00fSDonald Hunter 38ba8be00fSDonald Hunter group = parser.add_mutually_exclusive_group() 39ba8be00fSDonald Hunter group.add_argument('--do', dest='do', metavar='DO-OPERATION', type=str) 40ba8be00fSDonald Hunter group.add_argument('--multi', dest='multi', nargs=2, action='append', 41ba8be00fSDonald Hunter metavar=('DO-OPERATION', 'JSON_TEXT'), type=str) 42ba8be00fSDonald Hunter group.add_argument('--dump', dest='dump', metavar='DUMP-OPERATION', type=str) 43*3e51f2cbSJakub Kicinski group.add_argument('--list-ops', action='store_true') 44*3e51f2cbSJakub Kicinski group.add_argument('--list-msgs', action='store_true') 45ba8be00fSDonald Hunter 464e4480e8SJakub Kicinski parser.add_argument('--sleep', dest='sleep', type=int) 474e4480e8SJakub Kicinski parser.add_argument('--subscribe', dest='ntf', type=str) 481768d8a7SDonald Hunter parser.add_argument('--replace', dest='flags', action='append_const', 491768d8a7SDonald Hunter const=Netlink.NLM_F_REPLACE) 501768d8a7SDonald Hunter parser.add_argument('--excl', dest='flags', action='append_const', 511768d8a7SDonald Hunter const=Netlink.NLM_F_EXCL) 521768d8a7SDonald Hunter parser.add_argument('--create', dest='flags', action='append_const', 531768d8a7SDonald Hunter const=Netlink.NLM_F_CREATE) 541768d8a7SDonald Hunter parser.add_argument('--append', dest='flags', action='append_const', 551768d8a7SDonald Hunter const=Netlink.NLM_F_APPEND) 56d96e48a3SJiri Pirko parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction) 57e2ece0bcSDonald Hunter parser.add_argument('--output-json', action='store_true') 58c0111878SJakub Kicinski parser.add_argument('--dbg-small-recv', default=0, const=4000, 59c0111878SJakub Kicinski action='store', nargs='?', type=int) 604e4480e8SJakub Kicinski args = parser.parse_args() 614e4480e8SJakub Kicinski 62e2ece0bcSDonald Hunter def output(msg): 63e2ece0bcSDonald Hunter if args.output_json: 64e2ece0bcSDonald Hunter print(json.dumps(msg, cls=YnlEncoder)) 65e2ece0bcSDonald Hunter else: 66e2ece0bcSDonald Hunter pprint.PrettyPrinter().pprint(msg) 67e2ece0bcSDonald Hunter 685c6674f6SJakub Kicinski if args.no_schema: 695c6674f6SJakub Kicinski args.schema = '' 705c6674f6SJakub Kicinski 714e4480e8SJakub Kicinski attrs = {} 724e4480e8SJakub Kicinski if args.json_text: 734e4480e8SJakub Kicinski attrs = json.loads(args.json_text) 744e4480e8SJakub Kicinski 75c0111878SJakub Kicinski ynl = YnlFamily(args.spec, args.schema, args.process_unknown, 76c0111878SJakub Kicinski recv_size=args.dbg_small_recv) 77c0111878SJakub Kicinski if args.dbg_small_recv: 78c0111878SJakub Kicinski ynl.set_recv_dbg(True) 794e4480e8SJakub Kicinski 804e4480e8SJakub Kicinski if args.ntf: 814e4480e8SJakub Kicinski ynl.ntf_subscribe(args.ntf) 824e4480e8SJakub Kicinski 834e4480e8SJakub Kicinski if args.sleep: 844e4480e8SJakub Kicinski time.sleep(args.sleep) 854e4480e8SJakub Kicinski 86*3e51f2cbSJakub Kicinski if args.list_ops: 87*3e51f2cbSJakub Kicinski for op_name, op in ynl.ops.items(): 88*3e51f2cbSJakub Kicinski print(op_name, " [", ", ".join(op.modes), "]") 89*3e51f2cbSJakub Kicinski if args.list_msgs: 90*3e51f2cbSJakub Kicinski for op_name, op in ynl.msgs.items(): 91*3e51f2cbSJakub Kicinski print(op_name, " [", ", ".join(op.modes), "]") 92*3e51f2cbSJakub Kicinski 93771b7012SDonald Hunter try: 948dfec0a8SJakub Kicinski if args.do: 951768d8a7SDonald Hunter reply = ynl.do(args.do, attrs, args.flags) 96e2ece0bcSDonald Hunter output(reply) 978dfec0a8SJakub Kicinski if args.dump: 988dfec0a8SJakub Kicinski reply = ynl.dump(args.dump, attrs) 99e2ece0bcSDonald Hunter output(reply) 100ba8be00fSDonald Hunter if args.multi: 101ba8be00fSDonald Hunter ops = [ (item[0], json.loads(item[1]), args.flags or []) for item in args.multi ] 102ba8be00fSDonald Hunter reply = ynl.do_multi(ops) 103ba8be00fSDonald Hunter output(reply) 104771b7012SDonald Hunter except NlError as e: 105771b7012SDonald Hunter print(e) 106771b7012SDonald Hunter exit(1) 1074e4480e8SJakub Kicinski 1084e4480e8SJakub Kicinski if args.ntf: 1094e4480e8SJakub Kicinski ynl.check_ntf() 110e2ece0bcSDonald Hunter output(ynl.async_msg_queue) 1114e4480e8SJakub Kicinski 1124e4480e8SJakub Kicinski 1134e4480e8SJakub Kicinskiif __name__ == "__main__": 1144e4480e8SJakub Kicinski main() 115