netlink: specs: support conditional operations
authorJakub Kicinski <kuba@kernel.org>
Wed, 25 Oct 2023 16:22:53 +0000 (09:22 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 27 Oct 2023 02:42:15 +0000 (19:42 -0700)
Page pool code is compiled conditionally, but the operations
are part of the shared netlink family. We can handle this
by reporting empty list of pools or -EOPNOTSUPP / -ENOSYS
but the cleanest way seems to be removing the ops completely
at compilation time. That way user can see that the page
pool ops are not present using genetlink introspection.
Same way they'd check if the kernel is "new enough" to
support the ops.

Extend the specs with the ability to specify the config
condition under which op (and its policies, etc.) should
be hidden.

Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20231025162253.133159-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/netlink/genetlink-c.yaml
Documentation/netlink/genetlink-legacy.yaml
Documentation/netlink/genetlink.yaml
tools/net/ynl/ynl-gen-c.py

index 7ef2496..9d13bbb 100644 (file)
@@ -295,6 +295,11 @@ properties:
               type: array
               items:
                 enum: [ strict, dump, dump-strict ]
+            config-cond:
+              description: |
+                Name of the kernel config option gating the presence of
+                the operation, without the 'CONFIG_' prefix.
+              type: string
             do: &subop-type
               description: Main command handler.
               type: object
index cd5ebe3..0daf404 100644 (file)
@@ -346,6 +346,11 @@ properties:
               type: array
               items:
                 enum: [ strict, dump, dump-strict ]
+            config-cond:
+              description: |
+                Name of the kernel config option gating the presence of
+                the operation, without the 'CONFIG_' prefix.
+              type: string
             # Start genetlink-legacy
             fixed-header: *fixed-header
             # End genetlink-legacy
index 501ed2e..3283bf4 100644 (file)
@@ -264,6 +264,11 @@ properties:
               type: array
               items:
                 enum: [ strict, dump, dump-strict ]
+            config-cond:
+              description: |
+                Name of the kernel config option gating the presence of
+                the operation, without the 'CONFIG_' prefix.
+              type: string
             do: &subop-type
               description: Main command handler.
               type: object
index 31fd96f..1c7474a 100755 (executable)
@@ -1162,6 +1162,7 @@ class CodeWriter:
         self._block_end = False
         self._silent_block = False
         self._ind = 0
+        self._ifdef_block = None
         if out_file is None:
             self._out = os.sys.stdout
         else:
@@ -1202,6 +1203,8 @@ class CodeWriter:
         if self._silent_block:
             ind += 1
         self._silent_block = line.endswith(')') and CodeWriter._is_cond(line)
+        if line[0] == '#':
+            ind = 0
         if add_ind:
             ind += add_ind
         self._out.write('\t' * ind + line + '\n')
@@ -1328,6 +1331,19 @@ class CodeWriter:
             line += '= ' + str(one[1]) + ','
             self.p(line)
 
+    def ifdef_block(self, config):
+        config_option = None
+        if config:
+            config_option = 'CONFIG_' + c_upper(config)
+        if self._ifdef_block == config_option:
+            return
+
+        if self._ifdef_block:
+            self.p('#endif /* ' + self._ifdef_block + ' */')
+        if config_option:
+            self.p('#ifdef ' + config_option)
+        self._ifdef_block = config_option
+
 
 scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'}
 
@@ -2006,10 +2022,13 @@ def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
 
 
 def print_req_policy(cw, struct, ri=None):
+    if ri and ri.op:
+        cw.ifdef_block(ri.op.get('config-cond', None))
     print_req_policy_fwd(cw, struct, ri=ri, terminate=False)
     for _, arg in struct.member_list():
         arg.attr_policy(cw)
     cw.p("};")
+    cw.ifdef_block(None)
     cw.nl()
 
 
@@ -2127,6 +2146,7 @@ def print_kernel_op_table(family, cw):
             if op.is_async:
                 continue
 
+            cw.ifdef_block(op.get('config-cond', None))
             cw.block_start()
             members = [('cmd', op.enum_name)]
             if 'dont-validate' in op:
@@ -2157,6 +2177,7 @@ def print_kernel_op_table(family, cw):
                 if op.is_async or op_mode not in op:
                     continue
 
+                cw.ifdef_block(op.get('config-cond', None))
                 cw.block_start()
                 members = [('cmd', op.enum_name)]
                 if 'dont-validate' in op:
@@ -2192,6 +2213,7 @@ def print_kernel_op_table(family, cw):
                 members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags])))
                 cw.write_struct_init(members)
                 cw.block_end(line=',')
+    cw.ifdef_block(None)
 
     cw.block_end(line=';')
     cw.nl()