All of lore.kernel.org
 help / color / mirror / Atom feed
From: Donald Hunter <donald.hunter@gmail.com>
To: Dan Williams <djbw@kernel.org>
Cc: linux-coco@lists.linux.dev,  linux-pci@vger.kernel.org,
	driver-core@lists.linux.dev,  ankita@nvidia.com,
	 Alistair Francis <alistair.francis@wdc.com>,
	 Lukas Wunner <lukas@wunner.de>,
	 Jakub Kicinski <kuba@kernel.org>
Subject: Re: [PATCH 02/15] tools: ynl: Teach pyynl to handle blobs
Date: Wed, 08 Jul 2026 14:48:28 +0100	[thread overview]
Message-ID: <m2ldblbnir.fsf@gmail.com> (raw)
In-Reply-To: <20260705220819.2472765-3-djbw@kernel.org>

Dan Williams <djbw@kernel.org> writes:

> 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(-)

I am mid-review of this but I think it could be simplified. See initial
thoughts below. Can you show me how to configure a test env so I can try
it out?

>
> 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()

Initialising to None would avoid some other logic.

>  
>          # 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)

I think this hunk can be dropped and instead use op.dump_blob_attrs directly

>              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)
> +

This approach seems unnecessary for pyynl. Just let multi-attr do its
thing and then concatenate them at the end.

>                  op_rsp.append(rsp_msg)
>  
>          return rsp

  parent reply	other threads:[~2026-07-08 13:48 UTC|newest]

Thread overview: 56+ 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-08 11:13   ` Donald Hunter
2026-07-11  1:43     ` Dan Williams (nvidia)
2026-07-08 13:23   ` Donald Hunter
2026-07-05 22:08 ` [PATCH 02/15] tools: ynl: Teach pyynl to handle blobs Dan Williams
2026-07-05 22:18   ` sashiko-bot
2026-07-08 13:48   ` Donald Hunter [this message]
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-08 13:22   ` Donald Hunter
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-08  5:00   ` Alexey Kardashevskiy
2026-07-08 18:25     ` Dan Williams (nvidia)
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-08 18:06     ` Dan Williams (nvidia)
2026-07-08 18:10       ` Aneesh Kumar K.V
2026-07-09  6:32   ` Alexey Kardashevskiy
2026-07-09  7:38     ` Alexey Kardashevskiy
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-08  9:49   ` Alexey Kardashevskiy
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-08  2:25   ` Alexey Kardashevskiy
2026-07-08 18:05     ` Dan Williams (nvidia)
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
2026-07-08  0:12       ` Dan Williams (nvidia)
2026-07-08 14:31         ` Jason Gunthorpe
2026-07-09  2:45           ` Dan Williams (nvidia)
2026-07-09 13:36             ` 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=m2ldblbnir.fsf@gmail.com \
    --to=donald.hunter@gmail.com \
    --cc=alistair.francis@wdc.com \
    --cc=ankita@nvidia.com \
    --cc=djbw@kernel.org \
    --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.