diff mbox series

[net-next,06/13] tools: ynl: introduce attribute-replace for sub-message

Message ID 20240219172525.71406-7-jiri@resnulli.us (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series netlink: specs: devlink: add the rest of missing attribute definitions | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl fail Generated files up to date; build failed; build has 3 warnings/errors; GEN HAS DIFF 2 files changed, 12648 deletions(-);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 2 maintainers not CCed: linux-doc@vger.kernel.org corbet@lwn.net
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 111 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-02-19--21-00 (tests: 1357)

Commit Message

Jiri Pirko Feb. 19, 2024, 5:25 p.m. UTC
From: Jiri Pirko <jiri@nvidia.com>

For devlink param, param-value-data attr is used by kernel to fill
different attribute type according to param-type attribute value.

Currently the sub-message feature allows spec to embed custom message
selected by another attribute. The sub-message is then nested inside the
attr of sub-message type.

Benefit from the sub-message feature and extend it. Introduce
attribute-replace spec flag by which the spec indicates that ynl should
consider sub-message as not nested in the original attribute, but rather
to consider the original attribute as the sub-message right away.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
---
 Documentation/netlink/genetlink-legacy.yaml   |  4 +++
 Documentation/netlink/netlink-raw.yaml        |  4 +++
 .../netlink/genetlink-legacy.rst              | 25 ++++++++++++++++++
 tools/net/ynl/lib/nlspec.py                   |  6 +++++
 tools/net/ynl/lib/ynl.py                      | 26 ++++++++++++++-----
 5 files changed, 59 insertions(+), 6 deletions(-)

Comments

Jakub Kicinski Feb. 19, 2024, 10:52 p.m. UTC | #1
On Mon, 19 Feb 2024 18:25:22 +0100 Jiri Pirko wrote:
> For devlink param, param-value-data attr is used by kernel to fill
> different attribute type according to param-type attribute value.
> 
> Currently the sub-message feature allows spec to embed custom message
> selected by another attribute. The sub-message is then nested inside the
> attr of sub-message type.
> 
> Benefit from the sub-message feature and extend it. Introduce
> attribute-replace spec flag by which the spec indicates that ynl should
> consider sub-message as not nested in the original attribute, but rather
> to consider the original attribute as the sub-message right away.

The "type agnostic" / generic style of devlink params and fmsg
are contrary to YNL's direction and goals. YNL abstracts parsing
and typing using external spec. devlink params and fmsg go in a
different direction where all information is carried by netlink values
and netlink typing is just to create "JSON-like" formatting.
These are incompatible ideas, and combining these two abstractions
in one library provides little value - devlink CLI already has an
implementation for fmsg and params. YNL doesn't have to cover
everything.
Jiri Pirko Feb. 20, 2024, 7:31 a.m. UTC | #2
Mon, Feb 19, 2024 at 11:52:04PM CET, kuba@kernel.org wrote:
>On Mon, 19 Feb 2024 18:25:22 +0100 Jiri Pirko wrote:
>> For devlink param, param-value-data attr is used by kernel to fill
>> different attribute type according to param-type attribute value.
>> 
>> Currently the sub-message feature allows spec to embed custom message
>> selected by another attribute. The sub-message is then nested inside the
>> attr of sub-message type.
>> 
>> Benefit from the sub-message feature and extend it. Introduce
>> attribute-replace spec flag by which the spec indicates that ynl should
>> consider sub-message as not nested in the original attribute, but rather
>> to consider the original attribute as the sub-message right away.
>
>The "type agnostic" / generic style of devlink params and fmsg
>are contrary to YNL's direction and goals. YNL abstracts parsing

True, but that's what we have. Similar to what we have in TC where
sub-messages are present, that is also against ynl's direction and
goals.

>and typing using external spec. devlink params and fmsg go in a
>different direction where all information is carried by netlink values
>and netlink typing is just to create "JSON-like" formatting.

Only fmsg, not params.

>These are incompatible ideas, and combining these two abstractions
>in one library provides little value - devlink CLI already has an
>implementation for fmsg and params. YNL doesn't have to cover
>everything.

True. In this patchset, I'm just using the existing sub-message
infrastructure with a bit of extension. The json-like thing of fmsg is
ignored, I don't try to reconstruct json from netlink message of fmsg.
Jakub Kicinski Feb. 21, 2024, 2:10 a.m. UTC | #3
On Tue, 20 Feb 2024 08:31:23 +0100 Jiri Pirko wrote:
> >The "type agnostic" / generic style of devlink params and fmsg
> >are contrary to YNL's direction and goals. YNL abstracts parsing  
> 
> True, but that's what we have. Similar to what we have in TC where
> sub-messages are present, that is also against ynl's direction and
> goals.

But TC and ip-link are raw netlink, meaning genetlink-legacy remains
fairly straightforward. BTW since we currently have full parity in C
code gen adding this series will break build for tools/net/ynl.

Plus ip-link is a really high value target. I had been pondering how 
to solve it myself. There's probably a hundred different implementations
out there of container management systems which spawn veths using odd
hacks because "netlink is scary". Once I find the time to finish
rtnetlink codegen we can replace all  the unholy libbpf netlink hacks
with ynl, too.

So at this stage I'd really like to focus YNL on language coverage
(adding more codegens), packaging and usability polish, not extending
the spec definitions to cover not-so-often used corner cases.
Especially those which will barely benefit because they are in
themselves built to be an abstraction.
Jiri Pirko Feb. 21, 2024, 12:48 p.m. UTC | #4
Wed, Feb 21, 2024 at 03:10:04AM CET, kuba@kernel.org wrote:
>On Tue, 20 Feb 2024 08:31:23 +0100 Jiri Pirko wrote:
>> >The "type agnostic" / generic style of devlink params and fmsg
>> >are contrary to YNL's direction and goals. YNL abstracts parsing  
>> 
>> True, but that's what we have. Similar to what we have in TC where
>> sub-messages are present, that is also against ynl's direction and
>> goals.
>
>But TC and ip-link are raw netlink, meaning genetlink-legacy remains
>fairly straightforward. BTW since we currently have full parity in C
>code gen adding this series will break build for tools/net/ynl.
>
>Plus ip-link is a really high value target. I had been pondering how 
>to solve it myself. There's probably a hundred different implementations
>out there of container management systems which spawn veths using odd
>hacks because "netlink is scary". Once I find the time to finish
>rtnetlink codegen we can replace all  the unholy libbpf netlink hacks
>with ynl, too.
>
>So at this stage I'd really like to focus YNL on language coverage
>(adding more codegens), packaging and usability polish, not extending
>the spec definitions to cover not-so-often used corner cases.
>Especially those which will barely benefit because they are in
>themselves built to be an abstraction.

That leaves devlink.yaml incomplete, which I'm not happy about. It is a
legacy, it should be covered by genetlink-legacy I believe.

To undestand you correctly, should I wait until codegen for raw netlink
is done and then to rebase-repost this? Or do you say this will never be
acceptable?
Jakub Kicinski Feb. 21, 2024, 6:45 p.m. UTC | #5
On Wed, 21 Feb 2024 13:48:13 +0100 Jiri Pirko wrote:
> >But TC and ip-link are raw netlink, meaning genetlink-legacy remains
> >fairly straightforward. BTW since we currently have full parity in C
> >code gen adding this series will break build for tools/net/ynl.
> >
> >Plus ip-link is a really high value target. I had been pondering how 
> >to solve it myself. There's probably a hundred different implementations
> >out there of container management systems which spawn veths using odd
> >hacks because "netlink is scary". Once I find the time to finish
> >rtnetlink codegen we can replace all  the unholy libbpf netlink hacks
> >with ynl, too.
> >
> >So at this stage I'd really like to focus YNL on language coverage
> >(adding more codegens), packaging and usability polish, not extending
> >the spec definitions to cover not-so-often used corner cases.
> >Especially those which will barely benefit because they are in
> >themselves built to be an abstraction.  
> 
> That leaves devlink.yaml incomplete, which I'm not happy about. It is a
> legacy, it should be covered by genetlink-legacy I believe.
> 
> To undestand you correctly, should I wait until codegen for raw netlink
> is done and then to rebase-repost this? Or do you say this will never be
> acceptable?

It'd definitely not acceptable before the rtnetlink C codegen is
complete, and at least two other code gens for genetlink-legacy.
At that point we can reconsider complicating the schema further.
Jiri Pirko Feb. 22, 2024, 1:20 p.m. UTC | #6
Wed, Feb 21, 2024 at 07:45:05PM CET, kuba@kernel.org wrote:
>On Wed, 21 Feb 2024 13:48:13 +0100 Jiri Pirko wrote:
>> >But TC and ip-link are raw netlink, meaning genetlink-legacy remains
>> >fairly straightforward. BTW since we currently have full parity in C
>> >code gen adding this series will break build for tools/net/ynl.
>> >
>> >Plus ip-link is a really high value target. I had been pondering how 
>> >to solve it myself. There's probably a hundred different implementations
>> >out there of container management systems which spawn veths using odd
>> >hacks because "netlink is scary". Once I find the time to finish
>> >rtnetlink codegen we can replace all  the unholy libbpf netlink hacks
>> >with ynl, too.
>> >
>> >So at this stage I'd really like to focus YNL on language coverage
>> >(adding more codegens), packaging and usability polish, not extending
>> >the spec definitions to cover not-so-often used corner cases.
>> >Especially those which will barely benefit because they are in
>> >themselves built to be an abstraction.  
>> 
>> That leaves devlink.yaml incomplete, which I'm not happy about. It is a
>> legacy, it should be covered by genetlink-legacy I believe.
>> 
>> To undestand you correctly, should I wait until codegen for raw netlink
>> is done and then to rebase-repost this? Or do you say this will never be
>> acceptable?
>
>It'd definitely not acceptable before the rtnetlink C codegen is
>complete, and at least two other code gens for genetlink-legacy.
>At that point we can reconsider complicating the schema further.

Okay, will keep it in the cupboard for now. I would definitelly love to
get the devlink.yaml complete. Next step is to generate the uapi header
from it replacing the existing one.
diff mbox series

Patch

diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml
index 6cb50e2cc021..77d89f81c71f 100644
--- a/Documentation/netlink/genetlink-legacy.yaml
+++ b/Documentation/netlink/genetlink-legacy.yaml
@@ -328,6 +328,10 @@  properties:
                   Name of the attribute space from which to resolve attributes
                   in the sub message.
                 type: string
+              attribute-replace:
+                description: |
+                  Replace the parent nested attribute with attribute set
+                type: boolean
 
   operations:
     description: Operations supported by the protocol.
diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml
index cc38b026c451..e32660fbe6c3 100644
--- a/Documentation/netlink/netlink-raw.yaml
+++ b/Documentation/netlink/netlink-raw.yaml
@@ -346,6 +346,10 @@  properties:
                   Name of the attribute space from which to resolve attributes
                   in the sub message.
                 type: string
+              attribute-replace:
+                description: |
+                  Replace the parent nested attribute with attribute set
+                type: boolean
 
   operations:
     description: Operations supported by the protocol.
diff --git a/Documentation/userspace-api/netlink/genetlink-legacy.rst b/Documentation/userspace-api/netlink/genetlink-legacy.rst
index 7126b650090e..a9ccbfbb4a8d 100644
--- a/Documentation/userspace-api/netlink/genetlink-legacy.rst
+++ b/Documentation/userspace-api/netlink/genetlink-legacy.rst
@@ -381,3 +381,28 @@  alongside a sub-message selector and also in a top level ``attribute-set``, then
 the selector will be resolved using the value 'closest' to the selector. If the
 value is not present in the message at the same level as defined in the spec
 then this is an error.
+
+Some users, like devlink param, fill different attribute type according to
+selector attribute value. ``replace-attribute`` set to ``true`` indicates,
+that sub-message is not nested inside the attribute, but rather replacing
+the attribute. This allows to treat the attribute type differently according
+to the selector:
+
+.. code-block:: yaml
+
+  sub-messages:
+    -
+      name: dl-param-value-data-msg
+      formats:
+        -
+          value: u32
+          attribute-set: dl-param-value-data-u32-attrs
+          attribute-replace: true
+        -
+          value: string
+          attribute-set: dl-param-value-data-string-attrs
+          attribute-replace: true
+        -
+          value: bool
+          attribute-set: dl-param-value-data-bool-attrs
+          attribute-replace: true
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index 5e48ee0fb8b4..280d50e9079c 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -237,6 +237,9 @@  class SpecAttrSet(SpecElement):
     def items(self):
         return self.attrs.items()
 
+    def keys(self):
+        return self.attrs.keys()
+
 
 class SpecStructMember(SpecElement):
     """Struct member attribute
@@ -318,6 +321,8 @@  class SpecSubMessageFormat(SpecElement):
         value         attribute value to match against type selector
         fixed_header  string, name of fixed header, or None
         attr_set      string, name of attribute set, or None
+        attr_replace  bool, indicates replacement of parent attribute with
+                      attr_set decode, or None
     """
     def __init__(self, family, yaml):
         super().__init__(family, yaml)
@@ -325,6 +330,7 @@  class SpecSubMessageFormat(SpecElement):
         self.value = yaml.get('value')
         self.fixed_header = yaml.get('fixed-header')
         self.attr_set = yaml.get('attribute-set')
+        self.attr_replace = yaml.get('attribute-replace')
 
 
 class SpecOperation(SpecElement):
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index d2ea1571d00c..8591e6bfe40b 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -507,11 +507,16 @@  class YnlFamily(SpecFamily):
                 attr_payload += self._encode_struct(msg_format.fixed_header, value)
             if msg_format.attr_set:
                 if msg_format.attr_set in self.attr_sets:
-                    nl_type |= Netlink.NLA_F_NESTED
-                    sub_attrs = SpaceAttrs(msg_format.attr_set, value, search_attrs)
-                    for subname, subvalue in value.items():
-                        attr_payload += self._add_attr(msg_format.attr_set,
-                                                       subname, subvalue, sub_attrs)
+                    if msg_format.attr_replace:
+                        first_attr_name = list(self.attr_sets[msg_format.attr_set].keys())[0]
+                        return self._add_attr(msg_format.attr_set, first_attr_name,
+                                              value, search_attrs)
+                    else:
+                        nl_type |= Netlink.NLA_F_NESTED
+                        sub_attrs = SpaceAttrs(msg_format.attr_set, value, search_attrs)
+                        for subname, subvalue in value.items():
+                            attr_payload += self._add_attr(msg_format.attr_set,
+                                                           subname, subvalue, sub_attrs)
                 else:
                     raise Exception(f"Unknown attribute-set '{msg_format.attr_set}'")
         else:
@@ -600,8 +605,17 @@  class YnlFamily(SpecFamily):
             offset = self._struct_size(msg_format.fixed_header)
         if msg_format.attr_set:
             if msg_format.attr_set in self.attr_sets:
-                subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set)
+                if msg_format.attr_replace:
+                    attrs = [attr]
+                else:
+                    attrs = NlAttrs(attr.raw, offset);
+                subdict = self._decode(attrs, msg_format.attr_set)
                 decoded.update(subdict)
+                if msg_format.attr_replace:
+                    try:
+                        decoded = decoded[attr_spec.name]
+                    except KeyError:
+                        raise Exception(f"Attribute-set '{attr_space}' does not contain '{attr_spec.name}'")
             else:
                 raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'")
         return decoded