diff options
author | Donald Hunter <donald.hunter@gmail.com> | 2023-03-27 09:31:35 +0100 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2023-03-28 23:54:43 -0700 |
commit | f036d936ca57e8bc1f39b92cadfbac27095dc4e7 (patch) | |
tree | a957b1e83af3def609f4da7c057c041f7b1bd8b4 /tools/net/ynl/lib | |
parent | 2607191395bd4db544db05452625cd7e98bc0848 (diff) | |
download | linux-stable-f036d936ca57e8bc1f39b92cadfbac27095dc4e7.tar.gz linux-stable-f036d936ca57e8bc1f39b92cadfbac27095dc4e7.tar.bz2 linux-stable-f036d936ca57e8bc1f39b92cadfbac27095dc4e7.zip |
tools: ynl: Add fixed-header support to ynl
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>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'tools/net/ynl/lib')
-rw-r--r-- | tools/net/ynl/lib/nlspec.py | 21 | ||||
-rw-r--r-- | tools/net/ynl/lib/ynl.py | 24 |
2 files changed, 33 insertions, 12 deletions
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index d1e5f60af580..06a906d74f0e 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -263,16 +263,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) @@ -284,6 +285,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 @@ -324,6 +326,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: @@ -397,6 +400,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: @@ -408,6 +412,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 63af3bd9787d..ec40918152e1 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -278,14 +278,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): @@ -509,6 +517,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) @@ -535,7 +550,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: @@ -545,7 +560,8 @@ 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 |