netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 00/11] tools: ynl: generate code for the devlink family
@ 2023-06-07 20:23 Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 01/11] netlink: specs: devlink: fill in some details important for C Jakub Kicinski
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Another chunk of changes to support more capabilities in the YNL
code gen. Devlink brings in deep nesting and directional messages
(requests and responses have different IDs). We need a healthy
dose of codegen changes to support those (I wasn't planning to
support code gen for "directional" families initially, but
the importance of devlink and ethtool is undeniable).

I have 1 more series like this (ethtool support).

Jakub Kicinski (11):
  netlink: specs: devlink: fill in some details important for C
  tools: ynl-gen: use enum names in op strmap more carefully
  tools: ynl-gen: refactor strmap helper generation
  tools: ynl-gen: enable code gen for directional specs
  tools: ynl-gen: try to sort the types more intelligently
  tools: ynl-gen: inherit struct use info
  tools: ynl-gen: walk nested types in depth
  tools: ynl-gen: don't generate forward declarations for policies
  tools: ynl-gen: don't generate forward declarations for policies -
    regen
  tools: ynl: generate code for the devlink family
  tools: ynl: add sample for devlink

 Documentation/netlink/specs/devlink.yaml |   8 +
 tools/net/ynl/generated/Makefile         |   2 +-
 tools/net/ynl/generated/devlink-user.c   | 721 +++++++++++++++++++++++
 tools/net/ynl/generated/devlink-user.h   | 210 +++++++
 tools/net/ynl/generated/fou-user.c       |   3 -
 tools/net/ynl/generated/handshake-user.c |   4 -
 tools/net/ynl/generated/netdev-user.c    |   2 -
 tools/net/ynl/lib/nlspec.py              |  11 +-
 tools/net/ynl/samples/.gitignore         |   1 +
 tools/net/ynl/samples/devlink.c          |  60 ++
 tools/net/ynl/ynl-gen-c.py               | 137 +++--
 11 files changed, 1101 insertions(+), 58 deletions(-)
 create mode 100644 tools/net/ynl/generated/devlink-user.c
 create mode 100644 tools/net/ynl/generated/devlink-user.h
 create mode 100644 tools/net/ynl/samples/devlink.c

-- 
2.40.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH net-next 01/11] netlink: specs: devlink: fill in some details important for C
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 02/11] tools: ynl-gen: use enum names in op strmap more carefully Jakub Kicinski
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Python YNL is much more forgiving than the C code gen in terms
of the spec completeness. Fill in a handful of devlink details
to make the spec usable in C.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/devlink.yaml | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index 90641668232e..5d46ca966979 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -9,6 +9,7 @@ doc: Partial family for Devlink.
 attribute-sets:
   -
     name: devlink
+    name-prefix: devlink-attr-
     attributes:
       -
         name: bus-name
@@ -95,10 +96,12 @@ doc: Partial family for Devlink.
       -
         name: reload-action-info
         type: nest
+        multi-attr: true
         nested-attributes: dl-reload-act-info
       -
         name: reload-action-stats
         type: nest
+        multi-attr: true
         nested-attributes: dl-reload-act-stats
   -
     name: dl-dev-stats
@@ -196,3 +199,8 @@ doc: Partial family for Devlink.
           attributes:
             - bus-name
             - dev-name
+            - info-driver-name
+            - info-serial-number
+            - info-version-fixed
+            - info-version-running
+            - info-version-stored
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 02/11] tools: ynl-gen: use enum names in op strmap more carefully
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 01/11] netlink: specs: devlink: fill in some details important for C Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 03/11] tools: ynl-gen: refactor strmap helper generation Jakub Kicinski
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

In preparation for supporting families which use different msg
ids to and from the kernel - make sure the ids in op strmap
are correct. The map is expected to be used mostly for notifications,
don't generate a separate map for the "to kernel" direction.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/generated/fou-user.c | 1 -
 tools/net/ynl/lib/nlspec.py        | 4 ++++
 tools/net/ynl/ynl-gen-c.py         | 6 +++++-
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c
index c99b5d438021..a0f33bb882e4 100644
--- a/tools/net/ynl/generated/fou-user.c
+++ b/tools/net/ynl/generated/fou-user.c
@@ -16,7 +16,6 @@
 
 /* Enums */
 static const char * const fou_op_strmap[] = {
-	[FOU_CMD_UNSPEC] = "unspec",
 	[FOU_CMD_ADD] = "add",
 	[FOU_CMD_DEL] = "del",
 	[FOU_CMD_GET] = "get",
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index ada22b073aa2..bd5da8aaeac7 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -442,6 +442,10 @@ jsonschema = None
             else:
                 raise Exception("Can't parse directional ops")
 
+            if req_val == req_val_next:
+                req_val = None
+            if rsp_val == rsp_val_next:
+                rsp_val = None
             op = self.new_operation(elem, req_val, rsp_val)
             req_val = req_val_next
             rsp_val = rsp_val_next
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index c07340715601..8a0abf9048db 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -1220,7 +1220,11 @@ _C_KW = {
     map_name = f'{family.name}_op_strmap'
     cw.block_start(line=f"static const char * const {map_name}[] =")
     for op_name, op in family.msgs.items():
-        cw.p(f'[{op.enum_name}] = "{op_name}",')
+        if op.rsp_value:
+            if op.req_value == op.rsp_value:
+                cw.p(f'[{op.enum_name}] = "{op_name}",')
+            else:
+                cw.p(f'[{op.rsp_value}] = "{op_name}",')
     cw.block_end(line=';')
     cw.nl()
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 03/11] tools: ynl-gen: refactor strmap helper generation
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 01/11] netlink: specs: devlink: fill in some details important for C Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 02/11] tools: ynl-gen: use enum names in op strmap more carefully Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 04/11] tools: ynl-gen: enable code gen for directional specs Jakub Kicinski
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Move generating strmap lookup function to a helper.
No functional changes.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/ynl-gen-c.py | 36 +++++++++++++++++-------------------
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 8a0abf9048db..efcf91675dfa 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -1212,6 +1212,21 @@ _C_KW = {
     cw.nl()
 
 
+def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None):
+    args = [f'int {arg_name}']
+    if enum and not ('enum-name' in enum and not enum['enum-name']):
+        args = [f'enum {render_name} {arg_name}']
+    cw.write_func_prot('const char *', f'{render_name}_str', args)
+    cw.block_start()
+    if enum and enum.type == 'flags':
+        cw.p(f'{arg_name} = ffs({arg_name}) - 1;')
+    cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))')
+    cw.p('return NULL;')
+    cw.p(f'return {map_name}[{arg_name}];')
+    cw.block_end()
+    cw.nl()
+
+
 def put_op_name_fwd(family, cw):
     cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';')
 
@@ -1228,13 +1243,7 @@ _C_KW = {
     cw.block_end(line=';')
     cw.nl()
 
-    cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'])
-    cw.block_start()
-    cw.p(f'if (op < 0 || op >= (int)MNL_ARRAY_SIZE({map_name}))')
-    cw.p('return NULL;')
-    cw.p(f'return {map_name}[op];')
-    cw.block_end()
-    cw.nl()
+    _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op')
 
 
 def put_enum_to_str_fwd(family, cw, enum):
@@ -1252,18 +1261,7 @@ _C_KW = {
     cw.block_end(line=';')
     cw.nl()
 
-    args = [f'enum {enum.render_name} value']
-    if 'enum-name' in enum and not enum['enum-name']:
-        args = ['int value']
-    cw.write_func_prot('const char *', f'{enum.render_name}_str', args)
-    cw.block_start()
-    if enum.type == 'flags':
-        cw.p('value = ffs(value) - 1;')
-    cw.p(f'if (value < 0 || value >= (int)MNL_ARRAY_SIZE({map_name}))')
-    cw.p('return NULL;')
-    cw.p(f'return {map_name}[value];')
-    cw.block_end()
-    cw.nl()
+    _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum)
 
 
 def put_req_nested(ri, struct):
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 04/11] tools: ynl-gen: enable code gen for directional specs
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (2 preceding siblings ...)
  2023-06-07 20:23 ` [PATCH net-next 03/11] tools: ynl-gen: refactor strmap helper generation Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 05/11] tools: ynl-gen: try to sort the types more intelligently Jakub Kicinski
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

I think that user space code gen for directional specs
works after recent changes. Let them through.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/lib/nlspec.py |  7 ++++---
 tools/net/ynl/ynl-gen-c.py  | 10 +++++++---
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index bd5da8aaeac7..9f7ad87d69af 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -324,6 +324,7 @@ jsonschema = None
 
     Attributes:
         proto     protocol type (e.g. genetlink)
+        msg_id_model   enum-model for operations (unified, directional etc.)
         license   spec license (loaded from an SPDX tag on the spec)
 
         attr_sets  dict of attribute sets
@@ -349,6 +350,7 @@ jsonschema = None
         super().__init__(self, spec)
 
         self.proto = self.yaml.get('protocol', 'genetlink')
+        self.msg_id_model = self.yaml['operations'].get('enum-model', 'unified')
 
         if schema_path is None:
             schema_path = os.path.dirname(os.path.dirname(spec_path)) + f'/{self.proto}.yaml'
@@ -477,10 +479,9 @@ jsonschema = None
             attr_set = self.new_attr_set(elem)
             self.attr_sets[elem['name']] = attr_set
 
-        msg_id_model = self.yaml['operations'].get('enum-model', 'unified')
-        if msg_id_model == 'unified':
+        if self.msg_id_model == 'unified':
             self._dictify_ops_unified()
-        elif msg_id_model == 'directional':
+        elif self.msg_id_model == 'directional':
             self._dictify_ops_directional()
 
         for op in self.msgs.values():
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index efcf91675dfa..7b3e79e17c01 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -709,9 +709,6 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
     def __init__(self, family, yaml, req_value, rsp_value):
         super().__init__(family, yaml, req_value, rsp_value)
 
-        if req_value != rsp_value:
-            raise Exception("Directional messages not supported by codegen")
-
         self.render_name = family.name + '_' + c_lower(self.name)
 
         self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \
@@ -2243,6 +2240,13 @@ _C_KW = {
         os.sys.exit(1)
         return
 
+    supported_models = ['unified']
+    if args.mode == 'user':
+        supported_models += ['directional']
+    if parsed.msg_id_model not in supported_models:
+        print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
+        os.sys.exit(1)
+
     cw = CodeWriter(BaseNlLib(), out_file)
 
     _, spec_kernel = find_kernel_root(args.spec)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 05/11] tools: ynl-gen: try to sort the types more intelligently
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (3 preceding siblings ...)
  2023-06-07 20:23 ` [PATCH net-next 04/11] tools: ynl-gen: enable code gen for directional specs Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 06/11] tools: ynl-gen: inherit struct use info Jakub Kicinski
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

We need to sort the structures to avoid the need for forward
declarations. While at it remove the sort of structs when
rendering, it doesn't do anything.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/ynl-gen-c.py | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 7b3e79e17c01..d9c74a678df8 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -875,6 +875,28 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
                         inherit.add('idx')
                     self.pure_nested_structs[nested].set_inherited(inherit)
 
+        # Try to reorder according to dependencies
+        pns_key_list = list(self.pure_nested_structs.keys())
+        pns_key_seen = set()
+        rounds = len(pns_key_list)**2  # it's basically bubble sort
+        for _ in range(rounds):
+            if len(pns_key_list) == 0:
+                break
+            name = pns_key_list.pop(0)
+            finished = True
+            for _, spec in self.attr_sets[name].items():
+                if 'nested-attributes' in spec:
+                    if spec['nested-attributes'] not in pns_key_seen:
+                        # Dicts are sorted, this will make struct last
+                        struct = self.pure_nested_structs.pop(name)
+                        self.pure_nested_structs[name] = struct
+                        finished = False
+                        break
+            if finished:
+                pns_key_seen.add(name)
+            else:
+                pns_key_list.append(name)
+
     def _load_all_notify(self):
         for op_name, op in self.ops.items():
             if not op:
@@ -2379,7 +2401,7 @@ _C_KW = {
             cw.nl()
 
             cw.p('/* Common nested types */')
-            for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
+            for attr_set, struct in parsed.pure_nested_structs.items():
                 ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
                 print_type_full(ri, struct)
 
@@ -2448,7 +2470,7 @@ _C_KW = {
                 put_typol(cw, struct)
 
             cw.p('/* Common nested types */')
-            for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
+            for attr_set, struct in parsed.pure_nested_structs.items():
                 ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
 
                 free_rsp_nested(ri, struct)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 06/11] tools: ynl-gen: inherit struct use info
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (4 preceding siblings ...)
  2023-06-07 20:23 ` [PATCH net-next 05/11] tools: ynl-gen: try to sort the types more intelligently Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:23 ` [PATCH net-next 07/11] tools: ynl-gen: walk nested types in depth Jakub Kicinski
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

We only render parse and netlink generation helpers as needed,
to avoid generating dead code. Propagate the information from
first- and second-layer attribute sets onto all children.
Otherwise devlink won't work, it has a lot more levels of nesting.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/ynl-gen-c.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index d9c74a678df8..1a97cd517116 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -896,6 +896,14 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
                 pns_key_seen.add(name)
             else:
                 pns_key_list.append(name)
+        # Propagate the request / reply
+        for attr_set, struct in reversed(self.pure_nested_structs.items()):
+            for _, spec in self.attr_sets[attr_set].items():
+                if 'nested-attributes' in spec:
+                    child = self.pure_nested_structs.get(spec['nested-attributes'])
+                    if child:
+                        child.request |= struct.request
+                        child.reply |= struct.reply
 
     def _load_all_notify(self):
         for op_name, op in self.ops.items():
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 07/11] tools: ynl-gen: walk nested types in depth
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (5 preceding siblings ...)
  2023-06-07 20:23 ` [PATCH net-next 06/11] tools: ynl-gen: inherit struct use info Jakub Kicinski
@ 2023-06-07 20:23 ` Jakub Kicinski
  2023-06-07 20:24 ` [PATCH net-next 08/11] tools: ynl-gen: don't generate forward declarations for policies Jakub Kicinski
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:23 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

So far we had only created structures for nested types nested
directly in messages (second level of attrs so to speak).
Walk types in depth to support deeper nesting.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/ynl-gen-c.py | 41 +++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 1a97cd517116..0cb0f74e714b 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -854,27 +854,44 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
                 self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs)
 
     def _load_nested_sets(self):
+        attr_set_queue = list(self.root_sets.keys())
+        attr_set_seen = set(self.root_sets.keys())
+
+        while len(attr_set_queue):
+            a_set = attr_set_queue.pop(0)
+            for attr, spec in self.attr_sets[a_set].items():
+                if 'nested-attributes' not in spec:
+                    continue
+
+                nested = spec['nested-attributes']
+                if nested not in attr_set_seen:
+                    attr_set_queue.append(nested)
+                    attr_set_seen.add(nested)
+
+                inherit = set()
+                if nested not in self.root_sets:
+                    if nested not in self.pure_nested_structs:
+                        self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit)
+                else:
+                    raise Exception(f'Using attr set as root and nested not supported - {nested}')
+
+                if 'type-value' in spec:
+                    if nested in self.root_sets:
+                        raise Exception("Inheriting members to a space used as root not supported")
+                    inherit.update(set(spec['type-value']))
+                elif spec['type'] == 'array-nest':
+                    inherit.add('idx')
+                self.pure_nested_structs[nested].set_inherited(inherit)
+
         for root_set, rs_members in self.root_sets.items():
             for attr, spec in self.attr_sets[root_set].items():
                 if 'nested-attributes' in spec:
-                    inherit = set()
                     nested = spec['nested-attributes']
-                    if nested not in self.root_sets:
-                        if nested not in self.pure_nested_structs:
-                            self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit)
                     if attr in rs_members['request']:
                         self.pure_nested_structs[nested].request = True
                     if attr in rs_members['reply']:
                         self.pure_nested_structs[nested].reply = True
 
-                    if 'type-value' in spec:
-                        if nested in self.root_sets:
-                            raise Exception("Inheriting members to a space used as root not supported")
-                        inherit.update(set(spec['type-value']))
-                    elif spec['type'] == 'array-nest':
-                        inherit.add('idx')
-                    self.pure_nested_structs[nested].set_inherited(inherit)
-
         # Try to reorder according to dependencies
         pns_key_list = list(self.pure_nested_structs.keys())
         pns_key_seen = set()
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 08/11] tools: ynl-gen: don't generate forward declarations for policies
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (6 preceding siblings ...)
  2023-06-07 20:23 ` [PATCH net-next 07/11] tools: ynl-gen: walk nested types in depth Jakub Kicinski
@ 2023-06-07 20:24 ` Jakub Kicinski
  2023-06-07 20:24 ` [PATCH net-next 09/11] tools: ynl-gen: don't generate forward declarations for policies - regen Jakub Kicinski
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:24 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Now that all nested types have structs and are sorted topologically
there should be no need to generate forward declarations for policies.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/ynl-gen-c.py | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 0cb0f74e714b..251c5bfffd8d 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -1235,10 +1235,6 @@ _C_KW = {
     print_prototype(ri, "request")
 
 
-def put_typol_fwd(cw, struct):
-    cw.p(f'extern struct ynl_policy_nest {struct.render_name}_nest;')
-
-
 def put_typol(cw, struct):
     type_max = struct.attr_set.max_name
     cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =')
@@ -2485,12 +2481,10 @@ _C_KW = {
             cw.nl()
 
             cw.p('/* Policies */')
-            for name, _ in parsed.attr_sets.items():
+            for name in parsed.pure_nested_structs:
                 struct = Struct(parsed, name)
-                put_typol_fwd(cw, struct)
-            cw.nl()
-
-            for name, _ in parsed.attr_sets.items():
+                put_typol(cw, struct)
+            for name in parsed.root_sets:
                 struct = Struct(parsed, name)
                 put_typol(cw, struct)
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 09/11] tools: ynl-gen: don't generate forward declarations for policies - regen
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (7 preceding siblings ...)
  2023-06-07 20:24 ` [PATCH net-next 08/11] tools: ynl-gen: don't generate forward declarations for policies Jakub Kicinski
@ 2023-06-07 20:24 ` Jakub Kicinski
  2023-06-07 20:24 ` [PATCH net-next 10/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:24 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Renegerate code after dropping forward declarations for policies.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/generated/fou-user.c       | 2 --
 tools/net/ynl/generated/handshake-user.c | 4 ----
 tools/net/ynl/generated/netdev-user.c    | 2 --
 3 files changed, 8 deletions(-)

diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c
index a0f33bb882e4..c08c85a6b6c4 100644
--- a/tools/net/ynl/generated/fou-user.c
+++ b/tools/net/ynl/generated/fou-user.c
@@ -42,8 +42,6 @@ const char *fou_encap_type_str(int value)
 }
 
 /* Policies */
-extern struct ynl_policy_nest fou_nest;
-
 struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = {
 	[FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, },
 	[FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, },
diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c
index fe99c4ef7373..72eb1c52a8fc 100644
--- a/tools/net/ynl/generated/handshake-user.c
+++ b/tools/net/ynl/generated/handshake-user.c
@@ -69,10 +69,6 @@ const char *handshake_auth_str(enum handshake_auth value)
 }
 
 /* Policies */
-extern struct ynl_policy_nest handshake_x509_nest;
-extern struct ynl_policy_nest handshake_accept_nest;
-extern struct ynl_policy_nest handshake_done_nest;
-
 struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = {
 	[HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, },
 	[HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, },
diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c
index aea5c7cc8ead..3db6921b9fab 100644
--- a/tools/net/ynl/generated/netdev-user.c
+++ b/tools/net/ynl/generated/netdev-user.c
@@ -48,8 +48,6 @@ const char *netdev_xdp_act_str(enum netdev_xdp_act value)
 }
 
 /* Policies */
-extern struct ynl_policy_nest netdev_dev_nest;
-
 struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = {
 	[NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, },
 	[NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, },
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 10/11] tools: ynl: generate code for the devlink family
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (8 preceding siblings ...)
  2023-06-07 20:24 ` [PATCH net-next 09/11] tools: ynl-gen: don't generate forward declarations for policies - regen Jakub Kicinski
@ 2023-06-07 20:24 ` Jakub Kicinski
  2023-06-08 11:48   ` Simon Horman
  2023-06-07 20:24 ` [PATCH net-next 11/11] tools: ynl: add sample for devlink Jakub Kicinski
  2023-06-08 21:10 ` [PATCH net-next 00/11] tools: ynl: generate code for the devlink family patchwork-bot+netdevbpf
  11 siblings, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:24 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Admittedly the devlink.yaml spec is fairly limitted,
it only covers basic device get and info-get ops.
That's sufficient to be useful (monitoring FW versions
in the fleet). Plus it gives us a chance to exercise
deep nesting and directional messaging in YNL.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/generated/Makefile       |   2 +-
 tools/net/ynl/generated/devlink-user.c | 721 +++++++++++++++++++++++++
 tools/net/ynl/generated/devlink-user.h | 210 +++++++
 3 files changed, 932 insertions(+), 1 deletion(-)
 create mode 100644 tools/net/ynl/generated/devlink-user.c
 create mode 100644 tools/net/ynl/generated/devlink-user.h

diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile
index 916723193b60..8ce610910b8d 100644
--- a/tools/net/ynl/generated/Makefile
+++ b/tools/net/ynl/generated/Makefile
@@ -9,7 +9,7 @@ endif
 
 TOOL:=../ynl-gen-c.py
 
-GENS:=handshake fou netdev
+GENS:=devlink handshake fou netdev
 SRCS=$(patsubst %,%-user.c,${GENS})
 HDRS=$(patsubst %,%-user.h,${GENS})
 OBJS=$(patsubst %,%-user.o,${GENS})
diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c
new file mode 100644
index 000000000000..c3204e20b971
--- /dev/null
+++ b/tools/net/ynl/generated/devlink-user.c
@@ -0,0 +1,721 @@
+// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+/* Do not edit directly, auto-generated from: */
+/*	Documentation/netlink/specs/devlink.yaml */
+/* YNL-GEN user source */
+
+#include <stdlib.h>
+#include "devlink-user.h"
+#include "ynl.h"
+#include <linux/devlink.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+/* Enums */
+static const char * const devlink_op_strmap[] = {
+	[3] = "get",
+	[DEVLINK_CMD_INFO_GET] = "info-get",
+};
+
+const char *devlink_op_str(int op)
+{
+	if (op < 0 || op >= (int)MNL_ARRAY_SIZE(devlink_op_strmap))
+		return NULL;
+	return devlink_op_strmap[op];
+}
+
+/* Policies */
+struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, },
+};
+
+struct ynl_policy_nest devlink_dl_info_version_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_info_version_policy,
+};
+
+struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, },
+	[DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, },
+};
+
+struct ynl_policy_nest devlink_dl_reload_stats_entry_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_reload_stats_entry_policy,
+};
+
+struct ynl_policy_attr devlink_dl_reload_act_stats_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, },
+};
+
+struct ynl_policy_nest devlink_dl_reload_act_stats_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_reload_act_stats_policy,
+};
+
+struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, },
+	[DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, },
+};
+
+struct ynl_policy_nest devlink_dl_reload_act_info_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_reload_act_info_policy,
+};
+
+struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, },
+};
+
+struct ynl_policy_nest devlink_dl_reload_stats_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_reload_stats_policy,
+};
+
+struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, },
+	[DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, },
+};
+
+struct ynl_policy_nest devlink_dl_dev_stats_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_dl_dev_stats_policy,
+};
+
+struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = {
+	[DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, },
+	[DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, },
+	[DEVLINK_ATTR_INFO_VERSION_RUNNING] = { .name = "info-version-running", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, },
+	[DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, },
+	[DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, },
+	[DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, },
+	[DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, },
+	[DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, },
+	[DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, },
+	[DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, },
+	[DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, },
+	[DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, },
+	[DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, },
+	[DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, },
+	[DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, },
+};
+
+struct ynl_policy_nest devlink_nest = {
+	.max_attr = DEVLINK_ATTR_MAX,
+	.table = devlink_policy,
+};
+
+/* Common nested types */
+void devlink_dl_info_version_free(struct devlink_dl_info_version *obj)
+{
+	free(obj->info_version_name);
+	free(obj->info_version_value);
+}
+
+int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg,
+				  const struct nlattr *nested)
+{
+	struct devlink_dl_info_version *dst = yarg->data;
+	const struct nlattr *attr;
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.info_version_name_len = len;
+			dst->info_version_name = malloc(len + 1);
+			memcpy(dst->info_version_name, mnl_attr_get_str(attr), len);
+			dst->info_version_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_VALUE) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.info_version_value_len = len;
+			dst->info_version_value = malloc(len + 1);
+			memcpy(dst->info_version_value, mnl_attr_get_str(attr), len);
+			dst->info_version_value[len] = 0;
+		}
+	}
+
+	return 0;
+}
+
+void
+devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj)
+{
+}
+
+int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg,
+					const struct nlattr *nested)
+{
+	struct devlink_dl_reload_stats_entry *dst = yarg->data;
+	const struct nlattr *attr;
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_LIMIT) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_stats_limit = 1;
+			dst->reload_stats_limit = mnl_attr_get_u8(attr);
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_VALUE) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_stats_value = 1;
+			dst->reload_stats_value = mnl_attr_get_u32(attr);
+		}
+	}
+
+	return 0;
+}
+
+void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj)
+{
+	unsigned int i;
+
+	for (i = 0; i < obj->n_reload_stats_entry; i++)
+		devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]);
+	free(obj->reload_stats_entry);
+}
+
+int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg,
+				      const struct nlattr *nested)
+{
+	struct devlink_dl_reload_act_stats *dst = yarg->data;
+	unsigned int n_reload_stats_entry = 0;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+	int i;
+
+	parg.ys = yarg->ys;
+
+	if (dst->reload_stats_entry)
+		return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)");
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) {
+			n_reload_stats_entry++;
+		}
+	}
+
+	if (n_reload_stats_entry) {
+		dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry));
+		dst->n_reload_stats_entry = n_reload_stats_entry;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_reload_stats_entry_nest;
+		mnl_attr_for_each_nested(attr, nested) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) {
+				parg.data = &dst->reload_stats_entry[i];
+				if (devlink_dl_reload_stats_entry_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj)
+{
+	unsigned int i;
+
+	for (i = 0; i < obj->n_reload_action_stats; i++)
+		devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]);
+	free(obj->reload_action_stats);
+}
+
+int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg,
+				     const struct nlattr *nested)
+{
+	struct devlink_dl_reload_act_info *dst = yarg->data;
+	unsigned int n_reload_action_stats = 0;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+	int i;
+
+	parg.ys = yarg->ys;
+
+	if (dst->reload_action_stats)
+		return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)");
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_action = 1;
+			dst->reload_action = mnl_attr_get_u8(attr);
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) {
+			n_reload_action_stats++;
+		}
+	}
+
+	if (n_reload_action_stats) {
+		dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats));
+		dst->n_reload_action_stats = n_reload_action_stats;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_reload_act_stats_nest;
+		mnl_attr_for_each_nested(attr, nested) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) {
+				parg.data = &dst->reload_action_stats[i];
+				if (devlink_dl_reload_act_stats_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj)
+{
+	unsigned int i;
+
+	for (i = 0; i < obj->n_reload_action_info; i++)
+		devlink_dl_reload_act_info_free(&obj->reload_action_info[i]);
+	free(obj->reload_action_info);
+}
+
+int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg,
+				  const struct nlattr *nested)
+{
+	struct devlink_dl_reload_stats *dst = yarg->data;
+	unsigned int n_reload_action_info = 0;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+	int i;
+
+	parg.ys = yarg->ys;
+
+	if (dst->reload_action_info)
+		return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)");
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) {
+			n_reload_action_info++;
+		}
+	}
+
+	if (n_reload_action_info) {
+		dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info));
+		dst->n_reload_action_info = n_reload_action_info;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_reload_act_info_nest;
+		mnl_attr_for_each_nested(attr, nested) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) {
+				parg.data = &dst->reload_action_info[i];
+				if (devlink_dl_reload_act_info_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj)
+{
+	devlink_dl_reload_stats_free(&obj->reload_stats);
+	devlink_dl_reload_stats_free(&obj->remote_reload_stats);
+}
+
+int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg,
+			       const struct nlattr *nested)
+{
+	struct devlink_dl_dev_stats *dst = yarg->data;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+
+	parg.ys = yarg->ys;
+
+	mnl_attr_for_each_nested(attr, nested) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_stats = 1;
+
+			parg.rsp_policy = &devlink_dl_reload_stats_nest;
+			parg.data = &dst->reload_stats;
+			if (devlink_dl_reload_stats_parse(&parg, attr))
+				return MNL_CB_ERROR;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_REMOTE_RELOAD_STATS) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.remote_reload_stats = 1;
+
+			parg.rsp_policy = &devlink_dl_reload_stats_nest;
+			parg.data = &dst->remote_reload_stats;
+			if (devlink_dl_reload_stats_parse(&parg, attr))
+				return MNL_CB_ERROR;
+		}
+	}
+
+	return 0;
+}
+
+/* ============== DEVLINK_CMD_GET ============== */
+/* DEVLINK_CMD_GET - do */
+void devlink_get_req_free(struct devlink_get_req *req)
+{
+	free(req->bus_name);
+	free(req->dev_name);
+	free(req);
+}
+
+void devlink_get_rsp_free(struct devlink_get_rsp *rsp)
+{
+	free(rsp->bus_name);
+	free(rsp->dev_name);
+	devlink_dl_dev_stats_free(&rsp->dev_stats);
+	free(rsp);
+}
+
+int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data)
+{
+	struct ynl_parse_arg *yarg = data;
+	struct devlink_get_rsp *dst;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+
+	dst = yarg->data;
+	parg.ys = yarg->ys;
+
+	mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.bus_name_len = len;
+			dst->bus_name = malloc(len + 1);
+			memcpy(dst->bus_name, mnl_attr_get_str(attr), len);
+			dst->bus_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.dev_name_len = len;
+			dst->dev_name = malloc(len + 1);
+			memcpy(dst->dev_name, mnl_attr_get_str(attr), len);
+			dst->dev_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_FAILED) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_failed = 1;
+			dst->reload_failed = mnl_attr_get_u8(attr);
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.reload_action = 1;
+			dst->reload_action = mnl_attr_get_u8(attr);
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_STATS) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.dev_stats = 1;
+
+			parg.rsp_policy = &devlink_dl_dev_stats_nest;
+			parg.data = &dst->dev_stats;
+			if (devlink_dl_dev_stats_parse(&parg, attr))
+				return MNL_CB_ERROR;
+		}
+	}
+
+	return MNL_CB_OK;
+}
+
+struct devlink_get_rsp *
+devlink_get(struct ynl_sock *ys, struct devlink_get_req *req)
+{
+	struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };
+	struct devlink_get_rsp *rsp;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1);
+	ys->req_policy = &devlink_nest;
+	yrs.yarg.rsp_policy = &devlink_nest;
+
+	if (req->_present.bus_name_len)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name);
+	if (req->_present.dev_name_len)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name);
+
+	rsp = calloc(1, sizeof(*rsp));
+	yrs.yarg.data = rsp;
+	yrs.cb = devlink_get_rsp_parse;
+	yrs.rsp_cmd = 3;
+
+	err = ynl_exec(ys, nlh, &yrs);
+	if (err < 0)
+		goto err_free;
+
+	return rsp;
+
+err_free:
+	devlink_get_rsp_free(rsp);
+	return NULL;
+}
+
+/* DEVLINK_CMD_GET - dump */
+void devlink_get_list_free(struct devlink_get_list *rsp)
+{
+	struct devlink_get_list *next = rsp;
+
+	while ((void *)next != YNL_LIST_END) {
+		rsp = next;
+		next = rsp->next;
+
+		free(rsp->obj.bus_name);
+		free(rsp->obj.dev_name);
+		devlink_dl_dev_stats_free(&rsp->obj.dev_stats);
+		free(rsp);
+	}
+}
+
+struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys)
+{
+	struct ynl_dump_state yds = {};
+	struct nlmsghdr *nlh;
+	int err;
+
+	yds.ys = ys;
+	yds.alloc_sz = sizeof(struct devlink_get_list);
+	yds.cb = devlink_get_rsp_parse;
+	yds.rsp_cmd = 3;
+	yds.rsp_policy = &devlink_nest;
+
+	nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1);
+
+	err = ynl_exec_dump(ys, nlh, &yds);
+	if (err < 0)
+		goto free_list;
+
+	return yds.first;
+
+free_list:
+	devlink_get_list_free(yds.first);
+	return NULL;
+}
+
+/* ============== DEVLINK_CMD_INFO_GET ============== */
+/* DEVLINK_CMD_INFO_GET - do */
+void devlink_info_get_req_free(struct devlink_info_get_req *req)
+{
+	free(req->bus_name);
+	free(req->dev_name);
+	free(req);
+}
+
+void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp)
+{
+	unsigned int i;
+
+	free(rsp->bus_name);
+	free(rsp->dev_name);
+	free(rsp->info_driver_name);
+	free(rsp->info_serial_number);
+	for (i = 0; i < rsp->n_info_version_fixed; i++)
+		devlink_dl_info_version_free(&rsp->info_version_fixed[i]);
+	free(rsp->info_version_fixed);
+	for (i = 0; i < rsp->n_info_version_running; i++)
+		devlink_dl_info_version_free(&rsp->info_version_running[i]);
+	free(rsp->info_version_running);
+	for (i = 0; i < rsp->n_info_version_stored; i++)
+		devlink_dl_info_version_free(&rsp->info_version_stored[i]);
+	free(rsp->info_version_stored);
+	free(rsp);
+}
+
+int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data)
+{
+	unsigned int n_info_version_running = 0;
+	unsigned int n_info_version_stored = 0;
+	unsigned int n_info_version_fixed = 0;
+	struct ynl_parse_arg *yarg = data;
+	struct devlink_info_get_rsp *dst;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+	int i;
+
+	dst = yarg->data;
+	parg.ys = yarg->ys;
+
+	if (dst->info_version_fixed)
+		return ynl_error_parse(yarg, "attribute already present (devlink.info-version-fixed)");
+	if (dst->info_version_running)
+		return ynl_error_parse(yarg, "attribute already present (devlink.info-version-running)");
+	if (dst->info_version_stored)
+		return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)");
+
+	mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+		if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.bus_name_len = len;
+			dst->bus_name = malloc(len + 1);
+			memcpy(dst->bus_name, mnl_attr_get_str(attr), len);
+			dst->bus_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.dev_name_len = len;
+			dst->dev_name = malloc(len + 1);
+			memcpy(dst->dev_name, mnl_attr_get_str(attr), len);
+			dst->dev_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_DRIVER_NAME) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.info_driver_name_len = len;
+			dst->info_driver_name = malloc(len + 1);
+			memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len);
+			dst->info_driver_name[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_SERIAL_NUMBER) {
+			unsigned int len;
+
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+
+			len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));
+			dst->_present.info_serial_number_len = len;
+			dst->info_serial_number = malloc(len + 1);
+			memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len);
+			dst->info_serial_number[len] = 0;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) {
+			n_info_version_fixed++;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) {
+			n_info_version_running++;
+		}
+		else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) {
+			n_info_version_stored++;
+		}
+	}
+
+	if (n_info_version_fixed) {
+		dst->info_version_fixed = calloc(n_info_version_fixed, sizeof(*dst->info_version_fixed));
+		dst->n_info_version_fixed = n_info_version_fixed;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_info_version_nest;
+		mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) {
+				parg.data = &dst->info_version_fixed[i];
+				if (devlink_dl_info_version_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+	if (n_info_version_running) {
+		dst->info_version_running = calloc(n_info_version_running, sizeof(*dst->info_version_running));
+		dst->n_info_version_running = n_info_version_running;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_info_version_nest;
+		mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) {
+				parg.data = &dst->info_version_running[i];
+				if (devlink_dl_info_version_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+	if (n_info_version_stored) {
+		dst->info_version_stored = calloc(n_info_version_stored, sizeof(*dst->info_version_stored));
+		dst->n_info_version_stored = n_info_version_stored;
+		i = 0;
+		parg.rsp_policy = &devlink_dl_info_version_nest;
+		mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+			if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) {
+				parg.data = &dst->info_version_stored[i];
+				if (devlink_dl_info_version_parse(&parg, attr))
+					return MNL_CB_ERROR;
+				i++;
+			}
+		}
+	}
+
+	return MNL_CB_OK;
+}
+
+struct devlink_info_get_rsp *
+devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req)
+{
+	struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };
+	struct devlink_info_get_rsp *rsp;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1);
+	ys->req_policy = &devlink_nest;
+	yrs.yarg.rsp_policy = &devlink_nest;
+
+	if (req->_present.bus_name_len)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name);
+	if (req->_present.dev_name_len)
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name);
+
+	rsp = calloc(1, sizeof(*rsp));
+	yrs.yarg.data = rsp;
+	yrs.cb = devlink_info_get_rsp_parse;
+	yrs.rsp_cmd = DEVLINK_CMD_INFO_GET;
+
+	err = ynl_exec(ys, nlh, &yrs);
+	if (err < 0)
+		goto err_free;
+
+	return rsp;
+
+err_free:
+	devlink_info_get_rsp_free(rsp);
+	return NULL;
+}
+
+const struct ynl_family ynl_devlink_family =  {
+	.name		= "devlink",
+};
diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h
new file mode 100644
index 000000000000..a008b99b6e24
--- /dev/null
+++ b/tools/net/ynl/generated/devlink-user.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
+/* Do not edit directly, auto-generated from: */
+/*	Documentation/netlink/specs/devlink.yaml */
+/* YNL-GEN user header */
+
+#ifndef _LINUX_DEVLINK_GEN_H
+#define _LINUX_DEVLINK_GEN_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <linux/types.h>
+#include <linux/devlink.h>
+
+struct ynl_sock;
+
+extern const struct ynl_family ynl_devlink_family;
+
+/* Enums */
+const char *devlink_op_str(int op);
+
+/* Common nested types */
+struct devlink_dl_info_version {
+	struct {
+		__u32 info_version_name_len;
+		__u32 info_version_value_len;
+	} _present;
+
+	char *info_version_name;
+	char *info_version_value;
+};
+
+struct devlink_dl_reload_stats_entry {
+	struct {
+		__u32 reload_stats_limit:1;
+		__u32 reload_stats_value:1;
+	} _present;
+
+	__u8 reload_stats_limit;
+	__u32 reload_stats_value;
+};
+
+struct devlink_dl_reload_act_stats {
+	unsigned int n_reload_stats_entry;
+	struct devlink_dl_reload_stats_entry *reload_stats_entry;
+};
+
+struct devlink_dl_reload_act_info {
+	struct {
+		__u32 reload_action:1;
+	} _present;
+
+	__u8 reload_action;
+	unsigned int n_reload_action_stats;
+	struct devlink_dl_reload_act_stats *reload_action_stats;
+};
+
+struct devlink_dl_reload_stats {
+	unsigned int n_reload_action_info;
+	struct devlink_dl_reload_act_info *reload_action_info;
+};
+
+struct devlink_dl_dev_stats {
+	struct {
+		__u32 reload_stats:1;
+		__u32 remote_reload_stats:1;
+	} _present;
+
+	struct devlink_dl_reload_stats reload_stats;
+	struct devlink_dl_reload_stats remote_reload_stats;
+};
+
+/* ============== DEVLINK_CMD_GET ============== */
+/* DEVLINK_CMD_GET - do */
+struct devlink_get_req {
+	struct {
+		__u32 bus_name_len;
+		__u32 dev_name_len;
+	} _present;
+
+	char *bus_name;
+	char *dev_name;
+};
+
+static inline struct devlink_get_req *devlink_get_req_alloc(void)
+{
+	return calloc(1, sizeof(struct devlink_get_req));
+}
+void devlink_get_req_free(struct devlink_get_req *req);
+
+static inline void
+devlink_get_req_set_bus_name(struct devlink_get_req *req, const char *bus_name)
+{
+	free(req->bus_name);
+	req->_present.bus_name_len = strlen(bus_name);
+	req->bus_name = malloc(req->_present.bus_name_len + 1);
+	memcpy(req->bus_name, bus_name, req->_present.bus_name_len);
+	req->bus_name[req->_present.bus_name_len] = 0;
+}
+static inline void
+devlink_get_req_set_dev_name(struct devlink_get_req *req, const char *dev_name)
+{
+	free(req->dev_name);
+	req->_present.dev_name_len = strlen(dev_name);
+	req->dev_name = malloc(req->_present.dev_name_len + 1);
+	memcpy(req->dev_name, dev_name, req->_present.dev_name_len);
+	req->dev_name[req->_present.dev_name_len] = 0;
+}
+
+struct devlink_get_rsp {
+	struct {
+		__u32 bus_name_len;
+		__u32 dev_name_len;
+		__u32 reload_failed:1;
+		__u32 reload_action:1;
+		__u32 dev_stats:1;
+	} _present;
+
+	char *bus_name;
+	char *dev_name;
+	__u8 reload_failed;
+	__u8 reload_action;
+	struct devlink_dl_dev_stats dev_stats;
+};
+
+void devlink_get_rsp_free(struct devlink_get_rsp *rsp);
+
+/*
+ * Get devlink instances.
+ */
+struct devlink_get_rsp *
+devlink_get(struct ynl_sock *ys, struct devlink_get_req *req);
+
+/* DEVLINK_CMD_GET - dump */
+struct devlink_get_list {
+	struct devlink_get_list *next;
+	struct devlink_get_rsp obj __attribute__ ((aligned (8)));
+};
+
+void devlink_get_list_free(struct devlink_get_list *rsp);
+
+struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys);
+
+/* ============== DEVLINK_CMD_INFO_GET ============== */
+/* DEVLINK_CMD_INFO_GET - do */
+struct devlink_info_get_req {
+	struct {
+		__u32 bus_name_len;
+		__u32 dev_name_len;
+	} _present;
+
+	char *bus_name;
+	char *dev_name;
+};
+
+static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void)
+{
+	return calloc(1, sizeof(struct devlink_info_get_req));
+}
+void devlink_info_get_req_free(struct devlink_info_get_req *req);
+
+static inline void
+devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req,
+				  const char *bus_name)
+{
+	free(req->bus_name);
+	req->_present.bus_name_len = strlen(bus_name);
+	req->bus_name = malloc(req->_present.bus_name_len + 1);
+	memcpy(req->bus_name, bus_name, req->_present.bus_name_len);
+	req->bus_name[req->_present.bus_name_len] = 0;
+}
+static inline void
+devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req,
+				  const char *dev_name)
+{
+	free(req->dev_name);
+	req->_present.dev_name_len = strlen(dev_name);
+	req->dev_name = malloc(req->_present.dev_name_len + 1);
+	memcpy(req->dev_name, dev_name, req->_present.dev_name_len);
+	req->dev_name[req->_present.dev_name_len] = 0;
+}
+
+struct devlink_info_get_rsp {
+	struct {
+		__u32 bus_name_len;
+		__u32 dev_name_len;
+		__u32 info_driver_name_len;
+		__u32 info_serial_number_len;
+	} _present;
+
+	char *bus_name;
+	char *dev_name;
+	char *info_driver_name;
+	char *info_serial_number;
+	unsigned int n_info_version_fixed;
+	struct devlink_dl_info_version *info_version_fixed;
+	unsigned int n_info_version_running;
+	struct devlink_dl_info_version *info_version_running;
+	unsigned int n_info_version_stored;
+	struct devlink_dl_info_version *info_version_stored;
+};
+
+void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp);
+
+/*
+ * Get device information, like driver name, hardware and firmware versions etc.
+ */
+struct devlink_info_get_rsp *
+devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req);
+
+#endif /* _LINUX_DEVLINK_GEN_H */
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH net-next 11/11] tools: ynl: add sample for devlink
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (9 preceding siblings ...)
  2023-06-07 20:24 ` [PATCH net-next 10/11] tools: ynl: generate code for the devlink family Jakub Kicinski
@ 2023-06-07 20:24 ` Jakub Kicinski
  2023-06-08 21:10 ` [PATCH net-next 00/11] tools: ynl: generate code for the devlink family patchwork-bot+netdevbpf
  11 siblings, 0 replies; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-07 20:24 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, Jakub Kicinski

Add a sample to show off how to issue basic devlink requests.
For added testing issue get requests while walking a dump.

$ ./devlink
netdevsim/netdevsim1:
    driver: netdevsim
    running fw:
        fw.mgmt: 10.20.30
    ...
netdevsim/netdevsim2:
    driver: netdevsim
    running fw:
        fw.mgmt: 10.20.30
    ...

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/samples/.gitignore |  1 +
 tools/net/ynl/samples/devlink.c  | 60 ++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 tools/net/ynl/samples/devlink.c

diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore
index 7b1f5179cb54..a24678b67557 100644
--- a/tools/net/ynl/samples/.gitignore
+++ b/tools/net/ynl/samples/.gitignore
@@ -1 +1,2 @@
+devlink
 netdev
diff --git a/tools/net/ynl/samples/devlink.c b/tools/net/ynl/samples/devlink.c
new file mode 100644
index 000000000000..d2611d7ebab4
--- /dev/null
+++ b/tools/net/ynl/samples/devlink.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include "devlink-user.h"
+
+int main(int argc, char **argv)
+{
+	struct devlink_get_list *devs;
+	struct ynl_sock *ys;
+
+	ys = ynl_sock_create(&ynl_devlink_family, NULL);
+	if (!ys)
+		return 1;
+
+	devs = devlink_get_dump(ys);
+	if (!devs)
+		goto err_close;
+
+	ynl_dump_foreach(devs, d) {
+		struct devlink_info_get_req *info_req;
+		struct devlink_info_get_rsp *info_rsp;
+
+		printf("%s/%s:\n", d->bus_name, d->dev_name);
+
+		info_req = devlink_info_get_req_alloc();
+		devlink_info_get_req_set_bus_name(info_req, d->bus_name);
+		devlink_info_get_req_set_dev_name(info_req, d->dev_name);
+
+		info_rsp = devlink_info_get(ys, info_req);
+		devlink_info_get_req_free(info_req);
+		if (!info_rsp)
+			goto err_free_devs;
+
+		if (info_rsp->_present.info_driver_name_len)
+			printf("    driver: %s\n", info_rsp->info_driver_name);
+		if (info_rsp->n_info_version_running)
+			printf("    running fw:\n");
+		for (unsigned i = 0; i < info_rsp->n_info_version_running; i++)
+			printf("        %s: %s\n",
+			       info_rsp->info_version_running[i].info_version_name,
+			       info_rsp->info_version_running[i].info_version_value);
+		printf("    ...\n");
+		devlink_info_get_rsp_free(info_rsp);
+	}
+	devlink_get_list_free(devs);
+
+	ynl_sock_destroy(ys);
+
+	return 0;
+
+err_free_devs:
+	devlink_get_list_free(devs);
+err_close:
+	fprintf(stderr, "YNL: %s\n", ys->err.msg);
+	ynl_sock_destroy(ys);
+	return 2;
+}
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 10/11] tools: ynl: generate code for the devlink family
  2023-06-07 20:24 ` [PATCH net-next 10/11] tools: ynl: generate code for the devlink family Jakub Kicinski
@ 2023-06-08 11:48   ` Simon Horman
  2023-06-08 15:53     ` Jakub Kicinski
  0 siblings, 1 reply; 16+ messages in thread
From: Simon Horman @ 2023-06-08 11:48 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

On Wed, Jun 07, 2023 at 01:24:02PM -0700, Jakub Kicinski wrote:
> Admittedly the devlink.yaml spec is fairly limitted,

nit: limitted -> limited

> it only covers basic device get and info-get ops.
> That's sufficient to be useful (monitoring FW versions
> in the fleet). Plus it gives us a chance to exercise
> deep nesting and directional messaging in YNL.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

...

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 10/11] tools: ynl: generate code for the devlink family
  2023-06-08 11:48   ` Simon Horman
@ 2023-06-08 15:53     ` Jakub Kicinski
  2023-06-09  7:46       ` Simon Horman
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2023-06-08 15:53 UTC (permalink / raw)
  To: Simon Horman; +Cc: davem, netdev, edumazet, pabeni, jiri

On Thu, 8 Jun 2023 13:48:49 +0200 Simon Horman wrote:
> On Wed, Jun 07, 2023 at 01:24:02PM -0700, Jakub Kicinski wrote:
> > Admittedly the devlink.yaml spec is fairly limitted,  
> 
> nit: limitted -> limited

I'll fix when applying if that's okay (assuming it's the only comment).

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 00/11] tools: ynl: generate code for the devlink family
  2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
                   ` (10 preceding siblings ...)
  2023-06-07 20:24 ` [PATCH net-next 11/11] tools: ynl: add sample for devlink Jakub Kicinski
@ 2023-06-08 21:10 ` patchwork-bot+netdevbpf
  11 siblings, 0 replies; 16+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-06-08 21:10 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

Hello:

This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Wed,  7 Jun 2023 13:23:52 -0700 you wrote:
> Another chunk of changes to support more capabilities in the YNL
> code gen. Devlink brings in deep nesting and directional messages
> (requests and responses have different IDs). We need a healthy
> dose of codegen changes to support those (I wasn't planning to
> support code gen for "directional" families initially, but
> the importance of devlink and ethtool is undeniable).
> 
> [...]

Here is the summary with links:
  - [net-next,01/11] netlink: specs: devlink: fill in some details important for C
    https://git.kernel.org/netdev/net-next/c/8947e5037371
  - [net-next,02/11] tools: ynl-gen: use enum names in op strmap more carefully
    https://git.kernel.org/netdev/net-next/c/9858bfc271de
  - [net-next,03/11] tools: ynl-gen: refactor strmap helper generation
    https://git.kernel.org/netdev/net-next/c/6f115d4575ab
  - [net-next,04/11] tools: ynl-gen: enable code gen for directional specs
    https://git.kernel.org/netdev/net-next/c/ff6db4b58c93
  - [net-next,05/11] tools: ynl-gen: try to sort the types more intelligently
    https://git.kernel.org/netdev/net-next/c/6afaa0ef9b0e
  - [net-next,06/11] tools: ynl-gen: inherit struct use info
    https://git.kernel.org/netdev/net-next/c/37487f93b125
  - [net-next,07/11] tools: ynl-gen: walk nested types in depth
    https://git.kernel.org/netdev/net-next/c/eae7af21bdb9
  - [net-next,08/11] tools: ynl-gen: don't generate forward declarations for policies
    https://git.kernel.org/netdev/net-next/c/168dea20ecef
  - [net-next,09/11] tools: ynl-gen: don't generate forward declarations for policies - regen
    https://git.kernel.org/netdev/net-next/c/0a9471219672
  - [net-next,10/11] tools: ynl: generate code for the devlink family
    https://git.kernel.org/netdev/net-next/c/5d1a30eb989a
  - [net-next,11/11] tools: ynl: add sample for devlink
    https://git.kernel.org/netdev/net-next/c/fff8660b5425

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH net-next 10/11] tools: ynl: generate code for the devlink family
  2023-06-08 15:53     ` Jakub Kicinski
@ 2023-06-09  7:46       ` Simon Horman
  0 siblings, 0 replies; 16+ messages in thread
From: Simon Horman @ 2023-06-09  7:46 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

On Thu, Jun 08, 2023 at 08:53:00AM -0700, Jakub Kicinski wrote:
> On Thu, 8 Jun 2023 13:48:49 +0200 Simon Horman wrote:
> > On Wed, Jun 07, 2023 at 01:24:02PM -0700, Jakub Kicinski wrote:
> > > Admittedly the devlink.yaml spec is fairly limitted,  
> > 
> > nit: limitted -> limited
> 
> I'll fix when applying if that's okay (assuming it's the only comment).

Sure, that is fine by me.
I don't think I have any further comments on this series.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-06-09  7:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-07 20:23 [PATCH net-next 00/11] tools: ynl: generate code for the devlink family Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 01/11] netlink: specs: devlink: fill in some details important for C Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 02/11] tools: ynl-gen: use enum names in op strmap more carefully Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 03/11] tools: ynl-gen: refactor strmap helper generation Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 04/11] tools: ynl-gen: enable code gen for directional specs Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 05/11] tools: ynl-gen: try to sort the types more intelligently Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 06/11] tools: ynl-gen: inherit struct use info Jakub Kicinski
2023-06-07 20:23 ` [PATCH net-next 07/11] tools: ynl-gen: walk nested types in depth Jakub Kicinski
2023-06-07 20:24 ` [PATCH net-next 08/11] tools: ynl-gen: don't generate forward declarations for policies Jakub Kicinski
2023-06-07 20:24 ` [PATCH net-next 09/11] tools: ynl-gen: don't generate forward declarations for policies - regen Jakub Kicinski
2023-06-07 20:24 ` [PATCH net-next 10/11] tools: ynl: generate code for the devlink family Jakub Kicinski
2023-06-08 11:48   ` Simon Horman
2023-06-08 15:53     ` Jakub Kicinski
2023-06-09  7:46       ` Simon Horman
2023-06-07 20:24 ` [PATCH net-next 11/11] tools: ynl: add sample for devlink Jakub Kicinski
2023-06-08 21:10 ` [PATCH net-next 00/11] tools: ynl: generate code for the devlink family patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).