netdev.vger.kernel.org archive mirror
 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,
	dcaratti@redhat.com, Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH net-next 3/3] tools: ynl-gen: support limit names
Date: Wed, 18 Oct 2023 09:39:17 -0700	[thread overview]
Message-ID: <20231018163917.2514503-4-kuba@kernel.org> (raw)
In-Reply-To: <20231018163917.2514503-1-kuba@kernel.org>

Support the use of symbolic names like s8-min or u32-max in checks
to make writing specs less painful.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/genetlink-c.yaml      |  9 ++++-
 Documentation/netlink/genetlink-legacy.yaml |  9 ++++-
 Documentation/netlink/genetlink.yaml        |  9 ++++-
 tools/net/ynl/ynl-gen-c.py                  | 45 ++++++++++++++++-----
 4 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml
index 75af0b51f3d7..dee11c514896 100644
--- a/Documentation/netlink/genetlink-c.yaml
+++ b/Documentation/netlink/genetlink-c.yaml
@@ -13,6 +13,11 @@ $schema: https://json-schema.org/draft-07/schema
     type: [ string, integer ]
     pattern: ^[0-9A-Za-z_]+( - 1)?$
     minimum: 0
+  len-or-limit:
+    # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
+    type: [ string, integer ]
+    pattern: ^[su](8|16|32|64)-(min|max)$
+    minimum: 0
 
 # Schema for specs
 title: Protocol
@@ -183,10 +188,10 @@ additionalProperties: False
                     type: string
                   min:
                     description: Min value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   max:
                     description: Max value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   min-len:
                     description: Min length for a binary attribute.
                     $ref: '#/$defs/len-or-define'
diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml
index c0f17a8bfe0d..9194f3e223ef 100644
--- a/Documentation/netlink/genetlink-legacy.yaml
+++ b/Documentation/netlink/genetlink-legacy.yaml
@@ -13,6 +13,11 @@ $schema: https://json-schema.org/draft-07/schema
     type: [ string, integer ]
     pattern: ^[0-9A-Za-z_]+( - 1)?$
     minimum: 0
+  len-or-limit:
+    # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
+    type: [ string, integer ]
+    pattern: ^[su](8|16|32|64)-(min|max)$
+    minimum: 0
 
 # Schema for specs
 title: Protocol
@@ -226,10 +231,10 @@ additionalProperties: False
                     type: string
                   min:
                     description: Min value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   max:
                     description: Max value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   min-len:
                     description: Min length for a binary attribute.
                     $ref: '#/$defs/len-or-define'
diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml
index 4fd56e3b1553..0a4ae861d011 100644
--- a/Documentation/netlink/genetlink.yaml
+++ b/Documentation/netlink/genetlink.yaml
@@ -13,6 +13,11 @@ $schema: https://json-schema.org/draft-07/schema
     type: [ string, integer ]
     pattern: ^[0-9A-Za-z_]+( - 1)?$
     minimum: 0
+  len-or-limit:
+    # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
+    type: [ string, integer ]
+    pattern: ^[su](8|16|32|64)-(min|max)$
+    minimum: 0
 
 # Schema for specs
 title: Protocol
@@ -156,10 +161,10 @@ additionalProperties: False
                     type: string
                   min:
                     description: Min value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   max:
                     description: Max value for an integer attribute.
-                    type: integer
+                    $ref: '#/$defs/len-or-limit'
                   min-len:
                     description: Min length for a binary attribute.
                     $ref: '#/$defs/len-or-define'
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 9d008346dd50..552ba49a444c 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -20,6 +20,21 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
     return name.lower().replace('-', '_')
 
 
+def limit_to_number(name):
+    """
+    Turn a string limit like u32-max or s64-min into its numerical value
+    """
+    if name[0] == 'u' and name.endswith('-min'):
+        return 0
+    width = int(name[1:-4])
+    if name[0] == 's':
+        width -= 1
+    value = (1 << width) - 1
+    if name[0] == 's' and name.endswith('-min'):
+        value = -value - 1
+    return value
+
+
 class BaseNlLib:
     def get_family_id(self):
         return 'ys->family_id'
@@ -68,6 +83,14 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
         self.enum_name = None
         delattr(self, "enum_name")
 
+    def get_limit(self, limit, default=None):
+        value = self.checks.get(limit, default)
+        if value is None:
+            return value
+        if not isinstance(value, int):
+            value = limit_to_number(value)
+        return value
+
     def resolve(self):
         if 'name-prefix' in self.attr:
             enum_name = f"{self.attr['name-prefix']}{self.name}"
@@ -273,12 +296,12 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
                 self.checks['max'] = high
 
         if 'min' in self.checks and 'max' in self.checks:
-            if self.checks['min'] > self.checks['max']:
-                raise Exception(f'Invalid limit for "{self.name}" min: {self.checks["min"]} max: {self.checks["max"]}')
+            if self.get_limit('min') > self.get_limit('max'):
+                raise Exception(f'Invalid limit for "{self.name}" min: {self.get_limit("min")} max: {self.get_limit("max")}')
             self.checks['range'] = True
 
-        low = min(self.checks.get('min', 0), self.checks.get('max', 0))
-        high = max(self.checks.get('min', 0), self.checks.get('max', 0))
+        low = min(self.get_limit('min', 0), self.get_limit('max', 0))
+        high = max(self.get_limit('min', 0), self.get_limit('max', 0))
         if low < 0 and self.type[0] == 'u':
             raise Exception(f'Invalid limit for "{self.name}" negative limit for unsigned type')
         if low < -32768 or high > 32767:
@@ -326,11 +349,11 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
         elif 'full-range' in self.checks:
             return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)"
         elif 'range' in self.checks:
-            return f"NLA_POLICY_RANGE({policy}, {self.checks['min']}, {self.checks['max']})"
+            return f"NLA_POLICY_RANGE({policy}, {self.get_limit('min')}, {self.get_limit('max')})"
         elif 'min' in self.checks:
-            return f"NLA_POLICY_MIN({policy}, {self.checks['min']})"
+            return f"NLA_POLICY_MIN({policy}, {self.get_limit('min')})"
         elif 'max' in self.checks:
-            return f"NLA_POLICY_MAX({policy}, {self.checks['max']})"
+            return f"NLA_POLICY_MAX({policy}, {self.get_limit('max')})"
         return super()._attr_policy(policy)
 
     def _attr_typol(self):
@@ -382,7 +405,7 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
     def _attr_policy(self, policy):
         mem = '{ .type = ' + policy
         if 'max-len' in self.checks:
-            mem += ', .len = ' + str(self.checks['max-len'])
+            mem += ', .len = ' + str(self.get_limit('max-len'))
         mem += ', }'
         return mem
 
@@ -431,7 +454,7 @@ from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, S
     def _attr_policy(self, policy):
         mem = '{ '
         if len(self.checks) == 1 and 'min-len' in self.checks:
-            mem += '.len = ' + str(self.checks['min-len'])
+            mem += '.len = ' + str(self.get_limit('min-len'))
         elif len(self.checks) == 0:
             mem += '.type = NLA_BINARY'
         else:
@@ -1982,9 +2005,9 @@ _C_KW = {
             cw.block_start(line=f'struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =')
             members = []
             if 'min' in attr.checks:
-                members.append(('min', attr.checks['min']))
+                members.append(('min', attr.get_limit('min')))
             if 'max' in attr.checks:
-                members.append(('max', attr.checks['max']))
+                members.append(('max', attr.get_limit('max')))
             cw.write_struct_init(members)
             cw.block_end(line=';')
             cw.nl()
-- 
2.41.0


  parent reply	other threads:[~2023-10-18 16:39 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-18 16:39 [PATCH net-next 0/3] tools: ynl-gen: support full range of min/max checks Jakub Kicinski
2023-10-18 16:39 ` [PATCH net-next 1/3] tools: ynl-gen: track attribute use Jakub Kicinski
2023-10-18 16:39 ` [PATCH net-next 2/3] tools: ynl-gen: support full range of min/max checks for integer values Jakub Kicinski
2023-10-18 16:39 ` Jakub Kicinski [this message]
2023-10-19 23:00 ` [PATCH net-next 0/3] tools: ynl-gen: support full range of min/max checks 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=20231018163917.2514503-4-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=davem@davemloft.net \
    --cc=dcaratti@redhat.com \
    --cc=edumazet@google.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /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 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).