diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/net/ynl/lib/nlspec.py | 6 | ||||
-rw-r--r-- | tools/net/ynl/lib/ynl.c | 6 | ||||
-rw-r--r-- | tools/net/ynl/lib/ynl.h | 17 | ||||
-rw-r--r-- | tools/net/ynl/lib/ynl.py | 14 | ||||
-rwxr-xr-x | tools/net/ynl/ynl-gen-c.py | 44 |
5 files changed, 65 insertions, 22 deletions
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 37bcb4d8b37b..92889298b197 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -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. diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 514e0d69e731..350ddc247450 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -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; diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 9eafa3552c16..87b4dad832f0 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -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 diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 28ac35008e65..3b36553a66cc 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -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': diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 552ba49a444c..a9e8898c9386 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -159,6 +159,15 @@ class Type(SpecAttr): spec = self._attr_policy(policy) cw.p(f"\t[{self.enum_name}] = {spec},") + def _mnl_type(self): + # mnl does not have helpers for signed integer types + # turn signed type into unsigned + # this only makes sense for scalar types + t = self.type + if t[0] == 's': + t = 'u' + t[1:] + return t + def _attr_typol(self): raise Exception(f"Type policy not implemented for class type {self.type}") @@ -326,15 +335,13 @@ 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 - def _mnl_type(self): - t = self.type - # mnl does not have a helper for signed types - if t[0] == 's': - t = 'u' + t[1:] - return t + def mnl_type(self): + return self._mnl_type() def _attr_policy(self, policy): if 'flags-mask' in self.checks or self.is_bitfield: @@ -357,16 +364,16 @@ 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}'] def attr_put(self, ri, var): - self._attr_put_simple(ri, var, self._mnl_type()) + self._attr_put_simple(ri, var, self.mnl_type()) def _attr_get(self, ri, var): - return f"{var}->{self.c_name} = mnl_attr_get_{self._mnl_type()}(attr);", None, None + return f"{var}->{self.c_name} = mnl_attr_get_{self.mnl_type()}(attr);", None, None def _setter_lines(self, ri, member, presence): return [f"{member} = {self.c_name};"] @@ -524,12 +531,8 @@ class TypeMultiAttr(Type): def presence_type(self): return 'count' - def _mnl_type(self): - t = self.type - # mnl does not have a helper for signed types - if t[0] == 's': - t = 'u' + t[1:] - return t + def mnl_type(self): + return self._mnl_type() def _complex_member_type(self, ri): if 'type' not in self.attr or self.attr['type'] == 'nest': @@ -564,7 +567,7 @@ class TypeMultiAttr(Type): def attr_put(self, ri, var): if self.attr['type'] in scalars: - put_type = self._mnl_type() + put_type = self.mnl_type() ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") elif 'type' not in self.attr or self.attr['type'] == 'nest': @@ -1290,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', @@ -1580,11 +1583,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))") ri.cw.p('return MNL_CB_ERROR;') - elif aspec['type'] in scalars: - t = aspec['type'] - if t[0] == 's': - t = 'u' + t[1:] - ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{t}(attr);") + elif aspec.type in scalars: + ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{aspec.mnl_type()}(attr);") else: raise Exception('Nest parsing type not supported yet') ri.cw.p('i++;') |