[PATCH net-next v2 3/8] ynl: support directional specs in ynl-gen-c.py

Stanislav Fomichev posted 8 patches 6 days, 21 hours ago
[PATCH net-next v2 3/8] ynl: support directional specs in ynl-gen-c.py
Posted by Stanislav Fomichev 6 days, 21 hours ago
The intent is to generate ethtool uapi headers. For now, some of the
things are hard-coded:
- <FAMILY>_MSG_{USER,KERNEL}_MAX
- the split between USER and KERNEL messages

Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
 tools/net/ynl/ynl-gen-c.py | 118 +++++++++++++++++++++++++++----------
 1 file changed, 87 insertions(+), 31 deletions(-)

diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 8ba252973c2d..e5ac6f89b78a 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -2419,6 +2419,87 @@ _C_KW = {
     cw.block_start(line=start_line)
 
 
+def render_uapi_unified(family, cw, max_by_define, separate_ntf):
+    max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
+    cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
+    max_value = f"({cnt_name} - 1)"
+
+    uapi_enum_start(family, cw, family['operations'], 'enum-name')
+    val = 0
+    for op in family.msgs.values():
+        if separate_ntf and ('notify' in op or 'event' in op):
+            continue
+
+        suffix = ','
+        if op.value != val:
+            suffix = f" = {op.value},"
+            val = op.value
+        cw.p(op.enum_name + suffix)
+        val += 1
+    cw.nl()
+    cw.p(cnt_name + ('' if max_by_define else ','))
+    if not max_by_define:
+        cw.p(f"{max_name} = {max_value}")
+    cw.block_end(line=';')
+    if max_by_define:
+        cw.p(f"#define {max_name} {max_value}")
+    cw.nl()
+
+
+def render_uapi_directional(family, cw, max_by_define):
+    max_name = f"{family.op_prefix}USER_MAX"
+    cnt_name = f"__{family.op_prefix}USER_CNT"
+    max_value = f"({cnt_name} - 1)"
+
+    cw.block_start(line='enum')
+    cw.p(c_upper(f'{family.name}_MSG_USER_NONE = 0,'))
+    val = 0
+    for op in family.msgs.values():
+        if 'do' in op and 'event' not in op:
+            suffix = ','
+            if op.value and op.value != val:
+                suffix = f" = {op.value},"
+                val = op.value
+            cw.p(op.enum_name + suffix)
+            val += 1
+    cw.nl()
+    cw.p(cnt_name + ('' if max_by_define else ','))
+    if not max_by_define:
+        cw.p(f"{max_name} = {max_value}")
+    cw.block_end(line=';')
+    if max_by_define:
+        cw.p(f"#define {max_name} {max_value}")
+    cw.nl()
+
+    max_name = f"{family.op_prefix}KERNEL_MAX"
+    cnt_name = f"__{family.op_prefix}KERNEL_CNT"
+    max_value = f"({cnt_name} - 1)"
+
+    cw.block_start(line='enum')
+    cw.p(c_upper(f'{family.name}_MSG_KERNEL_NONE = 0,'))
+    val = 0
+    for op in family.msgs.values():
+        if ('do' in op and 'reply' in op['do']) or 'notify' in op or 'event' in op:
+            enum_name = op.enum_name
+            if 'event' not in op and 'notify' not in op:
+                enum_name = f'{enum_name}_REPLY'
+
+            suffix = ','
+            if op.value and op.value != val:
+                suffix = f" = {op.value},"
+                val = op.value
+            cw.p(enum_name + suffix)
+            val += 1
+    cw.nl()
+    cw.p(cnt_name + ('' if max_by_define else ','))
+    if not max_by_define:
+        cw.p(f"{max_name} = {max_value}")
+    cw.block_end(line=';')
+    if max_by_define:
+        cw.p(f"#define {max_name} {max_value}")
+    cw.nl()
+
+
 def render_uapi(family, cw):
     hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
     cw.p('#ifndef ' + hdr_prot)
@@ -2522,30 +2603,12 @@ _C_KW = {
     # Commands
     separate_ntf = 'async-prefix' in family['operations']
 
-    max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
-    cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
-    max_value = f"({cnt_name} - 1)"
-
-    uapi_enum_start(family, cw, family['operations'], 'enum-name')
-    val = 0
-    for op in family.msgs.values():
-        if separate_ntf and ('notify' in op or 'event' in op):
-            continue
-
-        suffix = ','
-        if op.value != val:
-            suffix = f" = {op.value},"
-            val = op.value
-        cw.p(op.enum_name + suffix)
-        val += 1
-    cw.nl()
-    cw.p(cnt_name + ('' if max_by_define else ','))
-    if not max_by_define:
-        cw.p(f"{max_name} = {max_value}")
-    cw.block_end(line=';')
-    if max_by_define:
-        cw.p(f"#define {max_name} {max_value}")
-    cw.nl()
+    if family.msg_id_model == 'unified':
+        render_uapi_unified(family, cw, max_by_define, separate_ntf)
+    elif family.msg_id_model == 'directional':
+        render_uapi_directional(family, cw, max_by_define)
+    else:
+        raise Exception(f'Unsupported enum-model {family.msg_id_model}')
 
     if separate_ntf:
         uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
@@ -2669,13 +2732,6 @@ _C_KW = {
         os.sys.exit(1)
         return
 
-    supported_models = ['unified']
-    if args.mode in ['user', 'kernel']:
-        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(), args.out_file, overwrite=(not args.cmp_out))
 
     _, spec_kernel = find_kernel_root(args.spec)
-- 
2.47.0
Re: [PATCH net-next v2 3/8] ynl: support directional specs in ynl-gen-c.py
Posted by Jakub Kicinski 6 days, 19 hours ago
On Fri, 15 Nov 2024 11:36:41 -0800 Stanislav Fomichev wrote:
> The intent is to generate ethtool uapi headers. For now, some of the
> things are hard-coded:
> - <FAMILY>_MSG_{USER,KERNEL}_MAX
> - the split between USER and KERNEL messages

Maybe toss in a TODO: comment or some such on top of
render_uapi_directional(), to make it clear that the code needs 
more love before it can be reasonably reused.

nit: possibly split into two commits for ease of review

> +    if family.msg_id_model == 'unified':
> +        render_uapi_unified(family, cw, max_by_define, separate_ntf)
> +    elif family.msg_id_model == 'directional':
> +        render_uapi_directional(family, cw, max_by_define)
> +    else:
> +        raise Exception(f'Unsupported enum-model {family.msg_id_model}')

You gotta say "Message enum-model", enum-mode alone sounds like we're
doing something with how enums are processed, rather than message IDs.
Re: [PATCH net-next v2 3/8] ynl: support directional specs in ynl-gen-c.py
Posted by Stanislav Fomichev 6 days, 18 hours ago
On 11/15, Jakub Kicinski wrote:
> On Fri, 15 Nov 2024 11:36:41 -0800 Stanislav Fomichev wrote:
> > The intent is to generate ethtool uapi headers. For now, some of the
> > things are hard-coded:
> > - <FAMILY>_MSG_{USER,KERNEL}_MAX
> > - the split between USER and KERNEL messages
> 
> Maybe toss in a TODO: comment or some such on top of
> render_uapi_directional(), to make it clear that the code needs 
> more love before it can be reasonably reused.
> 
> nit: possibly split into two commits for ease of review
> 
> > +    if family.msg_id_model == 'unified':
> > +        render_uapi_unified(family, cw, max_by_define, separate_ntf)
> > +    elif family.msg_id_model == 'directional':
> > +        render_uapi_directional(family, cw, max_by_define)
> > +    else:
> > +        raise Exception(f'Unsupported enum-model {family.msg_id_model}')
> 
> You gotta say "Message enum-model", enum-mode alone sounds like we're
> doing something with how enums are processed, rather than message IDs.

"Unsupported message enum-model {...}" ? Will do.
Re: [PATCH net-next v2 3/8] ynl: support directional specs in ynl-gen-c.py
Posted by Jakub Kicinski 6 days, 18 hours ago
On Fri, 15 Nov 2024 13:55:36 -0800 Stanislav Fomichev wrote:
> > You gotta say "Message enum-model", enum-mode alone sounds like we're
> > doing something with how enums are processed, rather than message IDs.  
> 
> "Unsupported message enum-model {...}" ? Will do.

SG