tools: ynl: add display-hint support to ynl

Add support to the ynl tool for rendering output based on display-hint
properties.

Signed-off-by: Donald Hunter <donald.hunter@gmail.com>
Link: https://lore.kernel.org/r/20230623201928.14275-3-donald.hunter@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Donald Hunter
2023-06-23 21:19:27 +01:00
committed by Jakub Kicinski
parent 737eab775d
commit d8eea68d91
2 changed files with 39 additions and 5 deletions

View File

@@ -154,6 +154,9 @@ class SpecAttr(SpecElement):
is_multi bool, attr may repeat multiple times is_multi bool, attr may repeat multiple times
struct_name string, name of struct definition struct_name string, name of struct definition
sub_type string, name of sub type sub_type string, name of sub type
len integer, optional byte length of binary types
display_hint string, hint to help choose format specifier
when displaying the value
""" """
def __init__(self, family, attr_set, yaml, value): def __init__(self, family, attr_set, yaml, value):
super().__init__(family, yaml) super().__init__(family, yaml)
@@ -164,6 +167,8 @@ class SpecAttr(SpecElement):
self.struct_name = yaml.get('struct') self.struct_name = yaml.get('struct')
self.sub_type = yaml.get('sub-type') self.sub_type = yaml.get('sub-type')
self.byte_order = yaml.get('byte-order') self.byte_order = yaml.get('byte-order')
self.len = yaml.get('len')
self.display_hint = yaml.get('display-hint')
class SpecAttrSet(SpecElement): class SpecAttrSet(SpecElement):
@@ -229,12 +234,17 @@ class SpecStructMember(SpecElement):
type string, type of the member attribute type string, type of the member attribute
byte_order string or None for native byte order byte_order string or None for native byte order
enum string, name of the enum definition enum string, name of the enum definition
len integer, optional byte length of binary types
display_hint string, hint to help choose format specifier
when displaying the value
""" """
def __init__(self, family, yaml): def __init__(self, family, yaml):
super().__init__(family, yaml) super().__init__(family, yaml)
self.type = yaml['type'] self.type = yaml['type']
self.byte_order = yaml.get('byte-order') self.byte_order = yaml.get('byte-order')
self.enum = yaml.get('enum') self.enum = yaml.get('enum')
self.len = yaml.get('len')
self.display_hint = yaml.get('display-hint')
class SpecStruct(SpecElement): class SpecStruct(SpecElement):

View File

@@ -8,6 +8,8 @@ import socket
import struct import struct
from struct import Struct from struct import Struct
import yaml import yaml
import ipaddress
import uuid
from .nlspec import SpecFamily from .nlspec import SpecFamily
@@ -105,6 +107,20 @@ class NlAttr:
else format.little else format.little
return format.native return format.native
@classmethod
def formatted_string(cls, raw, display_hint):
if display_hint == 'mac':
formatted = ':'.join('%02x' % b for b in raw)
elif display_hint == 'hex':
formatted = bytes.hex(raw, ' ')
elif display_hint in [ 'ipv4', 'ipv6' ]:
formatted = format(ipaddress.ip_address(raw))
elif display_hint == 'uuid':
formatted = str(uuid.UUID(bytes=raw))
else:
formatted = raw
return formatted
def as_scalar(self, attr_type, byte_order=None): def as_scalar(self, attr_type, byte_order=None):
format = self.get_format(attr_type, byte_order) format = self.get_format(attr_type, byte_order)
return format.unpack(self.raw)[0] return format.unpack(self.raw)[0]
@@ -124,10 +140,16 @@ class NlAttr:
offset = 0 offset = 0
for m in members: for m in members:
# TODO: handle non-scalar members # TODO: handle non-scalar members
if m.type == 'binary':
decoded = self.raw[offset:offset+m['len']]
offset += m['len']
elif m.type in NlAttr.type_formats:
format = self.get_format(m.type, m.byte_order) format = self.get_format(m.type, m.byte_order)
decoded = format.unpack_from(self.raw, offset) [ decoded ] = format.unpack_from(self.raw, offset)
offset += format.size offset += format.size
value[m.name] = decoded[0] if m.display_hint:
decoded = self.formatted_string(decoded, m.display_hint)
value[m.name] = decoded
return value return value
def __repr__(self): def __repr__(self):
@@ -385,7 +407,7 @@ class YnlFamily(SpecFamily):
elif attr["type"] == 'string': elif attr["type"] == 'string':
attr_payload = str(value).encode('ascii') + b'\x00' attr_payload = str(value).encode('ascii') + b'\x00'
elif attr["type"] == 'binary': elif attr["type"] == 'binary':
attr_payload = value attr_payload = bytes.fromhex(value)
elif attr['type'] in NlAttr.type_formats: elif attr['type'] in NlAttr.type_formats:
format = NlAttr.get_format(attr['type'], attr.byte_order) format = NlAttr.get_format(attr['type'], attr.byte_order)
attr_payload = format.pack(int(value)) attr_payload = format.pack(int(value))
@@ -421,6 +443,8 @@ class YnlFamily(SpecFamily):
decoded = attr.as_c_array(attr_spec.sub_type) decoded = attr.as_c_array(attr_spec.sub_type)
else: else:
decoded = attr.as_bin() decoded = attr.as_bin()
if attr_spec.display_hint:
decoded = NlAttr.formatted_string(decoded, attr_spec.display_hint)
return decoded return decoded
def _decode(self, attrs, space): def _decode(self, attrs, space):