moq-wg / moq-transport

draft-ietf-moq-transport
Other
82 stars 20 forks source link

Need MoQT Object Header Extensibility #433

Open fluffy opened 5 months ago

fluffy commented 5 months ago

The whole draft needed a pass at some point for extensibility but a more immediate concern is to play with various things, we need a way of adding header to an object that the relay can read. The LOC draft has a line about needing this, I think Will had some use cases that needed it, and it would help with experimenting and migrating some pre standard implementations to the current version of the draft.

The requirement would be there was a way to define new headers in extensions, there was a way to indicate if the header needs to be understood by relays, reviewers, both, or neither.

kixelated commented 5 months ago

IMO we should negotiate extensions in the SETUP message. I'm a little worried about adding arbitrary blobs to messages that might change the relay's behavior, although I understand that's how HTTP works today.

fluffy commented 5 months ago

+1 on both parts of what you said. Let me give a more concrete example.

Many systems end up traces defined roughly like https://opentelemetry.io/docs/concepts/signals/traces/ - to debug things across clients, servers, and a distributed system. To make this work for MoQT, we need to be able to add a trace id that is sent across the network. In many cases not every object would be traced as that would have a performance impact, but perhaps the first object in all the I frames might be traced from a client that was having issues.

I was imaging something like a spec could define an extension and get a IANA number for it ( small numbers for RFC, larger numbers for non IETF specs ). You would negotiate support for the extension in usual way in the SETUP. Then in the object there would be an array of extensions that could be zero size and each the data for each extension included the number that identified the extension. That way someone could right an extension for something like adding a trace_id to object and relays that supported that could log information about it that included the trace-id.

We probably need a way for extensions to mandatory to understand or not by relays and if not mandatory to understand include a length or way to be able to skip over the data.

wilaw commented 5 months ago

Thanks Cullen for raising this issue.

I think Will had some use cases that needed it

Indeed I do. I was thinking about the usefulness of headers in HTTP and how much innovation, behavior and extensibility in workflows is enabled by their presence and relatively simple implementation. I'd like something similar for moqt.

there was a way to indicate if the header needs to be understood by relays, reviewers, both, or neither.

IMO, if a header needs to be understood by relays, then it should be part of the moqt specification and not part of some extensibility scheme. Therefore I'd say that headers are NEVER mandatory to be understood by relays. Headers, if present, are to be understood only by those nodes that know to look for them. All other nodes would ignore them.

IMO we should negotiate extensions in the SETUP message. I'm a little worried about adding arbitrary blobs to messages that might change the relay's behavior, although I understand that's how HTTP works today.

If we go with headers are never mandatory, then there is no need for negotiation during setup. I'd rather the existing subprotocol negotiation handle required behavior.

For extensibility, we can go in two directions. The first, as suggested, is an IANA table for each header type.

OBJECT_STREAM Message {
  Subscribe ID (i),
  Track Alias (i),
  Group ID (i),
  Object ID (i),
  Object Send Order (i),
  Custom-extension1 (i),
  Custom-extension2 (i),
  Object Payload (..),
}

The second , which I prefer, defines a single new Object header called "header", or perhaps "Extension" if we wish to decouple it from the HTTP semantics.

OBJECT_STREAM Message {
  Subscribe ID (i),
  Track Alias (i),
  Group ID (i),
  Object ID (i),
  Object Send Order (i),
  Extension(i),
  Object Payload (..),
}

The Extension bytes are then a concatenation of Extension types|length|payloads. The types are identifiers that are registered with IANA. Order is unimportant.

Extension {
   Extension type (i),
   Extension length (i),
   Extension payload (i),
   Extension type (i),
   Extension length (i),
   Extension payload (i),
 ...
   Extension type (i),
   Extension length (i),
   Extension payload (i)
}

A node can ignore the Extension filed completely, or it may parse its way down the extension payload looking for extension types that it recognizes. Once it recognizes a type, it will know how to parse the payload.

fluffy commented 5 months ago

+1 on the the TLV approach in your second approach with Extension.

fluffy commented 5 months ago

Just one little tweek to your syntax above ... I think the object would need to look more like

  Num Extensions (i),
  Extension(..),

It seems to me you need to know the number of them to know when to stop parsing. I don't know if the style is better to have that outside or inside the Extension structure but somewhere.

wilaw commented 5 months ago

It seems to me you need to know the number of them to know when to stop parsing.

I think it would work without, because the Extension(i) value in the object header would give the total number of bytes assigned to the extensions. 0 indicates no extensions. For a positive value B, any receiver could parse their way down until totalExtensionBytesProcessed = B and then they would know that the next byte represents the start of the Object payload and not the next TLV extension.

vasilvv commented 1 month ago

I would like to see specific use cases presented for this before discussing further.

IMO, if a header needs to be understood by relays, then it should be part of the moqt specification and not part of some extensibility scheme. Therefore I'd say that headers are NEVER mandatory to be understood by relays. Headers, if present, are to be understood only by those nodes that know to look for them. All other nodes would ignore them.

I'm not sure this makes sense to me. If a specific piece of metadata does not need to be understood by relays, you can just put it into the object payload.

wilaw commented 1 month ago

If a specific piece of metadata does not need to be understood by relays, you can just put it into the object payload.

But what if some relays need to use it while the rest can ignore and forward it? Here's an example: imagine a advertising header that only the outermost relay ( the edge relay) will use to manipulate data that it sends to the end subscribers. We can't put this info in the object payload because that is opaque to relays and may be encrypted. Therefore we would like to have this extension header be preserved and forwarded (but not understood or parsed) by distribution relays and then only the last relay, which is programmed to look for it, would actually parse and use it.