summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGal Pressman <gal@nvidia.com>2025-11-18 16:32:06 +0200
committerPaolo Abeni <pabeni@redhat.com>2025-11-20 15:43:04 +0100
commit2a2d5a3392b63ef5141c158117dba4f3b9b3ac22 (patch)
treee25662e29e98ffb94b7597d8dd3d7c1cb31fbdf8
parent7828a4d3f6dbd8d44948726589457b152e3be79b (diff)
tools: ynl: cli: Add --list-attrs option to show operation attributes
Add a --list-attrs option to the YNL CLI that displays information about netlink operations, including request and reply attributes. This eliminates the need to manually inspect YAML spec files to determine the JSON structure required for operations, or understand the structure of the reply. Example usage: # ./cli.py --family netdev --list-attrs dev-get Operation: dev-get Get / dump information about a netdev. Do request attributes: - ifindex: u32 netdev ifindex Do reply attributes: - ifindex: u32 netdev ifindex - xdp-features: u64 (enum: xdp-act) Bitmask of enabled xdp-features. - xdp-zc-max-segs: u32 max fragment count supported by ZC driver - xdp-rx-metadata-features: u64 (enum: xdp-rx-metadata) Bitmask of supported XDP receive metadata features. See Documentation/networking/xdp-rx-metadata.rst for more details. - xsk-features: u64 (enum: xsk-flags) Bitmask of enabled AF_XDP features. Dump reply attributes: - ifindex: u32 netdev ifindex - xdp-features: u64 (enum: xdp-act) Bitmask of enabled xdp-features. - xdp-zc-max-segs: u32 max fragment count supported by ZC driver - xdp-rx-metadata-features: u64 (enum: xdp-rx-metadata) Bitmask of supported XDP receive metadata features. See Documentation/networking/xdp-rx-metadata.rst for more details. - xsk-features: u64 (enum: xsk-flags) Bitmask of enabled AF_XDP features. Reviewed-by: Nimrod Oren <noren@nvidia.com> Signed-off-by: Gal Pressman <gal@nvidia.com> Link: https://patch.msgid.link/20251118143208.2380814-2-gal@nvidia.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rwxr-xr-xtools/net/ynl/pyynl/cli.py56
1 files changed, 56 insertions, 0 deletions
diff --git a/tools/net/ynl/pyynl/cli.py b/tools/net/ynl/pyynl/cli.py
index 8c192e900bd3..4d91a2cee381 100755
--- a/tools/net/ynl/pyynl/cli.py
+++ b/tools/net/ynl/pyynl/cli.py
@@ -7,6 +7,7 @@ import os
import pathlib
import pprint
import sys
+import textwrap
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import YnlFamily, Netlink, NlError
@@ -39,6 +40,37 @@ class YnlEncoder(json.JSONEncoder):
return json.JSONEncoder.default(self, obj)
+def print_attr_list(attr_names, attr_set):
+ """Print a list of attributes with their types and documentation."""
+ for attr_name in attr_names:
+ if attr_name in attr_set.attrs:
+ attr = attr_set.attrs[attr_name]
+ attr_info = f' - {attr_name}: {attr.type}'
+ if 'enum' in attr.yaml:
+ attr_info += f" (enum: {attr.yaml['enum']})"
+ if attr.yaml.get('doc'):
+ doc_text = textwrap.indent(attr.yaml['doc'], ' ')
+ attr_info += f"\n{doc_text}"
+ print(attr_info)
+
+
+def print_mode_attrs(mode, mode_spec, attr_set, print_request=True):
+ """Print a given mode (do/dump/event/notify)."""
+ mode_title = mode.capitalize()
+
+ if print_request and 'request' in mode_spec and 'attributes' in mode_spec['request']:
+ print(f'\n{mode_title} request attributes:')
+ print_attr_list(mode_spec['request']['attributes'], attr_set)
+
+ if 'reply' in mode_spec and 'attributes' in mode_spec['reply']:
+ print(f'\n{mode_title} reply attributes:')
+ print_attr_list(mode_spec['reply']['attributes'], attr_set)
+
+ if 'attributes' in mode_spec:
+ print(f'\n{mode_title} attributes:')
+ print_attr_list(mode_spec['attributes'], attr_set)
+
+
def main():
description = """
YNL CLI utility - a general purpose netlink utility that uses YAML
@@ -70,6 +102,8 @@ def main():
group.add_argument('--dump', dest='dump', metavar='DUMP-OPERATION', type=str)
group.add_argument('--list-ops', action='store_true')
group.add_argument('--list-msgs', action='store_true')
+ group.add_argument('--list-attrs', dest='list_attrs', metavar='OPERATION', type=str,
+ help='List attributes for an operation')
parser.add_argument('--duration', dest='duration', type=int,
help='when subscribed, watch for DURATION seconds')
@@ -135,6 +169,28 @@ def main():
for op_name, op in ynl.msgs.items():
print(op_name, " [", ", ".join(op.modes), "]")
+ if args.list_attrs:
+ op = ynl.msgs.get(args.list_attrs)
+ if not op:
+ print(f'Operation {args.list_attrs} not found')
+ exit(1)
+
+ print(f'Operation: {op.name}')
+ print(op.yaml['doc'])
+
+ for mode in ['do', 'dump', 'event']:
+ if mode in op.yaml:
+ print_mode_attrs(mode, op.yaml[mode], op.attr_set, True)
+
+ if 'notify' in op.yaml:
+ mode_spec = op.yaml['notify']
+ ref_spec = ynl.msgs.get(mode_spec).yaml.get('do')
+ if ref_spec:
+ print_mode_attrs('notify', ref_spec, op.attr_set, False)
+
+ if 'mcgrp' in op.yaml:
+ print(f"\nMulticast group: {op.yaml['mcgrp']}")
+
try:
if args.do:
reply = ynl.do(args.do, attrs, args.flags)