Commit 3456084d authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Paolo Abeni
Browse files

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: default avatarDonald Hunter <donald.hunter@gmail.com>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Link: https://patch.msgid.link/20250429154704.2613851-9-kuba@kernel.org


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 0ea8cf56
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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()