tools: ynl-gen: mutli-attr: support binary types with struct

Binary types with struct are fixed size, relatively easy to
handle for multi attr. Declare the member as a pointer.
Count the members, allocate an array, copy in the data.
Allow the netlink attr to be smaller or larger than our view
of the struct in case the build headers are newer or older
than the running kernel.

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Link: https://patch.msgid.link/20250429154704.2613851-9-kuba@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Jakub Kicinski 2025-04-29 08:47:00 -07:00 committed by Paolo Abeni
parent 0ea8cf56cc
commit 3456084d63

View file

@ -640,6 +640,8 @@ class TypeMultiAttr(Type):
def _complex_member_type(self, ri):
if 'type' not in self.attr or self.attr['type'] == 'nest':
return self.nested_struct_type
elif self.attr['type'] == 'binary' and 'struct' in self.attr:
return None # use arg_member()
elif self.attr['type'] == 'string':
return 'struct ynl_string *'
elif self.attr['type'] in scalars:
@ -648,6 +650,12 @@ class TypeMultiAttr(Type):
else:
raise Exception(f"Sub-type {self.attr['type']} not supported yet")
def arg_member(self, ri):
if self.type == 'binary' and 'struct' in self.attr:
return [f'struct {c_lower(self.attr["struct"])} *{self.c_name}',
f'unsigned int n_{self.c_name}']
return super().arg_member(ri)
def free_needs_iter(self):
return self.attr['type'] in {'nest', 'string'}
@ -655,6 +663,8 @@ class TypeMultiAttr(Type):
lines = []
if self.attr['type'] in scalars:
lines += [f"free({var}->{ref}{self.c_name});"]
elif self.attr['type'] == 'binary' and 'struct' in self.attr:
lines += [f"free({var}->{ref}{self.c_name});"]
elif self.attr['type'] == 'string':
lines += [
f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)",
@ -685,6 +695,9 @@ class TypeMultiAttr(Type):
put_type = self.type
ri.cw.p(f"for (i = 0; i < {var}->n_{self.c_name}; i++)")
ri.cw.p(f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
elif self.attr['type'] == 'binary' and 'struct' in self.attr:
ri.cw.p(f"for (i = 0; i < {var}->n_{self.c_name}; i++)")
ri.cw.p(f"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}[i], sizeof(struct {c_lower(self.attr['struct'])}));")
elif self.attr['type'] == 'string':
ri.cw.p(f"for (i = 0; i < {var}->n_{self.c_name}; i++)")
ri.cw.p(f"ynl_attr_put_str(nlh, {self.enum_name}, {var}->{self.c_name}[i]->str);")
@ -1847,6 +1860,12 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.p('return YNL_PARSE_CB_ERROR;')
elif aspec.type in scalars:
ri.cw.p(f"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);")
elif aspec.type == 'binary' and 'struct' in aspec:
ri.cw.p('size_t len = ynl_attr_data_len(attr);')
ri.cw.nl()
ri.cw.p(f'if (len > sizeof(dst->{aspec.c_name}[0]))')
ri.cw.p(f'len = sizeof(dst->{aspec.c_name}[0]);')
ri.cw.p(f"memcpy(&dst->{aspec.c_name}[i], ynl_attr_data(attr), len);")
elif aspec.type == 'string':
ri.cw.p('unsigned int len;')
ri.cw.nl()