netlink: specs: add support for auto-sized scalars
authorJakub Kicinski <kuba@kernel.org>
Wed, 18 Oct 2023 21:39:21 +0000 (14:39 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 20 Oct 2023 10:43:35 +0000 (11:43 +0100)
Support uint / sint types in specs and YNL.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/netlink/genetlink-c.yaml
Documentation/netlink/genetlink-legacy.yaml
Documentation/netlink/genetlink.yaml
tools/net/ynl/lib/nlspec.py
tools/net/ynl/lib/ynl.c
tools/net/ynl/lib/ynl.h
tools/net/ynl/lib/ynl.py
tools/net/ynl/ynl-gen-c.py

index dee11c514896d54de8eaf73dbe6cefc0f28402c5..c72c8a428911c92d3138debe7c72f76175ffd860 100644 (file)
@@ -149,7 +149,8 @@ properties:
               name:
                 type: string
               type: &attr-type
-                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
+                enum: [ unused, pad, flag, binary,
+                        uint, sint, u8, u16, u32, u64, s32, s64,
                         string, nest, array-nest, nest-type-value ]
               doc:
                 description: Documentation of the attribute.
index 9194f3e223ef36f44a507591c9eb4e9699ace18b..923de0ff1a9ea9c20e66b8730649260931fcc82b 100644 (file)
@@ -192,7 +192,8 @@ properties:
                 type: string
               type: &attr-type
                 description: The netlink attribute type
-                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
+                enum: [ unused, pad, flag, binary,
+                        uint, sint, u8, u16, u32, u64, s32, s64,
                         string, nest, array-nest, nest-type-value ]
               doc:
                 description: Documentation of the attribute.
index 0a4ae861d011a702c73a26f7f8b7c8b2865a3576..9ceb096b2df2ea250b5618609ba0c5f0afa37f10 100644 (file)
@@ -122,7 +122,8 @@ properties:
               name:
                 type: string
               type: &attr-type
-                enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
+                enum: [ unused, pad, flag, binary,
+                        uint, sint, u8, u16, u32, u64, s32, s64,
                         string, nest, array-nest, nest-type-value ]
               doc:
                 description: Documentation of the attribute.
index 37bcb4d8b37b0b37170ff5a316cf94df7434a84e..92889298b197e514b59e976c7ca66fa7255fd687 100644 (file)
@@ -149,6 +149,7 @@ class SpecAttr(SpecElement):
     Represents a single attribute type within an attr space.
 
     Attributes:
+        type          string, attribute type
         value         numerical ID when serialized
         attr_set      Attribute Set containing this attr
         is_multi      bool, attr may repeat multiple times
@@ -157,10 +158,13 @@ class SpecAttr(SpecElement):
         len           integer, optional byte length of binary types
         display_hint  string, hint to help choose format specifier
                       when displaying the value
+
+        is_auto_scalar bool, attr is a variable-size scalar
     """
     def __init__(self, family, attr_set, yaml, value):
         super().__init__(family, yaml)
 
+        self.type = yaml['type']
         self.value = value
         self.attr_set = attr_set
         self.is_multi = yaml.get('multi-attr', False)
@@ -170,6 +174,8 @@ class SpecAttr(SpecElement):
         self.len = yaml.get('len')
         self.display_hint = yaml.get('display-hint')
 
+        self.is_auto_scalar = self.type == "sint" or self.type == "uint"
+
 
 class SpecAttrSet(SpecElement):
     """ Netlink Attribute Set class.
index 514e0d69e73106a867270eebb41948128a1befe3..350ddc247450cac9681a69e1cf9f8d11e8d274b4 100644 (file)
@@ -352,6 +352,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr)
                yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
                     "Invalid attribute (u64 %s)", policy->name);
                return -1;
+       case YNL_PT_UINT:
+               if (len == sizeof(__u32) || len == sizeof(__u64))
+                       break;
+               yerr(yarg->ys, YNL_ERROR_ATTR_INVALID,
+                    "Invalid attribute (uint %s)", policy->name);
+               return -1;
        case YNL_PT_FLAG:
                /* Let flags grow into real attrs, why not.. */
                break;
index 9eafa3552c16796883df85ea8148f09512b6d3b6..87b4dad832f07c74dbf6140e95b00e58c6ddebfb 100644 (file)
@@ -133,6 +133,7 @@ enum ynl_policy_type {
        YNL_PT_U16,
        YNL_PT_U32,
        YNL_PT_U64,
+       YNL_PT_UINT,
        YNL_PT_NUL_STR,
 };
 
@@ -234,4 +235,20 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh,
 void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd);
 int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
 
+#ifndef MNL_HAS_AUTO_SCALARS
+static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
+{
+       if (mnl_attr_get_len(attr) == 4)
+               return mnl_attr_get_u32(attr);
+       return mnl_attr_get_u64(attr);
+}
+
+static inline void
+mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
+{
+       if ((uint32_t)data == (uint64_t)data)
+               return mnl_attr_put_u32(nlh, type, data);
+       return mnl_attr_put_u64(nlh, type, data);
+}
+#endif
 #endif
index 28ac35008e655e9efbe7242f0d204054b4ebce78..3b36553a66cc08f1bf4b06b8507f6e849b17bcab 100644 (file)
@@ -130,6 +130,13 @@ class NlAttr:
         format = self.get_format(attr_type, byte_order)
         return format.unpack(self.raw)[0]
 
+    def as_auto_scalar(self, attr_type, byte_order=None):
+        if len(self.raw) != 4 and len(self.raw) != 8:
+            raise Exception(f"Auto-scalar len payload be 4 or 8 bytes, got {len(self.raw)}")
+        real_type = attr_type[0] + str(len(self.raw) * 8)
+        format = self.get_format(real_type, byte_order)
+        return format.unpack(self.raw)[0]
+
     def as_strz(self):
         return self.raw.decode('ascii')[:-1]
 
@@ -463,6 +470,11 @@ class YnlFamily(SpecFamily):
                 attr_payload = bytes.fromhex(value)
             else:
                 raise Exception(f'Unknown type for binary attribute, value: {value}')
+        elif attr.is_auto_scalar:
+            scalar = int(value)
+            real_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64')
+            format = NlAttr.get_format(real_type, attr.byte_order)
+            attr_payload = format.pack(int(value))
         elif attr['type'] in NlAttr.type_formats:
             format = NlAttr.get_format(attr['type'], attr.byte_order)
             attr_payload = format.pack(int(value))
@@ -529,6 +541,8 @@ class YnlFamily(SpecFamily):
                 decoded = self._decode_binary(attr, attr_spec)
             elif attr_spec["type"] == 'flag':
                 decoded = True
+            elif attr_spec.is_auto_scalar:
+                decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order)
             elif attr_spec["type"] in NlAttr.type_formats:
                 decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order)
             elif attr_spec["type"] == 'array-nest':
index 6f4c538bda9ada2f11349c90ec015218ac57accb..a9e8898c93863ff7460efc8567698607d2568a5a 100755 (executable)
@@ -335,6 +335,8 @@ class TypeScalar(Type):
         maybe_enum = not self.is_bitfield and 'enum' in self.attr
         if maybe_enum and self.family.consts[self.attr['enum']].enum_name:
             self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}"
+        elif self.is_auto_scalar:
+            self.type_name = '__' + self.type[0] + '64'
         else:
             self.type_name = '__' + self.type
 
@@ -362,7 +364,7 @@ class TypeScalar(Type):
         return super()._attr_policy(policy)
 
     def _attr_typol(self):
-        return f'.type = YNL_PT_U{self.type[1:]}, '
+        return f'.type = YNL_PT_U{c_upper(self.type[1:])}, '
 
     def arg_member(self, ri):
         return [f'{self.type_name} {self.c_name}{self.byte_order_comment}']
@@ -1291,7 +1293,7 @@ class CodeWriter:
             self.p(line)
 
 
-scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64'}
+scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'}
 
 direction_to_suffix = {
     'reply': '_rsp',