Make it possible for struct definitions to reference other struct definitions ofr binary members. For example, the tbf qdisc uses this struct definition for its parms attribute: - name: tc-tbf-qopt type: struct members: - name: rate type: binary struct: tc-ratespec - name: peakrate type: binary struct: tc-ratespec - name: limit type: u32 - name: buffer type: u32 - name: mtu type: u32 This adds the necessary schema changes and adds nested struct encoding and decoding to ynl. Signed-off-by: Donald Hunter <donald.hunter@xxxxxxxxx> --- Documentation/netlink/netlink-raw.yaml | 15 ++++++++++++--- tools/net/ynl/lib/nlspec.py | 2 ++ tools/net/ynl/lib/ynl.py | 26 ++++++++++++++++++++------ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 04b92f1a5cd6..ac4e05415f2f 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -152,14 +152,23 @@ properties: the right formatting mechanism when displaying values of this type. enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + struct: + description: Name of the nested struct type. + type: string if: properties: type: - oneOf: - - const: binary - - const: pad + const: pad then: required: [ len ] + if: + properties: + type: + const: binary + then: + oneOf: + - required: [ len ] + - required: [ struct ] # End genetlink-legacy attribute-sets: diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 44f13e383e8a..5d197a12ab8d 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -248,6 +248,7 @@ class SpecStructMember(SpecElement): len integer, optional byte length of binary types display_hint string, hint to help choose format specifier when displaying the value + struct string, name of nested struct type """ def __init__(self, family, yaml): super().__init__(family, yaml) @@ -256,6 +257,7 @@ class SpecStructMember(SpecElement): self.enum = yaml.get('enum') self.len = yaml.get('len') self.display_hint = yaml.get('display-hint') + self.struct = yaml.get('struct') class SpecStruct(SpecElement): diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 2b0ca61deaf8..0f4193cc2e3b 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -674,7 +674,10 @@ class YnlFamily(SpecFamily): size = 0 for m in members: if m.type in ['pad', 'binary']: - size += m.len + if m.struct: + size += self._struct_size(m.struct) + else: + size += m.len else: format = NlAttr.get_format(m.type, m.byte_order) size += format.size @@ -691,8 +694,14 @@ class YnlFamily(SpecFamily): if m.type == 'pad': offset += m.len elif m.type == 'binary': - value = data[offset : offset + m.len] - offset += m.len + if m.struct: + len = self._struct_size(m.struct) + value = self._decode_struct(data[offset : offset + len], + m.struct) + offset += len + else: + value = data[offset : offset + m.len] + offset += m.len else: format = NlAttr.get_format(m.type, m.byte_order) [ value ] = format.unpack_from(data, offset) @@ -713,10 +722,15 @@ class YnlFamily(SpecFamily): if m.type == 'pad': attr_payload += bytearray(m.len) elif m.type == 'binary': - if value is None: - attr_payload += bytearray(m.len) + if m.struct: + if value is None: + value = dict() + attr_payload += self._encode_struct(m.struct, value) else: - attr_payload += bytes.fromhex(value) + if value is None: + attr_payload += bytearray(m.len) + else: + attr_payload += bytes.fromhex(value) else: if value is None: value = 0 -- 2.42.0