All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com,
	andrew+netdev@lunn.ch, horms@kernel.org, donald.hunter@gmail.com,
	jacob.e.keller@intel.com, sdf@fomichev.me, jstancek@redhat.com,
	kory.maincent@bootlin.com, Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH net-next v2 06/12] tools: ynl-gen: support passing selector to a nest
Date: Tue, 20 May 2025 09:19:10 -0700	[thread overview]
Message-ID: <20250520161916.413298-7-kuba@kernel.org> (raw)
In-Reply-To: <20250520161916.413298-1-kuba@kernel.org>

In rtnetlink all submessages had the selector at the same level
of nesting as the submessage. We could refer to the relevant
attribute from the current struct. In TC, stats are one level
of nesting deeper than "kind". Teach the code-gen about structs
which need to be passed a selector by the caller for parsing.

Because structs are "topologically sorted" one pass of propagating
the selectors down is enough.

For generating netlink message we depend on the presence bits
so no selector passing needed there.

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/pyynl/ynl_gen_c.py | 65 +++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 5 deletions(-)

diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py
index 1f8cc34ab3f0..c1508d8c1e7a 100755
--- a/tools/net/ynl/pyynl/ynl_gen_c.py
+++ b/tools/net/ynl/pyynl/ynl_gen_c.py
@@ -685,7 +685,11 @@ from lib import SpecSubMessage, SpecSubMessageFormat
                             f"{self.enum_name}, {at}{var}->{self.c_name})")
 
     def _attr_get(self, ri, var):
-        get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))",
+        pns = self.family.pure_nested_structs[self.nested_attrs]
+        args = ["&parg", "attr"]
+        for sel in pns.external_selectors():
+            args.append(f'{var}->{sel.name}')
+        get_lines = [f"if ({self.nested_render_name}_parse({', '.join(args)}))",
                      "return YNL_PARSE_CB_ERROR;"]
         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
                       f"parg.data = &{var}->{self.c_name};"]
@@ -890,15 +894,24 @@ from lib import SpecSubMessage, SpecSubMessageFormat
 
     def _attr_typol(self):
         typol = f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
-        typol += f'.is_submsg = 1, .selector_type = {self.attr_set[self["selector"]].value} '
+        typol += '.is_submsg = 1, '
+        # Reverse-parsing of the policy (ynl_err_walk() in ynl.c) does not
+        # support external selectors. No family uses sub-messages with external
+        # selector for requests so this is fine for now.
+        if not self.selector.is_external():
+            typol += f'.selector_type = {self.attr_set[self["selector"]].value} '
         return typol
 
     def _attr_get(self, ri, var):
         sel = c_lower(self['selector'])
-        get_lines = [f'if (!{var}->{sel})',
+        if self.selector.is_external():
+            sel_var = f"_sel_{sel}"
+        else:
+            sel_var = f"{var}->{sel}"
+        get_lines = [f'if (!{sel_var})',
                      f'return ynl_submsg_failed(yarg, "%s", "%s");' %
                         (self.name, self['selector']),
-                    f"if ({self.nested_render_name}_parse(&parg, {var}->{sel}, attr))",
+                    f"if ({self.nested_render_name}_parse(&parg, {sel_var}, attr))",
                      "return YNL_PARSE_CB_ERROR;"]
         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
                       f"parg.data = &{var}->{self.c_name};"]
@@ -914,7 +927,15 @@ from lib import SpecSubMessage, SpecSubMessageFormat
             self.attr.is_selector = True
             self._external = False
         else:
-            raise Exception("Passing selectors from external nests not supported")
+            # The selector will need to get passed down thru the structs
+            self.attr = None
+            self._external = True
+
+    def set_attr(self, attr):
+        self.attr = attr
+
+    def is_external(self):
+        return self._external
 
 
 class Struct:
@@ -976,6 +997,13 @@ from lib import SpecSubMessage, SpecSubMessageFormat
             raise Exception("Inheriting different members not supported")
         self.inherited = [c_lower(x) for x in sorted(self._inherited)]
 
+    def external_selectors(self):
+        sels = []
+        for name, attr in self.attr_list:
+            if isinstance(attr, TypeSubMessage) and attr.selector.is_external():
+                sels.append(attr.selector)
+        return sels
+
     def free_needs_iter(self):
         for _, attr in self.attr_list:
             if attr.free_needs_iter():
@@ -1222,6 +1250,7 @@ from lib import SpecSubMessage, SpecSubMessageFormat
         self._load_root_sets()
         self._load_nested_sets()
         self._load_attr_use()
+        self._load_selector_passing()
         self._load_hooks()
 
         self.kernel_policy = self.yaml.get('kernel-policy', 'split')
@@ -1436,6 +1465,30 @@ from lib import SpecSubMessage, SpecSubMessageFormat
                 if attr in rs_members['reply']:
                     spec.set_reply()
 
+    def _load_selector_passing(self):
+        def all_structs():
+            for k, v in reversed(self.pure_nested_structs.items()):
+                yield k, v
+            for k, _ in self.root_sets.items():
+                yield k, None  # we don't have a struct, but it must be terminal
+
+        for attr_set, struct in all_structs():
+            for _, spec in self.attr_sets[attr_set].items():
+                if 'nested-attributes' in spec:
+                    child_name = spec['nested-attributes']
+                elif 'sub-message' in spec:
+                    child_name = spec.sub_message
+                else:
+                    continue
+
+                child = self.pure_nested_structs.get(child_name)
+                for selector in child.external_selectors():
+                    if selector.name in self.attr_sets[attr_set]:
+                        sel_attr = self.attr_sets[attr_set][selector.name]
+                        selector.set_attr(sel_attr)
+                    else:
+                        raise Exception("Passing selector thru more than one layer not supported")
+
     def _load_global_policy(self):
         global_set = set()
         attr_set_name = None
@@ -2183,6 +2236,8 @@ _C_KW = {
 def parse_rsp_nested_prototype(ri, struct, suffix=';'):
     func_args = ['struct ynl_parse_arg *yarg',
                  'const struct nlattr *nested']
+    for sel in struct.external_selectors():
+        func_args.append('const char *_sel_' + sel.name)
     if struct.submsg:
         func_args.insert(1, 'const char *sel')
     for arg in struct.inherited:
-- 
2.49.0


  parent reply	other threads:[~2025-05-20 16:19 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-20 16:19 [PATCH net-next v2 00/12] tools: ynl-gen: add support for "inherited" selector and therefore TC Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 01/12] tools: ynl-gen: add makefile deps for neigh Jakub Kicinski
2025-05-20 17:15   ` Kory Maincent
2025-05-20 16:19 ` [PATCH net-next v2 02/12] netlink: specs: tc: remove duplicate nests Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 03/12] netlink: specs: tc: use tc-gact instead of tc-gen as struct name Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 04/12] netlink: specs: tc: add C naming info Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 05/12] netlink: specs: tc: drop the family name prefix from attrs Jakub Kicinski
2025-05-20 16:19 ` Jakub Kicinski [this message]
2025-05-20 16:19 ` [PATCH net-next v2 07/12] tools: ynl-gen: move fixed header info from RenderInfo to Struct Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 08/12] tools: ynl-gen: support local attrs in _multi_parse Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 09/12] tools: ynl-gen: support weird sub-message formats Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 10/12] tools: ynl: enable codegen for TC Jakub Kicinski
2025-05-20 16:34   ` Kory Maincent
2025-05-20 16:50     ` Jakub Kicinski
2025-05-20 17:36       ` Kory Maincent
2025-05-21 20:31         ` Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 11/12] netlink: specs: tc: add qdisc dump to TC spec Jakub Kicinski
2025-05-20 16:19 ` [PATCH net-next v2 12/12] tools: ynl: add a sample for TC Jakub Kicinski
2025-05-21 22:50 ` [PATCH net-next v2 00/12] tools: ynl-gen: add support for "inherited" selector and therefore TC patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250520161916.413298-7-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=jacob.e.keller@intel.com \
    --cc=jstancek@redhat.com \
    --cc=kory.maincent@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sdf@fomichev.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.