From: Dan Williams <djbw@kernel.org>
To: linux-coco@lists.linux.dev
Cc: linux-pci@vger.kernel.org, driver-core@lists.linux.dev,
ankita@nvidia.com, Alistair Francis <alistair.francis@wdc.com>,
Lukas Wunner <lukas@wunner.de>,
Donald Hunter <donald.hunter@gmail.com>,
Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH 02/15] tools: ynl: Teach pyynl to handle blobs
Date: Sun, 5 Jul 2026 15:08:06 -0700 [thread overview]
Message-ID: <20260705220819.2472765-3-djbw@kernel.org> (raw)
In-Reply-To: <20260705220819.2472765-1-djbw@kernel.org>
The generic "device evidence" facility wants to convey large objects
(certificate chains, measurements) and support various security commands
relative to that evidence (like validate) [1].
Update pyynl to understand the "bloblen" property indicates:
* the associated attribute is a variable length byte array
* it is multi-attr where each message with the same attribute represents
chunks of the byte array
* the byte array's size is conveyed in a scalar attribute named by the
"bloblen" property.
* the attribute identified by "bloblen" always arrives in a message before
the first chunk of the associated blob
A "multi-attr" without "bloblen" retains the legacy behavior where repeated
reception of the same attribute across messages results in a new instance
of the object. The new behavior causes repeated reception of an
attribute to be treated as filling consecutive bytes of an array.
Assisted-by: Codex:GPT-5
[codex: drafted initial python changes]
Cc: Alistair Francis <alistair.francis@wdc.com>
Cc: Lukas Wunner <lukas@wunner.de>
Cc: Donald Hunter <donald.hunter@gmail.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Link: http://lore.kernel.org/20260318170014.6650d2bf@kernel.org [1]
Signed-off-by: Dan Williams <djbw@kernel.org>
---
tools/net/ynl/pyynl/lib/nlspec.py | 12 ++++++
tools/net/ynl/pyynl/lib/ynl.py | 62 ++++++++++++++++++++++++++++++-
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/tools/net/ynl/pyynl/lib/nlspec.py b/tools/net/ynl/pyynl/lib/nlspec.py
index 0469a0e270d0..4764263968ea 100644
--- a/tools/net/ynl/pyynl/lib/nlspec.py
+++ b/tools/net/ynl/pyynl/lib/nlspec.py
@@ -172,6 +172,7 @@ class SpecAttr(SpecElement):
selector string, name of attribute used to select
sub-message type
+ bloblen string, name of attr which reports the blob length
is_auto_scalar bool, attr is a variable-size scalar
"""
def __init__(self, family, attr_set, yaml, value):
@@ -181,6 +182,7 @@ class SpecAttr(SpecElement):
self.value = value
self.attr_set = attr_set
self.is_multi = yaml.get('multi-attr', False)
+ self.bloblen = yaml.get('bloblen')
self.struct_name = yaml.get('struct')
self.sub_type = yaml.get('sub-type')
self.byte_order = yaml.get('byte-order')
@@ -191,6 +193,10 @@ class SpecAttr(SpecElement):
self.is_auto_scalar = self.type in ("sint", "uint")
+ if self.bloblen and not self.is_multi:
+ raise SpecException(
+ f"Attribute '{attr_set.name}.{self.name}' has bloblen without multi-attr")
+
class SpecAttrSet(SpecElement):
""" Netlink Attribute Set class.
@@ -355,6 +361,8 @@ class SpecOperation(SpecElement):
attr_set attribute set name
fixed_header string, optional name of fixed header struct
+ dump_blob_attrs set, reply blob attribute names which may span messages
+
yaml raw spec as loaded from the spec file
"""
def __init__(self, family, yaml, req_value, rsp_value):
@@ -369,6 +377,7 @@ class SpecOperation(SpecElement):
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)
+ self.dump_blob_attrs = frozenset()
# Added by resolve:
self.attr_set = None
@@ -388,6 +397,9 @@ class SpecOperation(SpecElement):
raise SpecException(f"Can't resolve attribute set for op '{self.name}'")
if attr_set_name:
self.attr_set = self.family.attr_sets[attr_set_name]
+ reply_attrs = self.yaml.get('dump', {}).get('reply', {}).get('attributes', ())
+ self.dump_blob_attrs = frozenset(
+ name for name in reply_attrs if self.attr_set[name].bloblen)
class SpecMcastGroup(SpecElement):
diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py
index 092d132edec1..f21b68043bd3 100644
--- a/tools/net/ynl/pyynl/lib/ynl.py
+++ b/tools/net/ynl/pyynl/lib/ynl.py
@@ -998,6 +998,47 @@ class YnlFamily(SpecFamily):
else:
rsp[name] = [decoded]
+ def _blob_fill(self, buf, off, chunks, name):
+ for chunk in chunks:
+ end = off + len(chunk)
+ if end > len(buf):
+ raise YnlException(f"Blob '{name}' data exceeds reported length")
+ buf[off:end] = chunk
+ off = end
+ return off
+
+ def _blob_init(self, op, rsp, blob_attrs):
+ """
+ Start a new blob object. Preallocate each blob payload using the
+ length carried ahead of the data and copy in the first chunk(s).
+ Return the per-attribute write offsets for any following messages.
+ """
+ offsets = {}
+ for name in blob_attrs:
+ if name not in rsp:
+ continue
+ length = rsp.get(op.attr_set[name].bloblen, 0)
+ buf = bytearray(length)
+ offsets[name] = self._blob_fill(buf, 0, rsp[name], name)
+ rsp[name] = buf
+ return offsets
+
+ def _blob_extend(self, rsp, update, blob_attrs, offsets):
+ """
+ Continue filling the previous object's blob(s) when the current
+ message carries only blob continuation attributes.
+ """
+ if any(name in rsp and name not in blob_attrs for name in update):
+ return False
+
+ for name, value in update.items():
+ if name in blob_attrs and name in rsp:
+ offsets[name] = self._blob_fill(rsp[name], offsets.get(name, 0),
+ value, name)
+ else:
+ rsp[name] = value
+ return True
+
def _resolve_selector(self, attr_spec, search_attrs):
sub_msg = attr_spec.sub_message
if sub_msg not in self.sub_msgs:
@@ -1356,7 +1397,10 @@ class YnlFamily(SpecFamily):
for (method, vals, flags) in ops:
op = self.ops[method]
msg = self._encode_message(op, vals, flags, req_seq)
- reqs_by_seq[req_seq] = (op, vals, msg, flags)
+ blob_attrs = None
+ if Netlink.NLM_F_DUMP in flags:
+ blob_attrs = op.dump_blob_attrs or None
+ reqs_by_seq[req_seq] = (op, vals, msg, flags, blob_attrs)
payload += msg
req_seq += 1
@@ -1365,6 +1409,7 @@ class YnlFamily(SpecFamily):
done = False
rsp = []
op_rsp = []
+ blob_off = {}
while not done:
reply, ancdata = self._recvmsg()
nsid = self._decode_nsid(ancdata)
@@ -1372,13 +1417,14 @@ class YnlFamily(SpecFamily):
self._recv_dbg_print(reply, nms)
for nl_msg in nms:
if nl_msg.nl_seq in reqs_by_seq:
- (op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
+ (op, vals, req_msg, req_flags, blob_attrs) = reqs_by_seq[nl_msg.nl_seq]
if nl_msg.extack:
nl_msg.annotate_extack(op.attr_set)
self._decode_extack(req_msg, op, nl_msg.extack, vals)
else:
op = None
req_flags = []
+ blob_attrs = None
if nl_msg.error:
raise NlError(nl_msg)
@@ -1388,6 +1434,11 @@ class YnlFamily(SpecFamily):
print(nl_msg)
if Netlink.NLM_F_DUMP in req_flags:
+ if blob_attrs:
+ for obj in op_rsp:
+ for name in blob_attrs:
+ if isinstance(obj.get(name), bytearray):
+ obj[name] = bytes(obj[name])
rsp.append(op_rsp)
elif not op_rsp:
rsp.append(None)
@@ -1414,6 +1465,13 @@ class YnlFamily(SpecFamily):
rsp_msg = self._decode(decoded.raw_attrs, op.attr_set.name)
if op.fixed_header:
rsp_msg.update(self._decode_struct(decoded.raw, op.fixed_header))
+
+ if blob_attrs:
+ if op_rsp and self._blob_extend(op_rsp[-1], rsp_msg,
+ blob_attrs, blob_off):
+ continue
+ blob_off = self._blob_init(op, rsp_msg, blob_attrs)
+
op_rsp.append(rsp_msg)
return rsp
--
2.54.0
next prev parent reply other threads:[~2026-07-05 22:08 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-05 22:08 [PATCH 00/15] Device Evidence and Trust for PCI Security Protocol (TDISP) Dan Williams
2026-07-05 22:08 ` [PATCH 01/15] netlink: specs: Introduce multi-message blobs for SPDM Dan Williams
2026-07-05 22:13 ` sashiko-bot
2026-07-05 22:08 ` Dan Williams [this message]
2026-07-05 22:18 ` [PATCH 02/15] tools: ynl: Teach pyynl to handle blobs sashiko-bot
2026-07-05 22:08 ` [PATCH 03/15] tools: ynl: Teach ynl_gen_c to validate and dump 'blob' attributes Dan Williams
2026-07-05 22:20 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 04/15] device core: Introduce "device evidence" over netlink Dan Williams
2026-07-05 22:20 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 05/15] device core: Add "device evidence" 'validate' command Dan Williams
2026-07-05 22:26 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 06/15] PCI/TSM: Add device evidence support Dan Williams
2026-07-05 22:16 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 07/15] modules: Document the global async_probe parameter Dan Williams
2026-07-05 22:15 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 08/15] device core: Initial device trust infrastructure Dan Williams
2026-07-05 22:17 ` sashiko-bot
2026-07-06 13:45 ` Jason Gunthorpe
2026-07-05 22:08 ` [PATCH 09/15] PCI, device core: Move "untrusted" concept to DEVICE_TRUST_ADVERSARY Dan Williams
2026-07-05 22:25 ` sashiko-bot
2026-07-06 13:49 ` Jason Gunthorpe
2026-07-07 13:04 ` Robin Murphy
2026-07-05 22:08 ` [PATCH 10/15] PCI/TSM: Add device interface security LOCKED support Dan Williams
2026-07-05 22:25 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 11/15] PCI/TSM: Add device interface security RUN support Dan Williams
2026-07-05 22:21 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 12/15] PCI/TSM: Add device interface security DMA enable/disable Dan Williams
2026-07-05 22:25 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 13/15] PCI, device core: Add private memory access for DEVICE_TRUST_TCB Dan Williams
2026-07-05 22:28 ` sashiko-bot
2026-07-06 12:42 ` Aneesh Kumar K.V
2026-07-05 22:08 ` [PATCH 14/15] PCI/TSM: Create MMIO descriptors via TDISP Report Dan Williams
2026-07-05 22:24 ` sashiko-bot
2026-07-05 22:08 ` [PATCH 15/15] PCI/TSM: Add relative MMIO offset support? Dan Williams
2026-07-05 22:25 ` sashiko-bot
2026-07-06 12:51 ` [PATCH 00/15] Device Evidence and Trust for PCI Security Protocol (TDISP) Jason Gunthorpe
2026-07-06 20:55 ` Dan Williams (nvidia)
2026-07-07 12:43 ` Jason Gunthorpe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260705220819.2472765-3-djbw@kernel.org \
--to=djbw@kernel.org \
--cc=alistair.francis@wdc.com \
--cc=ankita@nvidia.com \
--cc=donald.hunter@gmail.com \
--cc=driver-core@lists.linux.dev \
--cc=kuba@kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-pci@vger.kernel.org \
--cc=lukas@wunner.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.