[PATCH net-next v4 4/7] tools: ynl: Add fixed-header support to ynl
From: Donald Hunter <donald.hunter@gmail.com>
Date: 2023-03-24 19:19:35
Also in:
linux-doc
Subsystem:
networking [general], the rest, yaml netlink (ynl) · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Donald Hunter
Add support for netlink families that add an optional fixed header structure after the genetlink header and before any attributes. The fixed-header can be specified on a per op basis, or once for all operations, which serves as a default value that can be overridden. Signed-off-by: Donald Hunter <donald.hunter@gmail.com> --- Documentation/netlink/genetlink-legacy.yaml | 10 +++++++++ tools/net/ynl/lib/nlspec.py | 21 ++++++++++++------- tools/net/ynl/lib/ynl.py | 23 +++++++++++++++++---- 3 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml
index d50c78b9f42d..3b8984122383 100644
--- a/Documentation/netlink/genetlink-legacy.yaml
+++ b/Documentation/netlink/genetlink-legacy.yaml@@ -261,6 +261,13 @@ properties: async-enum: description: Name for the enum type with notifications/events. type: string + # Start genetlink-legacy + fixed-header: &fixed-header + description: | + Name of the structure defininig the optional fixed-length protocol header. This header is + placed in a message after the netlink and genetlink headers and before any attributes. + type: string + # End genetlink-legacy list: description: List of commands type: array
@@ -293,6 +300,9 @@ properties: type: array items: enum: [ strict, dump ] + # Start genetlink-legacy + fixed-header: *fixed-header + # End genetlink-legacy do: &subop-type description: Main command handler. type: object
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index a08f6dda5b79..09dbb6c51ee9 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py@@ -258,16 +258,17 @@ class SpecOperation(SpecElement): Information about a single Netlink operation. Attributes: - value numerical ID when serialized, None if req/rsp values differ + value numerical ID when serialized, None if req/rsp values differ - req_value numerical ID when serialized, user -> kernel - rsp_value numerical ID when serialized, user <- kernel - is_call bool, whether the operation is a call - is_async bool, whether the operation is a notification - is_resv bool, whether the operation does not exist (it's just a reserved ID) - attr_set attribute set name + req_value numerical ID when serialized, user -> kernel + rsp_value numerical ID when serialized, user <- kernel + is_call bool, whether the operation is a call + is_async bool, whether the operation is a notification + is_resv bool, whether the operation does not exist (it's just a reserved ID) + attr_set attribute set name + fixed_header string, optional name of fixed header struct - yaml raw spec as loaded from the spec file + yaml raw spec as loaded from the spec file """ def __init__(self, family, yaml, req_value, rsp_value): super().__init__(family, yaml)
@@ -279,6 +280,7 @@ class SpecOperation(SpecElement): self.is_call = 'do' in yaml or 'dump' in yaml self.is_async = 'notify' in yaml or 'event' in yaml self.is_resv = not self.is_async and not self.is_call + self.fixed_header = self.yaml.get('fixed-header', family.fixed_header) # Added by resolve: self.attr_set = None
@@ -319,6 +321,7 @@ class SpecFamily(SpecElement): msgs_by_value dict of all messages (indexed by name) ops dict of all valid requests / responses consts dict of all constants/enums + fixed_header string, optional name of family default fixed header struct """ def __init__(self, spec_path, schema_path=None): with open(spec_path, "r") as stream:
@@ -392,6 +395,7 @@ class SpecFamily(SpecElement): self._resolution_list.append(elem) def _dictify_ops_unified(self): + self.fixed_header = self.yaml['operations'].get('fixed-header') val = 1 for elem in self.yaml['operations']['list']: if 'value' in elem:
@@ -403,6 +407,7 @@ class SpecFamily(SpecElement): self.msgs[op.name] = op def _dictify_ops_directional(self): + self.fixed_header = self.yaml['operations'].get('fixed-header') req_val = rsp_val = 1 for elem in self.yaml['operations']['list']: if 'notify' in elem:
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index af1d6d380035..4d206c46a087 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py@@ -277,14 +277,22 @@ def _genl_load_families(): class GenlMsg: - def __init__(self, nl_msg): + def __init__(self, nl_msg, fixed_header_members = []): self.nl = nl_msg self.hdr = nl_msg.raw[0:4] - self.raw = nl_msg.raw[4:] + offset = 4 self.genl_cmd, self.genl_version, _ = struct.unpack("BBH", self.hdr) + self.fixed_header_attrs = dict() + for m in fixed_header_members: + format, size = NlAttr.type_formats[m.type] + decoded = struct.unpack_from(format, nl_msg.raw, offset) + offset += size + self.fixed_header_attrs[m.name] = decoded[0] + + self.raw = nl_msg.raw[offset:] self.raw_attrs = NlAttrs(self.raw) def __repr__(self):
@@ -504,6 +512,13 @@ class YnlFamily(SpecFamily): req_seq = random.randint(1024, 65535) msg = _genl_msg(self.family.family_id, nl_flags, op.req_value, 1, req_seq) + fixed_header_members = [] + if op.fixed_header: + fixed_header_members = self.consts[op.fixed_header].members + for m in fixed_header_members: + value = vals.pop(m.name) + format, _ = NlAttr.type_formats[m.type] + msg += struct.pack(format, value) for name, value in vals.items(): msg += self._add_attr(op.attr_set.name, name, value) msg = _genl_msg_finalize(msg)
@@ -530,7 +545,7 @@ class YnlFamily(SpecFamily): done = True break - gm = GenlMsg(nl_msg) + gm = GenlMsg(nl_msg, fixed_header_members) # Check if this is a reply to our request if nl_msg.nl_seq != req_seq or gm.genl_cmd != op.rsp_value: if gm.genl_cmd in self.async_msg_ids:
@@ -540,7 +555,7 @@ class YnlFamily(SpecFamily): print('Unexpected message: ' + repr(gm)) continue - rsp.append(self._decode(gm.raw_attrs, op.attr_set.name)) + rsp.append(self._decode(gm.raw_attrs, op.attr_set.name) | gm.fixed_header_attrs) if not rsp: return None
--
2.39.0