Commit bf08f32c authored by Donald Hunter's avatar Donald Hunter Committed by Jakub Kicinski

tools/net/ynl: Add support for nested structs

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: default avatarDonald Hunter <donald.hunter@gmail.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20240129223458.52046-11-donald.hunter@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 971c3eea
...@@ -152,14 +152,23 @@ properties: ...@@ -152,14 +152,23 @@ properties:
the right formatting mechanism when displaying values of this the right formatting mechanism when displaying values of this
type. type.
enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] enum: [ hex, mac, fddi, ipv4, ipv6, uuid ]
struct:
description: Name of the nested struct type.
type: string
if: if:
properties: properties:
type: type:
oneOf: const: pad
- const: binary
- const: pad
then: then:
required: [ len ] required: [ len ]
if:
properties:
type:
const: binary
then:
oneOf:
- required: [ len ]
- required: [ struct ]
# End genetlink-legacy # End genetlink-legacy
attribute-sets: attribute-sets:
......
...@@ -248,6 +248,7 @@ class SpecStructMember(SpecElement): ...@@ -248,6 +248,7 @@ class SpecStructMember(SpecElement):
len integer, optional byte length of binary types len integer, optional byte length of binary types
display_hint string, hint to help choose format specifier display_hint string, hint to help choose format specifier
when displaying the value when displaying the value
struct string, name of nested struct type
""" """
def __init__(self, family, yaml): def __init__(self, family, yaml):
super().__init__(family, yaml) super().__init__(family, yaml)
...@@ -256,6 +257,7 @@ class SpecStructMember(SpecElement): ...@@ -256,6 +257,7 @@ class SpecStructMember(SpecElement):
self.enum = yaml.get('enum') self.enum = yaml.get('enum')
self.len = yaml.get('len') self.len = yaml.get('len')
self.display_hint = yaml.get('display-hint') self.display_hint = yaml.get('display-hint')
self.struct = yaml.get('struct')
class SpecStruct(SpecElement): class SpecStruct(SpecElement):
......
...@@ -674,7 +674,10 @@ class YnlFamily(SpecFamily): ...@@ -674,7 +674,10 @@ class YnlFamily(SpecFamily):
size = 0 size = 0
for m in members: for m in members:
if m.type in ['pad', 'binary']: if m.type in ['pad', 'binary']:
size += m.len if m.struct:
size += self._struct_size(m.struct)
else:
size += m.len
else: else:
format = NlAttr.get_format(m.type, m.byte_order) format = NlAttr.get_format(m.type, m.byte_order)
size += format.size size += format.size
...@@ -691,8 +694,14 @@ class YnlFamily(SpecFamily): ...@@ -691,8 +694,14 @@ class YnlFamily(SpecFamily):
if m.type == 'pad': if m.type == 'pad':
offset += m.len offset += m.len
elif m.type == 'binary': elif m.type == 'binary':
value = data[offset : offset + m.len] if m.struct:
offset += m.len 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: else:
format = NlAttr.get_format(m.type, m.byte_order) format = NlAttr.get_format(m.type, m.byte_order)
[ value ] = format.unpack_from(data, offset) [ value ] = format.unpack_from(data, offset)
...@@ -713,10 +722,15 @@ class YnlFamily(SpecFamily): ...@@ -713,10 +722,15 @@ class YnlFamily(SpecFamily):
if m.type == 'pad': if m.type == 'pad':
attr_payload += bytearray(m.len) attr_payload += bytearray(m.len)
elif m.type == 'binary': elif m.type == 'binary':
if value is None: if m.struct:
attr_payload += bytearray(m.len) if value is None:
value = dict()
attr_payload += self._encode_struct(m.struct, value)
else: else:
attr_payload += bytes.fromhex(value) if value is None:
attr_payload += bytearray(m.len)
else:
attr_payload += bytes.fromhex(value)
else: else:
if value is None: if value is None:
value = 0 value = 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment