RFC 5740

NACK-Oriented Reliable Multicast (NORM) Transport Protocol

๐Ÿ“… published November 2009, from ietf

RFC 5740 ๐ŸŽ€ NACK-Oriented Reliable Multicast (NORM) Transport Protocol

Bestie, this one is a whole vibe ๐Ÿ’– It's an IETF Standards Track doc from the Network Working Group, dated November 2009. It obsoletes RFC 3940 ๐Ÿซถ The authors are B. Adamson, C. Bormann, M. Handley, and J. Macker. Adamson and Macker are at the Naval Research Laboratory, Bormann is at Universitaet Bremen TZI, and Handley is at University College London. ๐Ÿงš

Abstract โœจ

This doc explains the messages and procedures for the Negative-ACKnowledgment (NACK) Oriented Reliable Multicast (NORM) protocol ๐Ÿฆ‹ NORM can give you end-to-end reliable transport of bulk data objects or streams over regular IP multicast routing and forwarding, and it's honestly iconic for that ๐Ÿ”ฅ It uses a selective negative acknowledgment mechanism for reliability and has extra features so senders and receivers don't need much a priori coordination ๐Ÿ’…

There's also a specified congestion control scheme, so NORM can fairly share the available network bandwidth with other transport protocols like Transmission Control Protocol (TCP) ๐Ÿ‘‘ It works with both reciprocal multicast routing between senders and receivers, and with asymmetric connectivity, which can mean a unicast return path between them ๐ŸŒˆ The protocol has a bunch of features so different apps, or even other higher-level transport protocols, can use it in different ways ๐Ÿ’œ It also leans on FEC-based (forward error correction) repair and other IETF Reliable Multicast Transport (RMT) building blocks in its design ๐Ÿ“ And yes, this document obsoletes RFC 3940. โญ

Status of This Memo ๐ŸŒธ

This document specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐Ÿซถ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) ๐Ÿ’… Distribution of this memo is unlimited โœจ

Copyright (c) 2009 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿ’–

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. ๐ŸŽ€ Please review these documents carefully, since they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the BSD License. ๐Ÿ”ฅ

This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. ๐Ÿ™ˆ The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English. ๐Ÿ’€

Table of Contents ๐Ÿงš

1.  Introduction and Applicability . . . . . . . . . . . . . . . .  4
  1.1.  Requirements Language  . . . . . . . . . . . . . . . . . .  5
  1.2.  NORM Data Delivery Service Model . . . . . . . . . . . . .  5
  1.3.  NORM Scalability . . . . . . . . . . . . . . . . . . . . .  7
  1.4.  Environmental Requirements and Considerations  . . . . . .  8
2.  Architecture Definition  . . . . . . . . . . . . . . . . . . .  8
  2.1.  Protocol Operation Overview  . . . . . . . . . . . . . . . 10
  2.2.  Protocol Building Blocks . . . . . . . . . . . . . . . . . 12
  2.3.  Design Trade-Offs  . . . . . . . . . . . . . . . . . . . . 12
3.  Conformance Statement  . . . . . . . . . . . . . . . . . . . . 13
4.  Message Formats  . . . . . . . . . . . . . . . . . . . . . . . 15
  4.1.  NORM Common Message Header and Extensions  . . . . . . . . 15
  4.2.  Sender Messages  . . . . . . . . . . . . . . . . . . . . . 18
    4.2.1.  NORM_DATA Message  . . . . . . . . . . . . . . . . . . 18
    4.2.2.  NORM_INFO Message  . . . . . . . . . . . . . . . . . . 28
    4.2.3.  NORM_CMD Messages  . . . . . . . . . . . . . . . . . . 29
  4.3.  Receiver Messages  . . . . . . . . . . . . . . . . . . . . 47
    4.3.1.  NORM_NACK Message  . . . . . . . . . . . . . . . . . . 47
    4.3.2.  NORM_ACK Message . . . . . . . . . . . . . . . . . . . 53
  4.4.  General Purpose Messages . . . . . . . . . . . . . . . . . 55
    4.4.1.  NORM_REPORT Message  . . . . . . . . . . . . . . . . . 55
5.  Detailed Protocol Operation  . . . . . . . . . . . . . . . . . 55
  5.1.  Sender Initialization and Transmission . . . . . . . . . . 57
    5.1.1.  Object Segmentation Algorithm  . . . . . . . . . . . . 58

  5.2.  Receiver Initialization and Reception  . . . . . . . . . . 59
  5.3.  Receiver NACK Procedure  . . . . . . . . . . . . . . . . . 59
  5.4.  Sender NACK Processing and Response  . . . . . . . . . . . 62
    5.4.1.  Sender Repair State Aggregation  . . . . . . . . . . . 62
    5.4.2.  Sender FEC Repair Transmission Strategy  . . . . . . . 63
    5.4.3.  Sender NORM_CMD(SQUELCH) Generation  . . . . . . . . . 64
    5.4.4.  Sender NORM_CMD(REPAIR_ADV) Generation . . . . . . . . 65
  5.5.  Additional Protocol Mechanisms . . . . . . . . . . . . . . 65
    5.5.1.  Group Round-Trip Time (GRTT) Collection  . . . . . . . 65
    5.5.2.  NORM Congestion Control Operation  . . . . . . . . . . 67
    5.5.3.  NORM Positive Acknowledgment Procedure . . . . . . . . 75
    5.5.4.  Group Size Estimate  . . . . . . . . . . . . . . . . . 77
6.  Configurable Elements  . . . . . . . . . . . . . . . . . . . . 77
7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 80
  7.1.  Baseline Secure NORM Operation . . . . . . . . . . . . . . 82
    7.1.1.  IPsec Approach . . . . . . . . . . . . . . . . . . . . 83
    7.1.2.  IPsec Requirements . . . . . . . . . . . . . . . . . . 85
8.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 86
  8.1.  Explicit IANA Assignment Guidelines  . . . . . . . . . . . 87
    8.1.1.  NORM Header Extension Types  . . . . . . . . . . . . . 87
    8.1.2.  NORM Stream Control Codes  . . . . . . . . . . . . . . 88
    8.1.3.  NORM_CMD Message Sub-Types . . . . . . . . . . . . . . 88
9.  Suggested Use  . . . . . . . . . . . . . . . . . . . . . . . . 89
10. Changes from RFC 3940  . . . . . . . . . . . . . . . . . . . . 90
11. Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 91
12. References . . . . . . . . . . . . . . . . . . . . . . . . . . 91
  12.1. Normative References . . . . . . . . . . . . . . . . . . . 91
  12.2. Informative References . . . . . . . . . . . . . . . . . . 92

1. Introduction and Applicability โœจ

Okay, the big picture ๐Ÿ’– NACK-Oriented Reliable Multicast (NORM) can give reliable transport of data from one or more senders to a group of receivers over an IP multicast network ๐Ÿฆ‹ Its main goals are to be efficient, scalable, and robust for bulk data, like computer files or persistent data, across IP networks and topologies that might be heterogeneous ๐Ÿ”ฅ The design supports distributed multicast session participation with minimal coordination between senders and receivers ๐Ÿซถ Senders and receivers can join and leave multicast sessions whenever they want, with minimal overhead for control information and timing synchronization ๐Ÿ’… To make that work, NORM message headers carry some common information, so receivers can easily sync up to senders for the whole life of a reliable multicast session ๐Ÿงš

NORM adapts itself to a wide range of dynamic network conditions with little or no pre-configuration ๐Ÿ‘‘ It's tolerant of inaccurate timing estimates and lossy conditions, which show up a lot in mobile and wireless networks ๐ŸŒˆ It can also converge and keep running efficiently even with heavy packet loss and large queuing or transmission delays ๐Ÿ˜ญ This document obsoletes the Experimental RFC 3940 specification ๐ŸŽ€

This document is a product of the IETF RMT working group, and it follows the guidelines in the Author Guidelines for Reliable Multicast Transport (RMT) Building Blocks and Protocol Instantiation documents [RFC3269] ๐Ÿ’œ

Statement of Intent ๐Ÿ“

This memo has the definitions you need to fully specify a Reliable Multicast Transport protocol under the criteria in IETF Criteria for Evaluating Reliable Multicast Transport and Application Protocols [RFC2357] ๐Ÿ’– The NORM spec in this document was first published in the Experimental Category [RFC3940] ๐ŸŒธ The RMT working group's stated intent was to re-submit this specification as an IETF Proposed Standard in due course ๐Ÿซถ So this Proposed Standard is based on RFC 3940, and it's been updated based on accumulated experience and the protocol's growing maturity since RFC 3940 came out โœจ That experience applies both to this spec and to the congestion control strategies used with it ๐Ÿ”ฅ The differences between RFC 3940 and this document are listed in Section 10 ๐Ÿ’…

1.1. Requirements Language ๐ŸŒˆ

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119] ๐ŸŽ€

1.2. NORM Data Delivery Service Model ๐Ÿ’–

okay so a NORM protocol instance (NormSession) lives in a world where participants send connectionless packets (like IP or UDP) across a network, using addresses and host port numbers that were picked ahead of time ๐Ÿ“ฆ. Usually everyone trades packets through an IP multicast group address, but unicast transport MAY also be set up as an add-on to multicast delivery ๐Ÿฆ‹. For multicast, the participating NormNodes talk over a shared IP multicast group address and port number, and those get chosen through means outside the NormSession itself โœจ. Other existing IETF data format and protocol standards MAY be applied to describe and pass along the a priori information a NormSession needs, like Session Description Protocol (SDP) [RFC4566], Session Announcement Protocol (SAP) [RFC2974], and so on ๐ŸŽ€.

NORM is mainly built around one sender blasting bulk data to a whole group of receivers ๐ŸŒธ. But the protocol MAY operate with multiple senders inside a single NormSession ๐Ÿ’…. In early implementations, senders are expected to transmit independently of each other, and receivers keep state for each sender as needed ๐Ÿงš. In future versions, some parts (round-trip time collection, for example) might get alternate modes that work more efficiently for apps with multiple senders ๐Ÿ”ฅ.

NORM reliably transports three types of bulk data content objects (NormObjects) ๐Ÿ“:

  1. static computer memory data content (NORM_OBJECT_DATA type),
  2. computer storage files (NORM_OBJECT_FILE type), and
  3. non-finite streams of continuous data content (NORM_OBJECT_STREAM type).

The only difference between NORM_OBJECT_DATA and NORM_OBJECT_FILE is a hint for receivers in sessions that serve several kinds of content, telling them whether to allocate memory or file storage for what they receive ๐Ÿ™ˆ. Other than that, they're identical, both giving reliable transport of finite (but possibly huge) units of content ๐Ÿ’œ. These static data and file services are expected to be handy for multicast cache apps that need to reliably move large amounts of static data ๐Ÿ’พ. Other static data or file delivery services might use these object types too ๐ŸŒˆ. The NORM_OBJECT_STREAM type is up to the application, and it could carry static data or files as well ๐Ÿ‘‘. The NORM reliable stream service also opens doors for things like serialized reliable messaging or other unbounded, maybe dynamically produced content โœจ. NORM_OBJECT_STREAM gives reliable transport similar to that of the Transmission Control Protocol (TCP), but NORM receivers can start receiving stream content at any point in time, so how useful that is depends on the application ๐Ÿฆ‹.

NORM also lets a small amount of out-of-band data (sent as NORM_INFO messages) get attached to the data content objects the sender transmits ๐Ÿ“ฌ. This is super handy because it helps multicast receivers quickly and efficiently figure out what kind of data, file, or stream content is coming ๐Ÿ”. It also gives the application control over whether a receiver node keeps participating in the current transport activity ๐ŸŽ›๏ธ. And it keeps things flexible, with very little pre-coordination needed between senders and receivers ๐Ÿซถ. The NORM_INFO content is atomic, which means its size MUST fit into the payload portion of a single NORM message ๐Ÿ“.

NORM does NOT provide global or application-level identification of data content in its message headers ๐Ÿ™…โ€โ™€๏ธ. The NORM_INFO out-of-band mechanism can be used by the application for this if it wants, or identification can be embedded within the data content instead ๐Ÿ’…. NORM does identify transmitted content (NormObjects), using transport identifiers that only apply while the sender is transmitting and/or repairing that object ๐ŸŽ€. These NormTransportIds are assigned in a monotonically increasing fashion by each NORM sender during a NormSession ๐Ÿ“ˆ. Participants, senders included, also get unique identifiers (NormNodeIds) ๐Ÿชช. Each sender keeps its own NormTransportId assignments independently, so a NormObject can be uniquely identified in transit by combining the session-unique sender identifier (NormNodeId) with its assigned NormTransportId ๐Ÿงฉ. NormTransportIds come from a large but fixed numeric space, assigned in increasing order, and they get reassigned during long-lived sessions ๐Ÿ”. NORM also has mechanisms so the sender application can stop transmitting data content and tell the group about it efficiently ๐Ÿ›‘. Other control mechanisms (session termination, receiver synchronization, and so on) are specified too, so reliable multicast app variants can build different complete bulk transfer communication models for their goals ๐Ÿ†.

To sum it all up, NORM gives reliable transport for different types of data content, even mixed types together ๐ŸŒŸ. Senders queue up and transmit bulk content as static data or files, and/or as non-finite, ongoing streams ๐Ÿš€. NORM senders send repair transmissions of data and/or FEC content whenever the receiver group sends NACK messages ๐Ÿ”. Out-of-band info and other transport control mechanisms are specified for applications to put together complete reliable multicast solutions for all sorts of purposes ๐Ÿ’–.

1.3. NORM Scalability โญ

Group communication scalability needs are why NACK-based protocol schemes get adapted whenever feedback is needed for reliability [RmComparison] ๐Ÿ“Š. NORM is centered on selective NACKs to request repairs of missing data ๐ŸŽฏ. It also supports packet-level forward error correction (FEC) techniques for efficient multicast repair, plus OPTIONAL proactive transmission robustness [RFC3453] ๐Ÿ›ก๏ธ. FEC-based repair can greatly reduce the number of reliable multicast repair requests and repair transmissions in a NACK-oriented protocol [MdpToolkit] โœ‚๏ธ. The big factor in NORM's scalability is how much feedback traffic the receiver set generates to support reliability and congestion control ๐Ÿ“ฃ. To handle that, NORM uses probabilistic suppression of redundant feedback, based on exponentially distributed random backoff timers ๐ŸŽฒ. How this suppression performs compared to other techniques is described in [McastFeedback] ๐Ÿ“š. NORM dynamically measures the group's round-trip timing status to set its suppression and other protocol timers โฑ๏ธ. That's what lets NORM scale well while keeping reliable data delivery with low latency, relative to the network topology it runs over ๐ŸŒธ.

Feedback messages can be multicast to the whole group or sent via unicast routing to the sender ๐Ÿ’Œ. With unicast feedback, the sender relays the feedback state to the group so suppression still works ๐Ÿ”„. In typical Internet environments, NORM will readily scale to group sizes on the order of tens of thousands of receivers ๐Ÿฅณ. A study of how much feedback this kind of protocol generates is described in [NormFeedback] ๐Ÿ“ˆ. NORM can operate with less feedback than a single TCP connection, even with relatively large numbers of receivers ๐Ÿ’…. So depending on the network topology, NORM might scale to even larger group sizes ๐Ÿš€. As for computer resource usage, NORM does not need state kept on every receiver in the group ๐Ÿง . NORM senders only maintain state for receivers that provide explicit congestion control feedback ๐Ÿซง. NORM receivers, however, need to maintain state for each active sender, and that can limit how many simultaneous senders some NORM uses can have ๐Ÿšง.

1.4. Environmental Requirements and Considerations ๐ŸŒฟ

Everything that applies to the "Multicast Negative-Acknowledgment (NACK) Building Blocks" [RFC5401], the "Forward Error Correction (FEC) Building Block" [RFC5052], and the "TCP-Friendly Multicast Congestion Control (TFMCC) Protocol Specification" [RFC4654] also applies to NORM ๐Ÿ“‹.

The NORM protocol SHALL be capable of operating end-to-end with no help from intermediate systems beyond basic IP multicast group management, routing, and forwarding services ๐ŸŽ€. The techniques NORM uses are mainly suited to flat, end-to-end IP multicast topologies, but they could also be applied within the sub-levels of hierarchical (e.g., tree-based) multicast distribution if you want ๐ŸŒณ. NORM can use reciprocal (among senders and receivers) multicast communication under the Any-Source Multicast (ASM) model defined in "Host Extensions for IP Multicasting" [RFC1112] ๐Ÿ”. But NORM SHALL also be capable of scalable operation in asymmetric topologies, like Source-Specific Multicast (SSM) [RFC4607], where only unicast routing service is available from the receivers back to the sender(s) ๐Ÿฆ‹.

NORM is compatible with IPv4 and IPv6 ๐ŸŒ. NORM can also be used with networks that employ Network Address Translation (NAT), as long as the NAT device supports IP multicast and/or can cache UDP traffic source port numbers so it can remap feedback traffic from receivers to the sender(s) ๐Ÿ”€โœจ.

2. Architecture Definition โœจ

okay so a NormSession is basically a group chat ๐Ÿ’ฌ made of participants (NormNodes) who can be senders, receivers, or both. NORM senders blast their content out as NormObjects to the session destination address, and NORM receivers try super hard to reliably catch everything, sending negative acknowledgments (NACKs) to ask for repairs ๐Ÿฉน. Each NormNode in a NormSession is assumed to have a preselected unique 32-bit identifier (NormNodeId). NormNodes MUST have uniquely assigned identifiers within a single NormSession so that multiple senders can be told apart and feedback from different receivers doesn't get mixed up ๐Ÿซถ. There are also two reserved NormNodeId values: 0x00000000 is considered an invalid NormNodeId (NORM_NODE_NONE), and 0xffffffff is a "wild card" NormNodeId (NORM_NODE_ANY) ๐ŸŽ€.

The protocol doesn't stop multiple senders from transmitting at the same time inside one NORM session (many-to-many operation, bestie ๐Ÿ’–). But any kind of interactive coordination among NORM senders is assumed to be handled by the application or a higher-protocol layer ๐Ÿงš. There are some OPTIONAL mechanisms in this document that can be used for that application-layer coordination โœจ.

As mentioned before, NORM can reliably send three basic types of data content ๐Ÿฆ‹. The first is NORM_OBJECT_DATA, which is for static, persistent blocks of data kept in the sender's application memory. The second is NORM_OBJECT_FILE, which is data stored in the sender's non-volatile file system ๐Ÿ’พ. NORM_OBJECT_DATA and NORM_OBJECT_FILE both represent NormObjects of finite but potentially very large size ๐Ÿ“ฆ. The third is NORM_OBJECT_STREAM, which is an ongoing transmission of undefined length. It's kind of like the reliable stream service TCP gives you for unicast transport ๐ŸŒŠ. The format of stream content is up to the application and can be "byte" or "message" oriented. NORM also lets you "flush" the stream to speed up delivery or to enforce application message boundaries ๐Ÿšฟ. NORM protocol implementations MAY offer in-order delivery of the stream data to the receive application, or out-of-order (more immediate) delivery of received stream segments to the receiver application, or MAY offer both ๐Ÿ™ˆ. Either way, NORM senders and receivers provide buffering so the stream can be repaired while it's being transported ๐Ÿ’….

All NormObjects are logically split into FEC coding blocks and symbols before the sender transmits them ๐Ÿงฉ. In NORM, a FEC encoding symbol maps directly onto the payload of a NORM_DATA message, which is also called a "segment" ๐Ÿ“. When systematic FEC codes are used, the payload of NORM_DATA messages sent for the first portion of a FEC encoding block are source symbols (actual segments of the original user data). The remaining symbols for that block are parity symbols generated by FEC encoding ๐Ÿ”ฅ. Those parity symbols are generally sent in response to repair requests, but some number MAY be sent proactively at the end of each encoding block to make transmission more robust ๐Ÿ›ก๏ธ. When non-systematic FEC codes are used, every symbol sent is FEC encoding parity content. In that case the receiver needs to receive a sufficient number of symbols to reconstruct the original user data for the block through FEC decoding ๐Ÿง .

Transmitted NormObjects are temporarily, yet uniquely, identified within the NormSession using the sender's NormNodeId, a NormInstanceId, and a temporary NormTransportId ๐Ÿชช. Depending on the implementation, each NORM sender can manage its NormInstanceIds independently. Or a common NormInstanceId could be agreed upon by all participating nodes in a session, if needed, to act as a session identifier ๐Ÿ‘‘. NORM NormTransportId data content identifiers are assigned by the sender and are only applicable and valid during a NormObject's actual transport. That means for as long as the sender is transmitting and providing repair for that NormObject ๐ŸŽฌ. In a long-lived session the NormTransportId field can wrap around, and previously used identifiers will get reused ๐Ÿ”. Also, NORM does not provide globally unique identification of transported data content. If that's needed, it's expected to be managed by the NORM application ๐ŸŒ. The individual segments or symbols of a NormObject are further identified with FEC payload identifiers, which include coding block and symbol identifiers. We'll go deeper into those later in this document ๐Ÿฆ‹.

2.1. Protocol Operation Overview

A NORM sender mainly generates messages of type NORM_DATA ๐Ÿ“จ. These messages carry original data segments or FEC symbols, plus repair segments and symbols, for the bulk data, file, or stream NormObjects being transferred ๐ŸŽ. By default, redundant FEC symbols are only sent in response to receiver repair requests (NACKs), so normally little or no extra transmission overhead comes from FEC encoding ๐Ÿ™Œ. However, the NORM implementation MAY be configured to proactively send some amount of redundant FEC symbols along with the original content. This can potentially improve performance (for example, delay) at the cost of extra transmission overhead โš–๏ธ. This setup makes sense for certain network conditions and can allow for robust, asymmetric multicast (for example, unidirectional routing, satellite, cable) [FecHybrid] with reduced receiver feedback. In some cases, it can even work with no feedback at all ๐Ÿ›ฐ๏ธ.

A sender message of type NORM_INFO is also defined, and it carries OPTIONAL out-of-band context information for a given transport object ๐Ÿ—‚๏ธ. A single NORM_INFO message can be associated with a NormObject. Because it's atomic, missing NORM_INFO messages can be NACKed and repaired with a slightly lower delay than NORM's general FEC-encoded data content โšก. NORM_INFO can be especially useful for bulk transfer and reliable multicast applications where receivers join the group mid-stream and need to figure out context about the content currently being sent ๐Ÿ‘€. The NACK process for NORM_INFO will be described later ๐Ÿ“. When the NORM_INFO message type is used, its transmission SHOULD precede the transmission of any NORM_DATA message for the associated NormObject ๐Ÿƒโ€โ™€๏ธ.

The sender also generates messages of type NORM_CMD to help with protocol operations like congestion control, end-of-transmission flushing, group round-trip time (GRTT) estimation, receiver synchronization, and OPTIONAL positive acknowledgment requests or application-defined commands ๐ŸŽ€. NORM_CMD messages are sent using one of three procedures: a single best-effort unreliable transmission of the command, repeated redundant transmissions of the command, or positively acknowledged commands ๐Ÿ“ฃ. The transmission technique for a given command depends on what that command does. Several core commands are defined for basic protocol operation ๐Ÿ’ช. Implementations MAY also wish to consider providing OPTIONAL application-defined commands, which can take advantage of the transmission methods available for commands ๐Ÿ’…. This lets application-level session management make use of information the underlying NORM protocol engine has, such as round-trip timing and transmission rate ๐Ÿ“Š. One notable difference between NORM_DATA messages and some NORM_CMD messages is that a receiver typically needs to allocate resources to manage reliable reception when it gets NORM_DATA messages. Some NORM_CMD messages are completely atomic, though, and don't need any specific reliability (buffering) state kept ๐Ÿซง. So for session management or other purposes, even participants acting mainly as data receivers MAY transmit NORM_CMD messages. However, it is RECOMMENDED that they don't do this within the context of the NORM multicast session unless congestion control is addressed ๐Ÿšฆ. For example, if lots of receiver nodes send NORM_CMD messages at the same moment, that can cause congestion for the destination(s) ๐Ÿ˜ญ.

All sender transmissions are subject to rate control, governed by a peak transmission rate that the application sets for each participant ๐Ÿšฐ. This can be used to limit the amount of multicast data the group transmits. When NORM's congestion control algorithm is enabled, the sender's rate is adjusted automatically ๐Ÿค–. In some networks it's desirable to set minimum and maximum bounds for that rate adjustment, depending on the application, even when dynamic congestion control is on โš–๏ธ. But on the general Internet, congestion control policy SHALL be observed that is compatible with coexistent TCP flows ๐Ÿซถ.

NORM receivers generate messages of type NORM_NACK or NORM_ACK in response to data and commands from a sender ๐Ÿ’Œ. NORM_NACK messages are generated to request repair of detected data transmission losses. Receivers usually detect losses by tracking the sequence of transmissions from a sender ๐Ÿ•ต๏ธโ€โ™€๏ธ. Sequencing information is embedded in the transmitted data packets and in end-of-transmission commands from the sender. NORM_ACK messages are generated in response to certain commands the sender transmits ๐Ÿ™‹โ€โ™€๏ธ. In the general (and most scalable) protocol mode, NORM_ACK messages are only sent in response to congestion control commands from the sender. The feedback volume of these congestion control NORM_ACK messages is controlled using the same timer-based probabilistic suppression techniques as NORM_NACK messages. This avoids feedback implosion ๐ŸŒŠ. To meet potential application requirements for positive acknowledgment from receivers, other NORM_ACK messages are defined and available for use โœ….

2.2. Protocol Building Blocks

The NORM protocol is based primarily on the concepts in the Multicast NACK Building Block [RFC5401] document ๐Ÿงฑ. That includes the basic NORM architecture and the data transmission, repair, and feedback strategies discussed in that document ๐Ÿ”ง. The reliable multicast building block approach, as described in "Reliable Multicast Transport Building Blocks for One-to-Many Bulk-Data Transfer" [RFC3048], is applied when creating the full NORM protocol instantiation ๐Ÿ—๏ธ. NORM also uses the parity-based encoding techniques for repair messaging and added transmission robustness described in "The Use of Forward Error Correction (FEC) in Reliable Multicast" [RFC3453] ๐Ÿงฌ. NORM uses the FEC Payload ID as specified by the FEC Building Block document [RFC5052] ๐Ÿ†”. And for congestion control, this document fully specifies a baseline congestion control mechanism (NORM-CC) based on the TCP-Friendly Multicast Congestion Control (TFMCC) scheme [TfmccPaper], [RFC4654] ๐ŸŒธ.

2.3. Design Trade-Offs ๐Ÿฆ‹

Okay bestie, the big truth here is that "no one size fits all" ๐Ÿ’… in the reliable multicast transport arena. There are tons of engineering trade-offs in reliable multicast design, so you need to be extra aware of your application and network architecture. The performance stuff that shapes the design includes: group size, heterogeneity (e.g., capacity and/or delay), asymmetric delivery, data ordering, delivery delay, group dynamics, mobility, congestion control, and transport across low-capacity connections. NORM has a bunch of parameters to handle lots of these different needs ๐ŸŽ€. The NORM protocol and its mechanisms MAY be applied in multicast applications outside of bulk data transfer, but there's an assumed model of bulk transfer transport service that drives the trade-offs behind the scalability and performance described in this document โœจ.

Reliability also depends on the buffer constraints of the sender and receiver applications ๐Ÿงš. NORM protocol implementations SHOULD operate with the greatest efficiency and robustness possible within application-defined buffer constraints. Buffer requirements for reliability are, as always, a function of the delay-bandwidth product of the network topology ๐ŸŒธ. NORM performs best when it gets more buffering resources than typical point-to-point transport protocols. The reason is that NORM feedback suppression is based on randomly delayed transmissions from the receiver set, rather than feedback that gets sent immediately โฐ.

There are definite trade-offs between buffer utilization, group size scalability, and efficiency of performance ๐Ÿ’œ. Large buffer sizes let NORM perform most efficiently in large delay-bandwidth topologies and allow for longer feedback suppression backoff timeouts. That yields improved group size scalability ๐ŸŒˆ. NORM can operate with reduced buffering, but it comes at a cost of decreased efficiency (lower relative goodput) and reduced group size scalability ๐Ÿฅฒ.


3. Conformance Statement ๐Ÿ“œ

This RMT Protocol Instantiation document, in conjunction with the "Multicast Negative-Acknowledgment (NACK) Building Blocks" [RFC5401] and "Forward Error Correction (FEC) Building Block" [RFC5052] Building Blocks, completely specifies a working reliable multicast transport protocol that conforms to the requirements described in RFC 2357 ๐Ÿซถ.

This document specifies the following message types and mechanisms that are REQUIRED in complying NORM protocol implementations ๐Ÿ”ฅ:

+----------------------+--------------------------------------------+
| Message Type         | Purpose                                    |
+----------------------+--------------------------------------------+
| NORM_DATA            | Sender message for application data        |
|                      | transmission.  Implementations MUST        |
|                      | support at least one of the                |
|                      | NORM_OBJECT_DATA, NORM_OBJECT_FILE, or     |
|                      | NORM_OBJECT_STREAM delivery services.  The |
|                      | use of the NORM FEC Object Transmission    |
|                      | Information header extension is OPTIONAL   |
|                      | with NORM_DATA messages.                   |
| NORM_CMD(FLUSH)      | Sender command to excite receivers for     |
|                      | repair requests in lieu of ongoing         |
|                      | NORM_DATA transmissions.  Note the use of  |
|                      | the NORM_CMD(FLUSH) for positive           |
|                      | acknowledgment of data receipt is          |
|                      | OPTIONAL.                                  |
| NORM_CMD(SQUELCH)    | Sender command to advertise its current    |
|                      | valid repair window in response to invalid |
|                      | requests for repair.                       |
| NORM_CMD(REPAIR_ADV) | Sender command to advertise current repair |
|                      | (and congestion control state) to group    |
|                      | when unicast feedback messages are         |
|                      | detected.  Used to control/suppress        |
|                      | excessive receiver feedback in asymmetric  |
|                      | multicast topologies.                      |
| NORM_CMD(CC)         | Sender command used in collection of       |
|                      | round-trip timing and congestion control   |
|                      | status from group (this is OPTIONAL if     |
|                      | alternative congestion control mechanism   |
|                      | and round-trip timing collection is used). |
| NORM_NACK            | Receiver message used to request repair of |
|                      | missing transmitted content.               |
| NORM_ACK             | Receiver message used to proactively       |
|                      | provide feedback for congestion control    |
|                      | purposes.  Also used with the OPTIONAL     |
|                      | NORM Positive Acknowledgment Process.      |
+----------------------+--------------------------------------------+

This document also describes the following message types and associated mechanisms that are OPTIONAL for complying NORM protocol implementations ๐Ÿงธ:

+-----------------------+-------------------------------------------+
| Message Type          | Purpose                                   |
+-----------------------+-------------------------------------------+
| NORM_INFO             | Sender message for providing ancillary    |
|                       | context information associated with NORM  |
|                       | transport objects.  The use of the NORM   |
|                       | FEC Object Transmission Information       |
|                       | header extension is OPTIONAL with         |
|                       | NORM_INFO messages.                       |
| NORM_CMD(EOT)         | Sender command to indicate it has reached |
|                       | end-of-transmission and will no longer    |
|                       | respond to repair requests.               |
| NORM_CMD(ACK_REQ)     | Sender command to support                 |
|                       | application-defined, positively           |
|                       | acknowledged commands sent outside of the |
|                       | context of the bulk data content being    |
|                       | transmitted.  The NORM Positive           |
|                       | Acknowledgment Procedure associated with  |
|                       | this message type is OPTIONAL.            |
| NORM_CMD(APPLICATION) | Sender command containing                 |
|                       | application-defined commands sent outside |
|                       | of the context of the bulk data content   |
|                       | being transmitted.                        |
| NORM_REPORT           | Optional message type reserved for        |
|                       | experimental implementations of the NORM  |
|                       | protocol.                                 |
+-----------------------+-------------------------------------------+

4. Message Formats ๐Ÿ’Œ

There are two primary classes of NORM messages (see Section 2.1): sender messages and receiver messages ๐Ÿ“จ. NORM_CMD, NORM_INFO, and NORM_DATA message types are generated by senders of data content, and NORM_NACK and NORM_ACK messages are generated by receivers within a NormSession. Sender messages SHALL be governed by congestion control for Internet use ๐Ÿšฆ. For session management or other purposes, receivers can also employ NORM_CMD message transmissions. The principal rationale for distinguishing sender and receiver messages is that receivers will typically need to allocate resources to support reliable reception from sender(s), and NORM sender messages are subject to congestion control ๐Ÿง . NORM receivers MAY employ the NORM_CMD message type for application-defined purposes, but it is RECOMMENDED that congestion control and feedback implosion issues be addressed ๐Ÿ™ˆ. Additionally, an auxiliary message type of NORM_REPORT is also provided for experimental purposes ๐Ÿงช.

This section describes the message formats used by the NORM protocol ๐ŸŽ€. These messages and their fields are referenced in the detailed functional description of the NORM protocol given in Section 5. Individual NORM messages are compatible with the Maximum Transmission Unit (MTU) limitations of encapsulating Internet protocols, including IPv4, IPv6, and UDP ๐ŸŒŠ. The current NORM protocol specification assumes UDP encapsulation and leverages the transport features of UDP. The NORM messages are independent of network addresses and can be used in IPv4 and IPv6 networks ๐Ÿฆ‹.

4.1. NORM Common Message Header and Extensions โœจ

Okay bestie, every NORM message starts with the same common header ๐Ÿซถ It's like an ID badge at the door. There's also a header extension mechanism, so NORM can level up its features without rewriting this whole doc ๐Ÿ’… Every NORM protocol message begins with a common header that has these fields:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version|  type |    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 1: NORM Common Message Header Format

The version field is a 4-bit value with the protocol version number. NORM implementations SHOULD ignore received messages with version numbers different from their own. This number is there to mark and tell apart upgrades that aren't interoperable ๐Ÿ™ˆ The NORM version number for this specification is 1.

The message type field is a 4-bit value that tells you which NORM protocol message type you're looking at. The types go like this:

                  +------------------+------------------+
                  | Message          |       Value      |
                  +------------------+------------------+
                  | NORM_INFO        |         1        |
                  | NORM_DATA        |         2        |
                  | NORM_CMD         |         3        |
                  | NORM_NACK        |         4        |
                  | NORM_ACK         |         5        |
                  | NORM_REPORT      |         6        |
                  +------------------+------------------+

The 8-bit hdr_len field says how many 32-bit words make up that message's header portion. This is what makes header extensions possible ๐Ÿงš Extensions are implied whenever the hdr_len value is bigger than the base value for that message type.

The sequence field is a 16-bit value that the message originator sets. It has two jobs, depending on the message type:

  1. NORM senders MUST set the sequence field of sender messages (NORM_INFO, NORM_DATA, and NORM_CMD) so receivers can watch it and estimate packet loss for congestion control purposes (see Section 5.5.2 for a detailed description of NORM Congestion Control operation). A monotonically increasing sequence number space MUST be maintained to mark NORM sender messages in this way. Heads up: this sequence number is explicitly not used in NORM's reliability procedures. The NORM object and FEC payload identifiers handle detecting missing content for reliable transfer ๐Ÿ”ฅ
  2. NORM receivers SHOULD set the sequence field to support protection from message replay attacks of NORM_NACK or NORM_NACK messages. Depending on configuration, NORM feedback messages go to the session multicast address or the unicast address(es) of the active NORM sender(s). So a separate, monotonically increasing sequence number space MUST be maintained for each destination address the NORM receiver sends feedback to ๐Ÿ‘‘

Those two jobs need separate sequence spaces to do their thing. And for NORM receivers, extra sequence spaces are needed when feedback goes to the sender unicast address(es) instead of the session address ๐ŸŒธ

The source_id field is a 32-bit value that uniquely identifies the node that sent the message within a single NormSession. It's called the NORM node identifier (NormNodeId), and unique NormNodeIds MUST be assigned within a single NormSession. Using the host IPv4 address or a hash of an address can work in some cases, but alternative ways of assigning node identifiers, and of resolving collisions inside a multicast session, SHOULD be considered ๐Ÿฆ‹ For example, the techniques for managing the 32-bit "synchronization source" (SSRC) identifiers defined in the Real-Time Protocol (RTP) specification [RFC3550] also work for NORM node identifiers when an ASM traffic model is in play. In most NORM deployments so far, NormNodeId assignments are set up by an administrator, and this form of NormNodeId assignment is RECOMMENDED for most purposes โœจ NORM sender NormNodeId values MUST be unique within an ASM session so senders can properly demultiplex NORM receiver feedback. NORM receiver NormNodeId values MUST also be unique for congestion control operation, or when the OPTIONAL positive acknowledgment mechanism is used ๐Ÿ’œ

NORM Header Extensions

When header extensions are applied, they go right after the message type's base header and come before any payload portion. There are two formats for header extensions, and both start with an 8-bit het (header extension type) field. The variable-length format is for het values from 0 through 127. The fixed-length format is one 32-bit word, for het values from 128 through 255 ๐ŸŽ€

For variable-length extensions, the hel (header extension length) field is the length of the entire header extension, counted in 32-bit words. The hel field MUST be present for variable-length extensions (het between 0 and 127) and MUST NOT be present for fixed-length extensions (het between 128 and 255) ๐Ÿ’…

Here's what the two formats look like:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   het <=127   |      hel      |                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
     |                    Header Extension Content                   |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 2: NORM Variable-Length Header Extension Format

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   het >=128   |    reserved   |    Header Extension Content   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 3: NORM Fixed-Length (32-bit) Header Extension Format

Each header extension type defines its own "Header Extension Content" portion. A few extensions are defined in this document for NORM's baseline FEC and congestion control operations ๐ŸŒˆ

4.2. Sender Messages โœจ

NORM sender messages cover the NORM_DATA type, the NORM_INFO type, and the NORM_CMD type. NORM_DATA and NORM_INFO messages carry application data content, while NORM_CMD messages handle various protocol control functions ๐Ÿ“

4.2.1. NORM_DATA Message ๐Ÿฆ‹

The NORM_DATA message is generally the most common type that NORM senders transmit. These messages wrap up segmented data content for objects of type NORM_OBJECT_DATA, NORM_OBJECT_FILE, and NORM_OBJECT_STREAM. NORM_DATA messages carry either original or FEC-encoded application data content ๐Ÿซถ

A NORM_DATA message has three logical portions: 1) a fixed-format NORM_DATA header portion, 2) a FEC Payload ID portion whose format depends on the FEC encoding used, and 3) a payload portion with source or encoded application data content. For objects of type NORM_OBJECT_STREAM, the payload portion also has extra fields that let receivers recover stream content properly. NORM implementations MAY also extend the NORM_DATA header with a FEC Object Transmission Information (EXT_FTI) header extension. This lets NORM receivers allocate resources and do FEC decoding automatically, with no pre-configuration or out-of-band information needed โœจ

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=2|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |     flags     |    fec_id     |     object_transport_id       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         fec_payload_id                        |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                header_extensions (if applicable)              |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          payload_len*         |       payload_msg_start*      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                        payload_offset*                        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          payload_data*                        |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 4: NORM_DATA Message Format

IMPORTANT NOTE: The payload_len, payload_msg_start and payload_offset fields are present only for objects of type NORM_OBJECT_STREAM. These fields, just like the entire payload, are subject to any FEC encoding used. So when systematic FEC codes are used, these values can be directly interpreted only for packets containing source symbols, while packets containing FEC parity content need decoding before these fields can be interpreted ๐Ÿ™ˆ

The version, type, hdr_len, sequence, and source_id fields form the NORM common message header, as described in Section 4.1. The value of the NORM_DATA type field is 2. The NORM_DATA base hdr_len value is 4 (that's four 32-bit words) plus the size of the fec_payload_id field. The size of fec_payload_id depends on the FEC encoding type referenced by the fec_id field. For example, when small block, systematic codes are used, a fec_id value of 129 is indicated, and the size of fec_payload_id is two 32-bit words. In that case, the NORM_DATA base hdr_len value is 6. The cumulative size of any header extensions applied gets added into the hdr_len field ๐Ÿ’–

The instance_id is a value the sender makes up itself to say "this is my current run in the session" ๐Ÿฆ‹ That's how receivers can tell when a sender bounced out and rejoined a session that was already going ๐Ÿ‘€ When a sender (spotted by its source_id) shows up with a new instance_id, NORM receivers SHOULD drop their previous state on that sender and start receiving fresh, or at least treat this instance as a new, separate sender ๐Ÿ’…

The grtt field is a non-linear quantized version of the sender's current estimate of group round-trip time (GRTT_sender), also called R_max in [TfmccPaper] ๐ŸŒธ The receivers use it to time the NACK repair process and a bunch of other stuff ๐Ÿงš Usually the advertised grtt matches what the sender measured from group feedback, but at low transmission rates the advertised grtt SHALL be set to MAX(grttMeasured, NormSegmentSize/senderRate), where NormSegmentSize is the sender's segment size in bytes and senderRate is its current transmission rate in bytes per second โœจ The encoding and decoding algorithm for this field lives in the Multicast NACK Building Block [RFC5401] document, so go check it out ๐Ÿ“š

The backoff field tells receivers the maximum backoff timer value for timer-based NORM NACK feedback suppression ๐Ÿ”ฅ It's a 4-bit field that supports values from 0-15, and each value gets multiplied by GRTT_sender to get that max backoff timeout ๐ŸŽ€ It basically tells receivers the sender's backoff factor parameter (K_sender). The Recommended values and what they're used for are described in the NORM receiver NACK procedure in Section 5.3 ๐Ÿซถ

The gsize field is the sender's current estimate of group size (GSIZE_sender) ๐Ÿ’– It's 4 bits and can roughly represent values from ten to 500 million. The most significant bit is the mantissa switch: 0 means a mantissa of 1, and 1 means a mantissa of 5. The three least significant bits, incremented by one, give you a base-10 exponent (order of magnitude) ๐Ÿงฎ Some examples so you can see the vibe:

  • 0x0 is 1.0e+01 (10) ๐Ÿ“
  • 0x8 is 5.0e+01 (50) ๐ŸŒˆ
  • 0x1 is 1.0e+02 (100) โญ
  • 0xf is 5.0e+08 ๐Ÿ”ฅ

For NORM feedback suppression, the group size doesn't need to be super precise ๐Ÿ’… The group size MAY even be estimated a bit conservatively (aka overestimated) to keep feedback traffic low ๐Ÿฆ‹ A default group size estimate of 10,000 (gsize = 0x3) is RECOMMENDED for general purpose reliable multicast apps using NORM ๐Ÿ’œ

The flags field holds a bunch of binary flags that give the receiver info and hints for handling the object it identifies ๐ŸŽ€ These are the defined flags:

+----------------------+-------+------------------------------------+
| Flag                 | Value | Purpose                            |
+----------------------+-------+------------------------------------+
| NORM_FLAG_REPAIR     |  0x01 | Indicates message is a repair      |
|                      |       | transmission                       |
| NORM_FLAG_EXPLICIT   |  0x02 | Indicates a repair segment         |
|                      |       | intended to meet a specific        |
|                      |       | receiver erasure, as compared to   |
|                      |       | parity segments provided by the    |
|                      |       | sender for general purpose (with   |
|                      |       | respect to a FEC coding block)     |
|                      |       | erasure filling.                   |
| NORM_FLAG_INFO       |  0x04 | Indicates availability of          |
|                      |       | NORM_INFO for object.              |
| NORM_FLAG_UNRELIABLE |  0x08 | Indicates that repair              |
|                      |       | transmissions for the specified    |
|                      |       | object will be unavailable         |
|                      |       | (one-shot, best-effort             |
|                      |       | transmission).                     |
| NORM_FLAG_FILE       |  0x10 | Indicates object is file-based     |
|                      |       | data (hint to use disk storage for |
|                      |       | reception).                        |
| NORM_FLAG_STREAM     |  0x20 | Indicates object is of type        |
|                      |       | NORM_OBJECT_STREAM.                |
+----------------------+-------+------------------------------------+

NORM_FLAG_REPAIR gets set when the message is a repair transmission ๐Ÿ” Receivers can use it to follow a join policy where newly joining receivers only start taking part in the NACK process once they've seen new (non-repair) data content ๐Ÿ‘€ NORM_FLAG_EXPLICIT marks repair messages sent after the data sender has run out of "fresh" (not previously transmitted) parity segments to use as repair ๐Ÿงฉ Intermediate systems could possibly use this flag to control sub-casting of repair content to different legs of a reliable multicast topology with different repair needs ๐ŸŒ NORM_FLAG_INFO is set only when OPTIONAL NORM_INFO content is actually available for the object, so receivers only NACK for NORM_INFO retransmission when it exists ๐Ÿ™ˆ NORM_FLAG_UNRELIABLE is for when the sender wants "best effort" delivery and won't provide repair transmissions for the object ๐Ÿ’€ NORM receivers SHOULD NOT execute repair requests for objects marked with NORM_FLAG_UNRELIABLE. Still, receivers can accidentally request repair for these objects if they don't get all the segments (or info content), which shows up as a gap in the object_transport_id sequence ๐Ÿ˜ญ When that happens, the sender SHALL invoke the NORM_CMD(SQUELCH) process, as described in Section 4.2.3 ๐Ÿซถ NORM_FLAG_FILE can be set as a hint that the object SHOULD be stored in non-volatile storage ๐Ÿ’พ NORM_FLAG_STREAM is set when the object is of type NORM_OBJECT_STREAM. If NORM_FLAG_STREAM is present, it overrides NORM_FLAG_FILE when it comes to interpreting object size and the format of NORM_DATA messages ๐Ÿ‘‘

The fec_id field matches the FEC Encoding Identifier from the FEC Building Block document [RFC5052] ๐Ÿง The fec_id value implies the format of the fec_payload_id field and, together with FEC Object Transmission Information, tells you how to decode FEC-encoded content ๐Ÿ” Small block, systematic codes (fec_id = 129) are expected to be used for most NORM purposes, and systematic FEC codes are RECOMMENDED for the most efficient NORM_OBJECT_STREAM transport ๐Ÿš€

The object_transport_id field is a monotonically and incrementally increasing value the sender assigns to the NormObjects it transmits ๐Ÿฆ‹ Transmissions and repair requests for that object all use the same object_transport_id value. In sessions of very long or indefinite duration, the field will wrap and repeat, but the 16-bit field is presumed to give enough sequence space to avoid object confusion between receivers and sources. Receivers SHOULD re-synchronize with a server when they get object sequence identifiers that are way out of range with the current state kept for a given source ๐Ÿ”„ During its transmission within a NORM session, an object is uniquely identified by the combo of the sender's source_id and the given object_transport_id ๐Ÿ’œ Also, NORM_INFO messages linked to the identified object carry the same object_transport_id value โœจ

The fec_payload_id identifies the attached NORM_DATA payload content ๐ŸŽ€ Its size and format depend on the FEC type indicated by the fec_id field. These formats are given in the descriptions of specific FEC schemes, like the ones in the FEC Basic Schemes [RFC5445] specification, or in other FEC Schemes ๐Ÿ“– As an example, here's the format of the fec_payload_id for Small Block, Systematic codes (fec_id = 129) from the FEC Basic Schemes [RFC5445] specification:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       source_block_number                     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        source_block_len       |      encoding_symbol_id       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      Figure 5: Example: FEC Payload Id Format for 'fec_id' = 129

Okay bestie, so this bit is about how the FEC payload ID works ๐Ÿฆ‹ The source_block_number, source_block_len, and encoding_symbol_id fields line up with the "Source Block Number", "Source Block Length", and "Encoding Symbol ID" fields of the FEC Payload ID format for Small Block Systematic FEC Schemes, which is the one with fec_id value 129 from the FEC Basic Schemes [RFC5445] spec ๐Ÿ’œ The source_block_number tells you where the coding block sits within a NormObject. Heads up: for NormObjects of type NORM_OBJECT_STREAM, the source_block_number will wrap around in very long-lived sessions ๐Ÿ™ˆ

The source_block_len tells you how many user data segments are in the block you're looking at. Once you know how many symbols of app data are in there, the receiver can tell whether the attached segment is data or parity and handle it properly โœจ Applications MAY dynamically "shorten" code blocks when the pending information content isn't predictable, like with real-time message streams ๐ŸŒธ When that happens, the source_block_len value given for an encoding_symbol_id that holds FEC parity content SHALL take precedence over the source_block_len value given for any packets holding source symbols. Also, the source_block_len value given for an ordinally higher encoding_symbol_id SHALL take precedence over the source_block_len given for earlier encoding symbols. Why? The sender only knows the maximum source block length while it's sending source symbols, and then it "shortens" the code later and sends that last source symbol and/or the encoding symbols with FEC parity content. Makes sense, right? ๐Ÿงš

The encoding_symbol_id says which specific symbol (segment) inside the coding block the payload carries ๐Ÿ’… Depending on that value and the block's source_block_len, the segment is either user data or a FEC parity segment. For systematic codes, encoding symbols numbered less than source_block_len hold the original application data, while segments greater than or equal to source_block_len hold parity symbols calculated for the block ๐ŸŽ€ Put object_transport_id::fec_payload_id together and you get a unique transport protocol data unit identifier for the attached segment, relative to the NORM sender's instance within a session. Iconic. ๐Ÿ‘‘

You also need extra FEC Object Transmission Information (FTI) (as described in the FEC Building Block [RFC5052] document) to properly receive and decode NORM transport objects ๐Ÿ˜ญ That info MAY be given as out-of-band session information. Sometimes it's really helpful for the sender to send it "in-band" too, so receivers don't need a ton of pre-configuration ๐Ÿซถ That's what the NORM FEC Object Transmission Information Header Extension (EXT_FTI) is for. This header extension MAY be applied to NORM_DATA and NORM_INFO messages to carry that necessary info. The EXT_FTI has two parts: a general part that holds the size of the associated transport object, and a part that depends on the FEC scheme in use. The fec_id field in NORM_DATA and NORM_INFO messages tells you which FEC scheme it is. Here's the general part:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    het = 64   |    hel = 4    |       object_size (msb)       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       object_size (lsb)                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                  FEC scheme-specific content ...              |

Figure 6: EXT_FTI Header Extension General Portion Format

The het value for the EXT_FTI header extension is 64 ๐ŸŒˆ The hel value depends on the FTI format for the encoding type named by the fec_id field.

The 48-bit object_size field is the total length of the object (in bytes) for the static object types NORM_OBJECT_FILE and NORM_OBJECT_DATA ๐Ÿ“ฆ Receivers use it to figure out how much storage they need and/or to allocate space for the incoming object. A receiver with not much storage might wish to skip reliable reception (meaning, not NACK for) of that object ๐Ÿ™ˆ For NORM_OBJECT_STREAM objects, the sender uses object_size to advertise the size of its stream buffer to the receiver group. Then receivers SHOULD use that number to allocate a stream buffer of the matching size ๐Ÿ’–

As I said, the extension format depends on the FEC code in use, but in general it has whatever details about that code are needed (for example, FEC Instance ID, etc.). For example, here's the EXT_FTI for small block systematic codes (fec_id = 129):

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    het = 64   |    hel = 4    |       object_size (msb)       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       object_size (lsb)                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |       fec_instance_id         |          segment_size         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |       fec_max_block_len       |         fec_num_parity        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 7: Example: EXT_FTI Header Extension Format for 'fec_id' = 129

In this example (where fec_id = 129), the hel value is 4 ๐ŸŽ€ The EXT_FTI could be a different size for other FEC schemes, so don't assume it's always 4. The 48-bit object_size works exactly the same as I explained above ๐Ÿ’…

The fec_instance_id matches the "FEC Instance ID" from the FEC Building Block [RFC5052] document. Here it's a value for the specific kind of Small Block Systematic Code being used (for example, Reed-Solomon GF(2^8), Reed-Solomon GF(2^16), etc.). The standard assignments for FEC Instance ID values are described in RFC 5052 ๐Ÿ“š

The segment_size field is the sender's current setting for maximum message payload content (in bytes). It helps receivers allocate the right buffering and work out other stuff they need to process the incoming data messages properly โœจ FEC parity symbol segments are typically this size ๐Ÿฆ‹

The fec_max_block_len is the current maximum number of user data segments per FEC coding block that the sender will use during the session. It lets receivers reserve enough buffer space for blocks coming from the sender ๐Ÿซง

The fec_num_parity matches the "maximum number of encoding symbols that can be generated for any source block" from FEC Object Transmission Information for Small Block Systematic Codes, as described in the FEC Building Block [RFC5052] document ๐Ÿง  Reed-Solomon codes can be arbitrarily shortened to make different code variations for a given block length, so it's a whole thing. For Reed-Solomon codes (GF(2^8) and GF(2^16)), this value is the maximum number of parity segments the sender has available for the coding blocks. This field MAY be interpreted differently for other systematic codes as they get defined ๐ŸŒธ

The payload part of NORM_DATA messages carries source data or FEC-encoded application content. What's in there depends on the FEC scheme being used, and if you're streaming with the NORM_OBJECT_STREAM type, the payload needs a little extra stuff too ๐Ÿ’œ

The payload_len, payload_msg_start, and payload_offset fields only show up for transport objects of type NORM_OBJECT_STREAM ๐ŸŒŠ These REQUIRED fields let senders vary the size of NORM_DATA payload segments for streams, so apps can flush streamed data whenever they need to for their own streaming requirements ๐Ÿ“ For NORM_OBJECT_FILE and NORM_OBJECT_DATA objects, these fields aren't needed, because the receiver can work out the payload length and offset from the fec_payload_id using the REQUIRED block partitioning algorithm in the FEC Building Block [RFC5052] document ๐Ÿงฎ When systematic FEC codes (for example, fec_id = 129) are used, the payload_len, payload_msg_start, and payload_offset fields hold the actual payload_data length, the message start index (or stream control code), and the byte offset for the application stream data segment (the rest of the payload_data field), in NORM_DATA messages that carry source data symbols. In NORM_DATA messages with FEC parity content, these fields don't hold values you can read directly. They're computed by FEC-encoding the payload_len, payload_msg_start, and payload_offset fields of the source data segments in the corresponding coding block. Once a FEC coding block is decoded, the real payload_msg_start, payload_len, and payload_offset values for missing data can be found ๐Ÿ” Note that these fields do NOT count toward the NORM_DATA hdr_len field. They're only present when the flags part of the NORM_DATA message says the transport object is NORM_OBJECT_STREAM ๐Ÿ’€

The payload_len value, when it's non-zero, is the length (in bytes) of the source content in the matching payload_data field. But when payload_len equals ZERO, the payload_msg_start field gets read as a stream_control_code instead ๐Ÿซถ The only stream_control_code value defined so far is NORM_STREAM_END = 0. NORM_STREAM_END tells you the sender is ending the stream at that spot, and the receiver MUST NOT expect any content (or ask for repair of any content) after that position in the stream ๐Ÿ›‘ Additional specifications MAY extend the NORM stream transport mode by defining more stream control codes. Those control codes get delivered to the receiving application reliably, in order with the streamed application data ๐ŸŽ‰

Okay so, payload_msg_start has two jobs, and they can't happen at the same time ๐ŸŽ€. When payload_len is non-zero, a non-zero payload_msg_start says the payload_data has an application-defined message boundary (start-of-message) inside it ๐Ÿ’…. The first byte of that application message sits at an offset of payload_msg_start - 1 bytes into payload_data. So if a NORM_DATA payload for a NORM_OBJECT_STREAM starts a new application message right at the first byte of payload_data, then payload_msg_start is 1 โœจ. NORM implementations SHOULD give sender stream applications a way to mark message boundaries like this ๐Ÿ”ฅ. Receivers, on the other hand, SHOULD let their application recover that boundary info ๐Ÿซถ. Why? Because it lets NORM receivers "synchronize" reliable reception of the stream in a way that actually makes sense to the app, whether they joined a session that's already going or they left and came back ๐Ÿฆ‹. And if payload_msg_start is ZERO, there's no boundary at all ๐Ÿ™ˆ. Also, payload_msg_start is always less than or equal to payload_len, EXCEPT when payload_len = 0. In that special case it gets read as a stream_control_code instead ๐Ÿ’€.

The payload_offset field is the relative byte position (counted from where the sender stream transmission started) of the source content inside payload_data ๐ŸŒธ. Heads up: for long-lived streams, payload_offset wraps around ๐ŸŒˆ.

The payload_data field holds the original application source content or parity content for the symbol named by fec_payload_id ๐Ÿงš. Its length SHALL be capped at the sender's NormSegmentSize bytes, as given in the FTI for the object ๐Ÿ’–. Parity messages always have a payload_data length of NormSegmentSize ๐Ÿ“. When segments come in different sizes, the FEC encoder SHALL assume ZERO-value padding for any data segment shorter than NormSegmentSize ๐Ÿง. It is RECOMMENDED that a sender's NormSegmentSize stay pretty much constant for the whole time that sender is participating in the session, though it can change per object ๐ŸŽ€. The NormSegmentSize SHOULD be configurable by the sender application before it joins the session, so it can match network topology MTU considerations โญ. For IPv6, MTU discovery MAY possibly be used at session startup to set this up ๐Ÿ›ฐ๏ธ. The payload_data content MAY be handed straight to the application for source symbols (when systematic FEC encoding is used), or once the FEC block has been decoded ๐Ÿ‘‘. For NORM_OBJECT_FILE and NORM_OBJECT_STREAM objects, you can work out the data segment length and offset with the block partitioning algorithm from the FEC Building Block [RFC5052] document ๐Ÿฆ‹. For NORM_OBJECT_STREAM objects specifically, the length and offset come from the segment's embedded payload_len and payload_offset fields ๐Ÿ’œ.

4.2.2. NORM_INFO Message โœจ

The NORM_INFO message carries OPTIONAL, application-defined, out-of-band context info for transmitted NormObjects ๐ŸŒŸ. A great example for bulk file transfer is putting the MIME type of the file, data, or stream object into the NORM_INFO payload ๐Ÿ“‚. Receivers can then peek at that NORM_INFO content and decide whether they even want to join in on reliable reception of the object ๐Ÿ‘€. Each NormObject can have its own unit of NORM_INFO attached to it ๐Ÿงฉ. NORM_DATA messages have a flag that tells you whether NORM_INFO is available for a given NormObject ๐Ÿšฉ. If a receiver hasn't gotten the NORM_INFO for a NormObject, it will NACK for a retransmission of it ๐Ÿ™. The NORM_INFO content is limited to the size of a single NormSegmentSize for that sender ๐Ÿ“. Because it's this small and atomic, NORM_INFO can be repaired quickly and efficiently inside the NORM reliable transmission process ๐Ÿ’จ.

When NORM_INFO content is available for a NormObject, the NORM_FLAG_INFO flag SHALL be set in NORM_DATA messages for the matching object_transport_id, and the NORM_INFO message SHALL be sent as the very first message for that NormObject ๐Ÿ”ฅ.

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |version| type=1|    hdr_len    |          sequence             |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                           source_id                           |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |          instance_id          |     grtt      |backoff| gsize |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |     flags     |     fec_id    |     object_transport_id       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                header_extensions (if applicable)              |
  |                              ...                              |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                         payload_data                          |
  |                              ...                              |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 8: NORM_INFO Message Format

The version, type, hdr_len, sequence, and source_id fields make up the NORM common message header, as described in Section 4.1 ๐Ÿงพ. When there are no header extensions, hdr_len is 4 ๐Ÿ“.

The instance_id, grtt, backoff, gsize, flags, fec_id, and object_transport_id fields carry the same info and do the same job as they do in NORM_DATA messages ๐ŸŽ€. They let the receiver get its buffers and everything else ready for whatever the sender sends next, if NORM_INFO is the first thing it receives ๐Ÿ—๏ธ.

Just like with NORM_DATA messages, the NORM FTI Header Extension (EXT_FTI) MAY be optionally applied to NORM_INFO messages ๐Ÿงฉ. To keep the overhead down, NORM implementations MAY apply EXT_FTI to NORM_INFO messages only, and not to NORM_DATA messages ๐Ÿฆ‹.

The NORM_INFO payload_data field holds sender application-defined content, which receiver applications can use for the purposes described above ๐Ÿ’œ.

4.2.3. NORM_CMD Messages โœจ

okay bestie, NORM_CMD messages are the sender's multitool ๐Ÿงฐ๐Ÿ’… Senders send them to do a bunch of different protocol jobs: collecting round-trip timing, running congestion control, syncing up the sender's and receivers' repair "windows" ๐ŸชŸ, and letting everyone know how the sender is doing. There's a core set of these that's officially listed, and there's also a range of command types left open for applications to use however they want ๐Ÿฆ‹. Some NORM_CMD types can carry dynamic content too, but that content is capped at the sender's NormSegmentSize, so each command stays atomic and doesn't get split up ๐Ÿซถ

Every NORM_CMD message starts with the usual NORM common message header, followed by a shared set of standard fields. Here's the layout:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |version| type=3|    hdr_len    |          sequence             |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           source_id                           |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |          instance_id          |     grtt      |backoff| gsize |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |    sub-type   |                                               |
    +-+-+-+-+-+-+-+-+        NORM_CMD Content                       +
    |                              ...                              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 9: NORM_CMD Standard Fields

So the version, type, hdr_len, sequence, and source_id fields are the NORM common message header from Section 4.1 ๐ŸŽ€ The hdr_len value for NORM_CMD messages without header extensions depends on the sub-type field, so keep that in mind, babe ๐Ÿ‘€

The instance_id, grtt, backoff, and gsize fields do the same job they do in NORM_DATA and NORM_INFO messages ๐Ÿ” And then there's sub-type, which tells you what kind of command is coming next. Whatever's after it depends entirely on that sub-type. Here are the NORM_CMD sub-types:

+-----------------------+----------+--------------------------------+
| Command               | Sub-type | Purpose                        |
+-----------------------+----------+--------------------------------+
| NORM_CMD(FLUSH)       |     1    | Used to indicate sender        |
|                       |          | temporary end-of-transmission. |
|                       |          | (Assists in robustly           |
|                       |          | initiating outstanding repair  |
|                       |          | requests from receivers).  May |
|                       |          | also be optionally used to     |
|                       |          | collect positive               |
|                       |          | acknowledgment of reliable     |
|                       |          | reception from a subset of     |
|                       |          | receivers.                     |
| NORM_CMD(EOT)         |     2    | Used to indicate sender        |
|                       |          | permanent end-of-transmission. |
| NORM_CMD(SQUELCH)     |     3    | Used to advertise sender's     |
|                       |          | current repair window in       |
|                       |          | response to out-of-range NACKs |
|                       |          | from receivers.                |
| NORM_CMD(CC)          |     4    | Used for GRTT measurement and  |
|                       |          | collection of congestion       |
|                       |          | control feedback.              |
| NORM_CMD(REPAIR_ADV)  |     5    | Used to advertise sender's     |
|                       |          | aggregated repair/feedback     |
|                       |          | state for suppression of       |
|                       |          | unicast feedback from          |
|                       |          | receivers.                     |
| NORM_CMD(ACK_REQ)     |     6    | Used to request                |
|                       |          | application-defined positive   |
|                       |          | acknowledgment from a list of  |
|                       |          | receivers (OPTIONAL).          |
| NORM_CMD(APPLICATION) |     7    | Used for application-defined   |
|                       |          | purposes that need to          |
|                       |          | temporarily preempt or         |
|                       |          | supplement data transmission   |
|                       |          | (OPTIONAL).                    |
+-----------------------+----------+--------------------------------+

Quick vibe check: FLUSH (sub-type 1) is the "hey, I'm pausing for a sec" move that helps receivers kick off any repair requests they're still waiting on ๐Ÿ™Œ EOT (sub-type 2) is the permanent "I'm done, bye" ๐Ÿ‘‹ SQUELCH (sub-type 3) is how the sender shows its current repair window when receivers send NACKs that are out of range ๐ŸชŸ CC (sub-type 4) handles GRTT measurement and congestion control feedback ๐Ÿ“ˆ REPAIR_ADV (sub-type 5) shares the sender's aggregated repair and feedback state so receivers don't all flood unicast feedback ๐ŸŒŠ And ACK_REQ (sub-type 6) plus APPLICATION (sub-type 7) are both OPTIONAL ๐Ÿ’œ ACK_REQ asks a list of receivers for an application-defined positive acknowledgment, and APPLICATION is for app-specific stuff that needs to temporarily preempt or supplement the data flow โœจ

4.2.3.1. NORM_CMD(FLUSH) Message โœจ

okay bestie, so NORM_CMD(FLUSH) is what the sender sends once it hits the end of all the data content and pending repairs it queued up for transmission ๐Ÿ“ญ. It can mean a temporary OR a permanent end of data, but the sender is still totally willing to answer repair requests ๐Ÿซถ. This command gets repeated once per 2*GRTT_sender to excite the receiver set, meaning it pokes them to check for outstanding repair requests up to and including the transmission point in the NORM_CMD(FLUSH) message ๐Ÿฆ‹. The number of repeats equals NORM_ROBUST_FACTOR, unless you've got a list of receivers that owe an explicit positive acknowledgment (acking_node_list). In that case, the acking_node_list gets updated as acknowledgments roll in, and the flush is repeated using the mechanism in Section 5.5.3 ๐Ÿ”ฅ. The bigger the NORM_ROBUST_FACTOR, the better the odds that every applicable receiver gets excited for acknowledgment or repair requests (NACKs) AND that those NACKs actually reach the sender ๐Ÿ’…. A default NORM_ROBUST_FACTOR of 20 is RECOMMENDED ๐ŸŒˆ. If a NORM_NACK message interrupts the flush process, the sender SHALL re-initiate the flush once any resulting repair transmissions are finished ๐Ÿ”.

Quick note: receivers have their own timeout too ๐Ÿ™ˆ. If they hear nothing from a sender (no messages of any type), they self-start NACKing when they still have repairs pending. This inactivity timeout is tied to NORM_CMD(FLUSH) and NORM_ROBUST_FACTOR, and it's spelled out in Section 5.3. Receivers SHALL self-initiate the NACK repair process once that inactivity timeout has expired for a specific sender AND they still need repairs from that sender. With a big enough NORM_ROBUST_FACTOR, data content gets delivered with a high level of assurance ๐Ÿซง. The catch is that a big NORM_ROBUST_FACTOR means potentially sending a bunch of extra NORM_CMD(FLUSH) messages, plus a longer inactivity timeout before receivers self-start the terminal NACK process ๐Ÿ˜ญ.

For finite-sized transport objects like NORM_OBJECT_DATA and NORM_OBJECT_FILE, the flush (as long as there are no more pending objects) happens at the end of the object. So FEC repair information is always there when repairs get requested in response to the flush command ๐Ÿงš. NORM_OBJECT_STREAM is a different story, though ๐Ÿ‘€. There, the flush can happen at any time, including in the middle of a FEC coding block if systematic FEC codes are in use. The sender then can't provide FEC parity content for the concurrent coding block yet, so it's limited to explicitly repairing the stream with source data content for that block.

Heads up: if your app flushes a stream a lot, it SHOULD be judicious about the FEC coding block size. Basically, don't pick a very large coding block size if frequent flushing is happening ๐Ÿšฉ.

For example, a reliable multicast app sending an ongoing series of small, intermittent messages has to trade off between the NORM_OBJECT_DATA paradigm and the NORM_OBJECT_STREAM paradigm, with an appropriate FEC coding block size ๐Ÿ“. It's honestly giving the same vibe as the app-level choices you make with other transport protocols, like picking a TCP mode of operation such as "no delay", etc. ๐Ÿ’œ

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  sub-type = 1 |    fec_id     |      object_transport_id      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         fec_payload_id                        |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                acking_node_list (if applicable)               |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 10: NORM_CMD(FLUSH) Message Format ๐ŸŽ€

The version, type, hdr_len, sequence, and source_id fields make up the NORM common message header from Section 4.1 ๐Ÿงฉ. On top of that common header and the standard NORM_CMD fields, the NORM_CMD(FLUSH) message carries fields that show the sender's current status and logical transmit position ๐Ÿ“.

The fec_id field tells you which FEC type is used for the flushing object_transport_id, and it also implies the size and format of the fec_payload_id field ๐Ÿ”. Heads up on the math: the hdr_len value for NORM_CMD(FLUSH) is 4 plus the size of the fec_payload_id field when there are no header extensions present โœจ.

The object_transport_id and fec_payload_id fields show the sender's current logical "transmit position". They get interpreted the same way as in the NORM_DATA message type ๐Ÿง . When receivers get a NORM_CMD(FLUSH), they're expected to check their completion state THROUGH (including) that transmission position ๐Ÿ‘€. If they have outstanding repair needs in that range, they SHALL initiate the NORM NACK Repair Process from Section 5.3 ๐Ÿ“ฃ. If they don't have any outstanding repair needs, they don't generate a response to the NORM_CMD(FLUSH) at all ๐Ÿซก.

Now for the tricky NORM_OBJECT_STREAM case with systematic FEC codes ๐ŸŒธ. Receivers MUST request "explicit-only" repair of the identified source_block_number if the given encoding_symbol_id is less than the source_block_len. That condition means the sender hasn't finished encoding that FEC block yet, so parity content isn't available. An "explicit-only" repair request is NACK content for the applicable source_block_number that doesn't ask for any parity-based repair. This is what lets NORM sender apps "flush" an ongoing stream when they need to, even in the middle of a FEC block ๐ŸŒŠ. Once the sender resumes stream transmission and passes the end of the pending coding block, later NACKs from receivers SHALL request parity-based repair like usual ๐Ÿ”„. Just a reminder that this all assumes a systematic FEC code is in use ๐Ÿค“. Also, the sender has the option to arbitrarily shorten a given code block when that application "flush" happens. In that case, the receiver asks for explicit repair, but the sender MAY provide FEC-based repair (parity segments) in response. Those parity segments MUST contain the corrected source_block_len for the shortened block ๐Ÿงฎ. The source_block_len tied to segments with parity content SHALL override the previously advertised source_block_len. Similarly, the source_block_len associated with the highest ordinal encoding_symbol_id SHALL take precedence over prior symbols whenever a difference shows up (for example, because the sender shortened the code) ๐Ÿ†. Normal receiver NACK initiation and construction is covered in detail in Section 5.3 ๐Ÿ“š.

The OPTIONAL acking_node_list field has a list of NormNodeIds for the receivers the sender is asking for explicit positive acknowledgment of reception, up through the transmission point identified by the object_transport_id and fec_payload_id fields ๐Ÿ™‹. The length of that list can be inferred from the length of the received NORM_CMD(FLUSH) message. When the acking_node_list is present, the lightweight positive acknowledgment process from Section 5.5.3 SHALL be observed ๐Ÿ’–.

4.2.3.2. NORM_CMD(EOT) Message ๐Ÿฆ‹

Now the grand finale: NORM_CMD(EOT) ๐ŸŽฌ. The sender sends this when it hits permanent end-of-transmission with respect to the NormSession and won't answer any more repair requests ๐Ÿšช. This lets receivers wrap things up gracefully with that sender (no timeout needed!) and free up any resources they don't need anymore ๐Ÿงน. The NORM_CMD(EOT) command SHOULD be sent with the same robust mechanism used for NORM_CMD(FLUSH) commands, so the receiver set gets a high level of assurance it actually got the message ๐Ÿ’œ.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  sub-type = 2 |                    reserved                   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 11: NORM_CMD(EOT) Message Format ๐ŸŒˆ

The hdr_len value for NORM_CMD(EOT) messages with no header extensions present is 4 ๐Ÿงฎ. The reserved field is reserved for future use and MUST be set to an all ZERO value 0๏ธโƒฃ. Receivers MUST ignore the reserved field ๐Ÿ™ˆ.

4.2.3.3. NORM_CMD(SQUELCH) Message โœจ

okay so the NORM_CMD(SQUELCH) command is what a sender fires off when it gets outdated or invalid NORM_NACK content ๐Ÿ’…. Invalid NACK content means repair requests for NormObjects the sender can't or won't repair. That covers outdated objects, aborted objects, and objects the sender previously sent with the NORM_FLAG_UNRELIABLE flag set ๐Ÿ™ˆ. This command basically tells receivers what's still available for repair, so it's a snapshot of the sender's current "repair window" ๐Ÿฆ‹. Receivers SHALL NOT generate repair requests for any content a NORM_CMD(SQUELCH) has flagged as invalid ๐Ÿšซ.

The NORM_CMD(SQUELCH) gets sent once per 2*GRTT_sender at the most โฐ. It advertises the current "repair window" by naming the earliest transmission point the sender will still repair from, plus an encoded list of objects from that point onward that are no longer valid for repair. This lets the sender application cancel or abort transmission and/or repair of specific objects it already enqueued ๐ŸŒธ. The list also includes the IDs of any objects inside the repair window that were sent with NORM_FLAG_UNRELIABLE set. Honestly, in normal conditions the NORM_CMD(SQUELCH) is needed pretty rarely, mostly just to give a reference repair window to receivers who got "out-of-sync" with the sender because of extremely poor network conditions ๐Ÿ˜ญ.

The starting point of the invalid NormObject list is the lowest invalid NormTransportId that's greater than the current "repair window" start, taken from the invalid NACK(s) that triggered the squelch ๐ŸŽ€. The list length is capped by the sender's NormSegmentSize. This keeps receivers in the loop about the sender's repair window without a ton of NORM_CMD(SQUELCH) traffic ๐Ÿงš. Here's the format:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | sub-type = 3  |     fec_id    |      object_transport_id      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         fec_payload_id                        |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                        invalid_object_list                    |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                Figure 12: NORM_CMD(SQUELCH) Message Format

On top of the NORM common message header and the standard NORM_CMD fields, NORM_CMD(SQUELCH) has fields that pin down the earliest logical transmit position of the sender's current repair window, plus an invalid_object_list that starts at the logically earliest invalid repair request from the offending NACK that kicked off the squelch ๐Ÿ’–. When no extensions are present, the hdr_len value is 4 plus the size of the fec_payload_id field, and that size depends on the FEC scheme named in fec_id โœจ.

The object_transport_id and fec_payload_id fields get concatenated to mark the start of the sender's current repair window, meaning the logically earliest point in its transmission history where repair is still on the table ๐ŸŒˆ. The fec_id field tells you the size and format of fec_payload_id. Together they act as a "synchronization" point that receivers use when they request repair ๐Ÿซถ. An encoding_symbol_id MAY be included in fec_payload_id, but the sender's repair window SHOULD be aligned on FEC coding block boundaries, so the encoding_symbol_id SHOULD be zero ๐Ÿ“.

The invalid_object_list is the squad of 16-bit NormTransportIds that are still inside the sender's repair window but no longer available for repair. For example, a sender application MAY dequeue an out-of-date object even if it's still within the repair window ๐Ÿ’€.

The total size of the invalid_object_list content can be figured out from the packet's payload length, and it's capped at the sender's NormSegmentSize ๐Ÿ“. So with really big repair windows, one NORM_CMD(SQUELCH) might not fit the whole invalid set. In that case, the sender SHALL ensure the list begins with a NormTransportId that is greater than or equal to the lowest ordinal invalid NormTransportId from the NACK message(s) that triggered the NORM_CMD(SQUELCH) ๐Ÿ”ฅ. Also, every NormTransportId in the invalid_object_list MUST be ordinally greater than the object_transport_id marking the start of the sender's repair window ๐Ÿ‘‘. That's what keeps the squelch process converging, even if it takes multiple rounds of invalid NACKs and squelches ๐ŸŒธ. This explicit description of invalid content inside the current window lets the sender application (especially for discrete object transport) arbitrarily invalidate, i.e. dequeue, chunks of enqueued content it no longer wants reliable transport for ๐Ÿฆ‹โœจ.

4.2.3.4. NORM_CMD(CC) Message โœจ

okay so the NORM_CMD(CC) message is literally the multitasker of NORM ๐Ÿ’…. it does two jobs: sender-to-group GRTT measurement and getting the whole group to send back congestion control feedback. the baseline congestion control scheme, NORM-CC, is based on the TCP-Friendly Multicast Congestion Control (TFMCC) scheme from RFC 4654, and it's fully specified in Section 5.5.2 of this document. NORM_CMD(CC) is usually sent as part of NORM-CC operation ๐Ÿฆ‹. There's a NORM header extension defined below to go with it so it can support NORM-CC. Different header extensions MAY be defined for NORM_CMD(CC) (and/or other NORM messages as needed) to support alternative congestion control schemes in the future ๐ŸŒˆ. And if NORM runs somewhere that resources are explicitly dedicated to the NORM session, so congestion control is turned off, then NORM_CMD(CC) is only used for GRTT measurement and MAY be sent less frequently than it would be with congestion control on ๐Ÿงš.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |            sequence           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  sub-type = 4 |    reserved   |          cc_sequence          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         send_time_sec                         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                        send_time_usec                         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |               header extensions (if applicable)               |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                  cc_node_list (if applicable)                 |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 13: NORM_CMD(CC) Message Format ๐ŸŽ€

The NORM common message header and standard NORM_CMD fields do their usual jobs ๐Ÿ’–. When no header extensions are present, the value of the hdr_len field is 6.

The reserved field is saved for potential future use, and it MUST be set to ZERO in this version of the NORM protocol and its baseline NORM-CC scheme ๐Ÿ™ˆ. Alternative congestion control schemes can use the NORM_CMD(CC) message defined here and borrow the reserved field for their own scheme-specific purposes. main character energy, honestly ๐Ÿ‘‘.

The cc_sequence field is a sequence number applied by the sender ๐Ÿ”ฅ. For NORM-CC, it gives you the same functionality as the "feedback round number" (fb_nr) described in RFC 4654. Receivers record the most recently received cc_sequence value, and they can feed it back to the sender in the congestion control feedback they generate for that sender. NORM implementations can also use cc_sequence to figure out how recently a receiver has received NORM_CMD(CC) probes from the sender, which is super useful instrumentation for complex or experimental multicast routing environments ๐Ÿง .

The send_time field is a timestamp showing when the NORM_CMD(CC) message was transmitted โฐ. It's a 64-bit field: 32 bits of time in seconds (send_time_sec) and 32 bits of time in microseconds (send_time_usec), counted since some reference time the source keeps (usually 00:00:00, 1 January 1970). The fields use "Big Endian" network order. Receivers take this timestamp, adjust it by the delay between receiving the NORM_CMD(CC) message and sending their response, and use that as the "grtt_response" portion of the NORM_ACK and NORM_NACK messages they generate. This lets the sender work out round-trip times to different receivers for congestion control and other (e.g., GRTT determination) purposes ๐ŸŒธ.

To make the baseline NORM-CC scheme from Section 5.5.2 work, there's a NORM-CC Rate header extension (EXT_RATE). It tells the group the sender's current transmission rate ๐Ÿš€. It works together with the loss detection "sequence" field of all NORM sender messages and the NORM_CMD(CC) GRTT collection process to make NORM-CC congestion control happen. The format is:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    het = 128  |    reserved   |           send_rate           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The send_rate field shows the sender's current transmission rate in bytes per second ๐Ÿ’…. This 16-bit field is a little math puzzle: the most significant portion is 12 bits of mantissa, and the least significant portion is 4 bits of base 10 integer exponent (E). The 12-bit mantissa is scaled so that a base 10 mantissa (M) floating point value of 0.0 corresponds to 0, and a value of 10.0 corresponds to 4096 in the upper 12 bits. So:

send_rate = (((int)(M * 4096.0 / 10.0 + 0.5)) << 4) | E;

For example, to represent a transmission rate of 256 kbit/s (3.2e+04 bytes per second), the lower 4 bits contain 0x04 for the exponent (E), while the upper 12 bits contain 0x51f (M), as worked out from the equation above:

send_rate = (((int)((3.2 * 4096.0 / 10.0) + 0.5)) << 4) | 4;
          = (0x51f << 4) | 0x4
          = 0x51f4

To decode the send_rate field, you can use this equation:

value = (send_rate >> 4) * (10/4096) * power(10, (send_rate & x000f))
the maximum transmission rate this scheme can represent is approximately 9.99e+15 bytes per second. that's a lot of bytes, bestie ๐Ÿ˜ญ

When this extension is present, a "cc_node_list" might be attached as the payload of the NORM_CMD(CC) message ๐Ÿงพ. Having this header extension also means NORM receivers MUST respond according to the procedures described in Section 5.5.2. no skipping!! ๐Ÿซถ

The "cc_node_list" is a list of NormNodeIds and their congestion control status ๐Ÿ’œ. It includes the current limiting receiver (CLR) node, any potential limiting receiver (PLR) nodes that have been identified, and some number of receivers whose congestion control status is being reported, most notably their current RTT measurement. The maximum length of the "cc_node_list" gives room for at least the CLR and one other receiver, but it can be made longer for more timely feedback to the group ๐Ÿ“. You can infer the list length from the length of the NORM_CMD(CC) message itself.

Each item in the "cc_node_list" looks like this:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          cc_node_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    cc_flags   |     cc_rtt    |            cc_rate            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The cc_node_id is the NormNodeId of the receiver that the item represents ๐Ÿ†”.

The cc_flags field holds flags showing the congestion control status of that receiver ๐Ÿšฉ. These flags are defined:

+--------------------+-------+--------------------------------------+
| Flag               | Value | Purpose                              |
+--------------------+-------+--------------------------------------+
| NORM_FLAG_CC_CLR   |  0x01 | Receiver is the current limiting     |
|                    |       | receiver (CLR).                      |
| NORM_FLAG_CC_PLR   |  0x02 | Receiver is a potential limiting     |
|                    |       | receiver (PLR).                      |
| NORM_FLAG_CC_RTT   |  0x04 | Receiver has measured RTT with       |
|                    |       | respect to sender.                   |
| NORM_FLAG_CC_START |  0x08 | Sender/receiver is in "slow start"   |
|                    |       | phase of congestion control          |
|                    |       | operation (i.e., the receiver has    |
|                    |       | not yet detected any packet loss and |
|                    |       | the "cc_rate" field is the           |
|                    |       | receiver's actual measured receive   |
|                    |       | rate).                               |
| NORM_FLAG_CC_LEAVE |  0x10 | Receiver is imminently leaving the   |
|                    |       | session and its feedback SHOULD not  |
|                    |       | be considered in congestion control  |
|                    |       | operation.                           |
+--------------------+-------+--------------------------------------+

The cc_rtt field holds a quantized version of the RTT as measured by the sender with respect to the receiver in that item ๐Ÿ“. This field only means something if the NORM_FLAG_CC_RTT flag is set in cc_flags. It's a one-byte field, quantized using the algorithm described in the Multicast NACK Building Block [RFC5401] document. so precise, so cute ๐Ÿงšโ€โ™€๏ธ.

The cc_rate field holds the receiver's current calculated congestion control rate (during steady-state congestion control operation), or twice its measured rate (during the slow start phase) ๐ŸŒŠ. It's encoded and decoded with the same technique described for the NORM_CMD(CC) send_rate field ๐Ÿ’–.

4.2.3.5. NORM_CMD(REPAIR_ADV) Message โœจ

okay bestie, the NORM_CMD(REPAIR_ADV) message is how the sender advertises its repair state ๐Ÿฆ‹. It bundles up everything from the NORM_NACK messages collected during a repair cycle, plus any congestion control feedback it got. This message only gets sent when the sender has been receiving NORM_NACK and/or NORM_ACK(CC) (when congestion control is on) via unicast instead of multicast ๐Ÿ™ˆ. By passing that info along to the whole receiver set, feedback suppression still works even when receivers are unicasting their feedback instead of multicasting it to the group [NormFeedback] ๐Ÿงš.

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |version| type=3|    hdr_len    |          sequence             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           source_id                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          instance_id          |     grtt      |backoff| gsize |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | sub-type = 5  |     flags     |            reserved           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |               header extensions (if applicable)               |
   |                              ...                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       repair_adv_payload                      |
   |                              ...                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

            Figure 14: NORM_CMD(REPAIR_ADV) Message Format

The instance_id, grtt, backoff, gsize, and sub-type fields do the same job they do in every other NORM_CMD message ๐Ÿ“. When there are no extensions present, hdr_len is 4 โœจ.

The flags field tells you what's going on with the NORM_CMD(REPAIR_ADV) content ๐Ÿ‘‘. Right now there's just one flag defined:

                   NORM_REPAIR_ADV_FLAG_LIMIT = 0x01

The sender sets this flag when it can't fit its full current repair state into a single NormSegmentSize ๐Ÿ˜ญ. When it's set, receivers SHALL limit their NACK response to generating NACK content only up through the maximum ordinal transmission position (objectTransportId::fecPayloadId) included in the "repair_adv_content".

When congestion control operation is enabled, a header extension SHOULD be applied to the NORM_CMD(REPAIR_ADV) representing the most limiting (in terms of congestion control feedback suppression) congestion control response. ๐Ÿ”ฅ

That's the spicy part! It lets the NORM_CMD(REPAIR_ADV) suppress receiver congestion control responses as well as NACK feedback messages ๐Ÿ’…. The field is defined as a header extension so alternative congestion control schemes can be used for NORM without revising this document ๐ŸŒˆ. A NORM-CC Feedback Header Extension (EXT_CC) is defined to encapsulate congestion control feedback within NORM_NACK, NORM_ACK, and NORM_CMD(REPAIR_ADV) messages. If another congestion control technique (for example, Pragmatic General Multicast Congestion Control (PGMCC) [PgmccPaper]) is used within a NORM implementation, an additional header extension MAY need to be defined to encapsulate any required feedback content ๐Ÿฆ‹. The NORM-CC Feedback Header Extension format looks like this:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     het = 3   |    hel = 3    |          cc_sequence          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    cc_flags   |     cc_rtt    |            cc_loss            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |            cc_rate            |          cc_reserved          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The "cc_sequence" field holds the current greatest "cc_sequence" value receivers have received in NORM_CMD(CC) messages from the sender ๐ŸŽ€. This tells the sender how "fresh" the receiver's round-trip measurement reference time is, and whether the receiver has been successfully getting recent congestion control probes ๐Ÿ‘€. For example, if it's obvious the receiver hasn't been getting recent congestion control probes (and so possibly other messages from the sender too), the sender SHOULD choose to take congestion avoidance measures ๐Ÿ˜ญ. For NORM_CMD(REPAIR_ADV) messages, the sender SHALL set the "cc_sequence" field value to the value set in the last NORM_CMD(CC) message sent.

The "cc_flags" field holds bits representing the receiver's state with respect to congestion control operation โœจ. The possible values are the ones specified for the NORM_CMD(CC) message node list item flags. Receivers use these to control (suppressing as necessary) their congestion control feedback. For NORM_CMD(REPAIR_ADV) messages, the NORM_FLAG_CC_RTT SHALL be set only when all feedback messages received by the sender have the flag set. Similarly, the NORM_FLAG_CC_CLR or NORM_FLAG_CC_PLR SHALL be set only when no feedback has been received from non-CLR or non-PLR receivers. And the NORM_FLAG_CC_LEAVE SHALL be set only when all feedback messages the sender has received have this flag set. These heuristics for setting the flags in NORM_CMD(REPAIR_ADV) ensure the most effective suppression of receivers providing unicast feedback messages ๐Ÿ’–.

The "cc_rtt" field SHALL be set to a default maximum value, and the NORM_FLAG_CC_RTT flag SHALL be cleared, when no receiver has received RTT measurement information yet ๐Ÿ•ฐ๏ธ. Once a receiver has received RTT measurement information, it SHALL set the "cc_rtt" value accordingly and set the NORM_FLAG_CC_RTT flag in the "cc_flags" field. For NORM_CMD(REPAIR_ADV) messages, the sender SHALL set the "cc_rtt" field value to the largest non-CLR/non-PLR RTT it has measured from receivers for the current feedback round ๐ŸŒธ.

The "cc_loss" field represents the receiver's current packet loss fraction estimate for the indicated source ๐Ÿ“‰. The loss fraction is a value from 0.0 to 1.0, which maps to a range of zero to 100 percent packet loss. The 16-bit "cc_loss" value is calculated with this formula:

          "cc_loss" = floor(decimal_loss_fraction * 65535.0)

For NORM_CMD(REPAIR_ADV) messages, the sender SHALL set the "cc_loss" field value to the largest non-CLR/non-PLR loss estimate it has received from receivers for the current feedback round ๐Ÿซถ.

The "cc_rate" field represents the receiver's current local congestion control rate ๐ŸŽ๏ธ. During "slow start", when the receiver has detected no loss, this value is set to twice the actual rate it has measured from the corresponding sender, and the NORM_FLAG_CC_START is set in the "cc_flags" field. Otherwise, the receiver calculates a congestion control rate for the "cc_rate" field based on its loss measurement and RTT measurement information (even if it's a default). For NORM_CMD(REPAIR_ADV) messages, the sender SHALL set the "cc_loss" field value to the lowest non-CLR/non-PLR "cc_rate" report it has received from receivers for the current feedback round ๐Ÿง.

The "cc_reserved" field is reserved for future NORM protocol use ๐Ÿ”ฎ. Right now, senders SHALL set this field to ZERO, and receivers SHALL ignore its content ๐Ÿ™…โ€โ™€๏ธ.

The "repair_adv_payload" is in exactly the same form as the "nack_content" of NORM_NACK messages, and receivers can process it for suppression purposes in the same way, with one exception: when NORM_REPAIR_ADV_FLAG_LIMIT is set ๐Ÿ’…โœจ.

4.2.3.6. NORM_CMD(ACK_REQ) Message โœจ

okay bestie, NORM_CMD(ACK_REQ) is how the sender asks a specific list of receivers to send back a positive ack ๐Ÿ’Œ. It's a super lightweight ack mechanism, and the reliable multicast app can skip it entirely since it's OPTIONAL ๐Ÿซถ. There's a whole range of ack request types so the app can pick whatever fits its vibe ๐ŸŽ€. Apps can also make their own positively acknowledged commands, which lets them automatically borrow the transmission and round-trip timing info NORM already has ๐Ÿงš. The whole NORM Positive Acknowledgment Process, including how the ACK_REQ gets sent and how receivers reply with NORM_ACK, is covered in Section 5.5.3 ๐Ÿ“–. Here's the layout:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | sub-type = 6  |    reserved   |    ack_type   |    ack_id     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       acking_node_list                        |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 15: NORM_CMD(ACK_REQ) Message Format

The NORM common message header and standard NORM_CMD fields do their usual jobs, nothing new there ๐Ÿ’…. If there are no header extensions, hdr_len for NORM_CMD(ACK_REQ) is 4.

The ack_type field tells everyone what kind of ack is being asked for, and that decides how the receiver handles the request ๐Ÿ‘‘. These are the values, which are also used in NORM_ACK messages later on:

+-----------------------+------------+------------------------------+
| ACK Type              | Value      | Purpose                      |
+-----------------------+------------+------------------------------+
| NORM_ACK(CC)          | 1          | Used to identify NORM_ACK    |
|                       |            | messages sent in response to |
|                       |            | NORM_CMD(CC) messages.       |
| NORM_ACK(FLUSH)       | 2          | Used to identify NORM_ACK    |
|                       |            | messages sent in response to |
|                       |            | NORM_CMD(FLUSH) messages.    |
| NORM_ACK(RESERVED)    | 3-15       | Reserved for possible future |
|                       |            | NORM protocol use.           |
| NORM_ACK(APPLICATION) | 16-255     | Used at application's        |
|                       |            | discretion.                  |
+-----------------------+------------+------------------------------+

So NORM_ACK(CC) is only for NORM_ACKs replying to NORM_CMD(CC) messages used in congestion control ๐Ÿฆ‹. NORM_ACK(FLUSH) is the same deal, but for applicable NORM_CMD(FLUSH) messages ๐ŸŒธ. Hard rule: the sender SHALL NOT generate NORM_CMD(ACK_REQ) messages with an ack_type of NORM_ACK(CC) or NORM_ACK(FLUSH) ๐Ÿšซ.

The NORM_ACK(RESERVED) range (3-15) is saved for future NORM protocol stuff ๐Ÿ”ฎ. The NORM_ACK(APPLICATION) range (16-255) is the fun one ๐ŸŽ‰. It lets apps build their own positively acknowledged commands and tap into the NORM implementation's transmission and round-trip timing info ๐Ÿ’œ.

The ack_id is a sequenced identifier for each NORM_CMD(ACK_REQ) ๐Ÿงพ. Receivers copy it into their NORM_ACK replies, so the sender can match each response to the request it belongs to ๐Ÿซถ.

The reserved field is reserved for future protocol use, so senders SHALL set it to ZERO and receivers SHALL ignore it ๐Ÿ™ˆ.

The acking_node_list holds the NormNodeIds of the current NORM receivers that are supposed to send a positive ack (NORM_ACK) for this request ๐Ÿ’–. The packet payload length tells you how long the list is, and the list can't go past the sender NormSegmentSize ๐Ÿ“. Each NormNodeId is written in network (Big Endian) byte order ๐Ÿ”ข. If a receiver's own NormNodeId is in the acking_node_list, it SHALL schedule a NORM_ACK transmission as described in Section 5.5.3 โœจ.


4.2.3.7. NORM_CMD(APPLICATION) Message ๐ŸŽ€

this one is the app's personal messenger ๐Ÿ“จ. NORM_CMD(APPLICATION) lets the NORM app robustly send its own commands. The command jumps ahead of any data that's currently being sent ๐Ÿƒโ€โ™€๏ธ, and it gets repeated up to NORM_ROBUST_FACTOR times, once every 2*GRTT_sender ๐Ÿ”. That spacing gives the app time to see any reply it's waiting for before the command goes out again ๐Ÿ‘€. The replies could be the start of data transmission, more NORM_CMD(APPLICATION) messages, or app-defined positively acknowledged commands from other NormSession participants ๐Ÿฅฐ. When these commands get scheduled they preempt data transmission, but they can also be multiplexed with data that's already flowing ๐Ÿงต. The big win is that apps get to build a full set of session control stuff with less state than FEC-encoded reliable content needs, while still using NORM's transmission and round-trip timing info ๐Ÿง .

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=3|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          instance_id          |     grtt      |backoff| gsize |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | sub-type = 7  |                    reserved                   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                   Application-Defined Content                 |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 16: NORM_CMD(APPLICATION) Message Format

The NORM common message header and NORM_CMD fields work the way they already did ๐Ÿ”. When there are no header extensions, hdr_len for NORM_CMD(APPLICATION) is 4.

The "Application-Defined Content" area holds whatever format the app wants ๐ŸŽจ. Its size SHALL be limited to a maximum of the sender's NormSegmentSize setting ๐Ÿ“. When it arrives, the NORM implementation SHALL deliver the content up to the receiver app ๐Ÿ“ฌ. Heads up: spotting duplicate NORM_CMD(APPLICATION) messages is the app's job, not NORM's ๐Ÿ™ˆ.


4.3. Receiver Messages ๐Ÿฆ‹

receivers have their own messages ๐Ÿ’Œ. The receiver types are NORM_NACK and NORM_ACK. NORM_NACK messages ask for repairs of missing data from the sender's transmissions ๐Ÿฉน. NORM_ACK messages get sent back in response to certain sender commands, including NORM_CMD(CC) and NORM_CMD(ACK_REQ) ๐Ÿ’œ.

4.3.1. NORM_NACK Message ๐Ÿซถ

the main job of NORM_NACK is to ask for repairs of the sender's content using selective, negative acknowledgment whenever a receiver notices incomplete data ๐Ÿ•ต๏ธโ€โ™€๏ธ. NORM_NACK messages follow the NACK generation and suppression rules in Section 5.3 ๐Ÿ“œ. They also carry extra fields that give the sender feedback for round-trip timing and congestion control ๐Ÿ“ˆ.

The payload of a NORM_NACK can hold one or more repair requests, for different objects or parts of objects ๐Ÿงฉ. Here's the format:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=4|    hdr_len    |            sequence           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           server_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           instance_id         |            reserved           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       grtt_response_sec                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       grtt_response_usec                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |               header extensions (if applicable)               |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          nack_payload                         |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 17: NORM_NACK Message Format

The NORM common message header fields do their usual jobs ๐Ÿง. With no header extensions, hdr_len for NORM_NACK is 6.

The server_id field says which NORM sender the NORM_NACK is headed to ๐Ÿ“ฌ.

The instance_id field carries the current session identifier from the sender named in server_id, as found in that sender's sender messages ๐Ÿ†”. The sender SHOULD ignore feedback messages with an invalid instance_id value ๐Ÿ™…โ€โ™€๏ธ.

The grtt_response fields are a tweaked copy of the timestamp from the latest NORM_CMD(CC) the receiver got from that NORM sender โฑ๏ธ. They use the same format as the send_time field of NORM_CMD(CC). The grtt_response value is measured relative to the send_time the source gave in the matching NORM_CMD(CC) โฐ. The receiver takes the source's NORM_CMD(CC) send_time and adds the gap between when it got the NORM_CMD(CC) and when it sends the NORM_NACK, which is the receive_to_response_delta ๐Ÿงฎ. Here's the formula:

grtt_response = NORM_CMD(CC) send_time + receive_to_response_delta

okay so we're picking up right where the NACK stuff left off ๐Ÿ’– the receiver SHALL set "grtt_response" to a ZERO value ๐Ÿ™ˆ which just means "I haven't gotten a NORM_CMD(CC) from this sender yet," and the sender MUST ignore "grtt_response" in this message. no notes, no drama ๐Ÿ’…

for NORM-CC operation, the NORM-CC Feedback Header Extension (the one described in the NORM_CMD(REPAIR_ADV} message description) gets tacked onto NORM_NACK messages so the sender can see the receiver's current congestion control state ๐ŸŒธ and honestly, other header extensions MAY be defined for other congestion control schemes later on. future us is gonna be so grateful ๐Ÿงš

the "reserved" field is saving space for future NORM stuff, and it SHALL be set to ZERO for this version of the protocol. keep it zero, bestie ๐Ÿซถ

now the good part โœจ the "nack_payload" of a NORM_NACK message tells the sender exactly what the receiver needs repaired from that sender (the one named in "server_id") ๐Ÿฆ‹ the receiver builds its repair requests from the NORM_DATA and/or NORM_INFO segments it's still missing, so it can finish reliable reception up to the sender's transmission position at the exact moment it kicks off the NACK procedure from Section 5.3. one NORM Repair Request is a list of items, ranges, and/or FEC coding block erasure counts for the content it needs. you can stack several repair requests inside one "nack_payload" ๐Ÿฅž and one request can have multiple "items", "ranges", or "erasure_counts" in it. so yeah, the "nack_payload" MAY contain multiple repair requests. this is the format for a single one:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      form     |     flags     |             length            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                      repair_request_items                     |
     |                             ...                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                   Figure 18: NORM Repair Request Format

the "form" field tells you what kind of items are in "repair_request_items" ๐ŸŽ€ here are the possible values:

                      +--------------------+-------+
                      | Form               | Value |
                      +--------------------+-------+
                      | NORM_NACK_ITEMS    |   1   |
                      | NORM_NACK_RANGES   |   2   |
                      | NORM_NACK_ERASURES |   3   |
                      +--------------------+-------+

so NORM_NACK_ITEMS means every repair request item is its own separate request ๐Ÿ’… NORM_NACK_RANGES means the list is made of pairs, and each pair is an inclusive range of repair needs ๐ŸŒˆ and NORM_NACK_ERASURES means the items are still treated one by one, but the "encoding_symbol_id" part of the "fec_payload_id" field (see below) gets read as an erasure count for the FEC coding block named by that item's "source_block_number" ๐Ÿฆ‹

the "flags" field says what level of data the repair items are for: a single segment, a whole FEC coding block, or a whole transport object โœจ here's the vibe check:

   +-------------------+--------+--------------------------------------+
   | Flag              |  Value | Purpose                              |
   +-------------------+--------+--------------------------------------+
   | NORM_NACK_SEGMENT |  0x01  | Indicates the listed segment(s) or   |
   |                   |        | range of segments needed as repair.  |
   | NORM_NACK_BLOCK   |  0x02  | Indicates the listed block(s) or     |
   |                   |        | range of blocks in entirety that are |
   |                   |        | needed as repair.                    |
   | NORM_NACK_INFO    |  0x04  | Indicates NORM_INFO is needed as     |
   |                   |        | repair for the listed object(s).     |
   | NORM_NACK_OBJECT  |  0x08  | Indicates the listed object(s) or    |
   |                   |        | range of objects in entirety are     |
   |                   |        | needed as repair.                    |
   +-------------------+--------+--------------------------------------+

when NORM_NACK_SEGMENT is set, "object_transport_id" and "fec_payload_id" work together to figure out which sets or ranges of individual NORM_DATA segments the receiver needs repaired ๐Ÿ“ when NORM_NACK_BLOCK is set, the receiver is totally missing the listed coding block(s), so it needs enough transmissions to fix those blocks completely ๐Ÿ’€ when NORM_NACK_INFO is set, the receiver is missing the NORM_INFO segment for that "object_transport_id" ๐Ÿงš and NORM_NACK_INFO can be paired with NORM_NACK_BLOCK or NORM_NACK_SEGMENT, or it can show up all by itself โœจ

when NORM_NACK_OBJECT is set, the receiver is missing the entire NormTransportObject referenced by "object_transport_id" ๐Ÿ˜ญ that also implicitly asks for any available NORM_INFO for the NormObject, if there is one. and the "fec_payload_id" field gets ignored whenever NORM_NACK_OBJECT is set, so don't even look at it ๐Ÿ™ˆ

the "length" field is just the length in bytes of the "repair_request_items" field ๐Ÿ“

okay and "repair_request_items" is a list of individual items or range pairs of transport data unit identifiers, and each one looks like this ๐Ÿ‘‘

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |     fec_id    |   reserved    |      object_transport_id      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                        fec_payload_id                         |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                Figure 19: NORM Repair Request Item Format

"fec_id" tells you the FEC type, and that's what decides how "fec_payload_id" is formatted ๐Ÿฆ‹ the "reserved" field is kept for possible future use and SHALL be set to a ZERO value, and NORM nodes processing NACK content SHALL ignore it ๐Ÿซถ

"object_transport_id" is the NormObject that needs repair, and "fec_payload_id" pins down the exact FEC coding block and/or segment being asked for โœจ if NORM_NACK_OBJECT is set, the "fec_payload_id" value gets ignored. if NORM_NACK_BLOCK is set, only the FEC code block identifier part of "fec_payload_id" is interpreted ๐ŸŒธ

the "fec_payload_id" field's format depends on what "fec_id" says ๐Ÿงš

now, if the receiver's repair needs are a mix of forms (ranges and individual items) or types (specific segments, blocks, or whole objects) to finish reliable transmission, then multiple NORM Repair Requests with different "form" and/or "flags" values can be stuck together in one NORM_NACK message ๐ŸŽ€ and NORM receivers SHALL construct NORM_NACK messages with their repair requests in ordinal order with respect to "object_transport_id" and "fec_payload_id" values ๐Ÿ‘‘ and the "nack_payload" size SHALL NOT exceed the NormSegmentSize for the sender the NORM_NACK is headed to ๐Ÿ™ˆ no going over, periodt.

NORM_NACK Content Examples:

in these examples, we assume a small block, systematic FEC code ("fec_id" = 129) with a user data block length of 32 segments ๐Ÿ“ Example 1 is a list of individual NORM_NACK_ITEMS repair requests. Example 2 (coming up) mixes a list of NORM_NACK_RANGES requests with a single NORM_NACK_ITEMS request to show what a NORM_NACK message can hold ๐ŸŒˆ FEC coding block erasure counts could also be included in each case ๐Ÿ’… but they aren't really needed, because the sender can work out the erasure count itself while it processes the NACK content. still, the erasure count option can be handy for other FEC codes or for intermediate system purposes โœจ

Example 1 ๐ŸŒˆ this is the "nack_payload" for Object 12, Coding Block 3, Segments 2, 5, and 8:

    Example 1: NORM_NACK "nack_payload" for: Object 12, Coding Block 3,
                           Segments 2, 5, and 8
      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   form = 1    | flags = 0x01  |       length  = 36            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 12   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 3                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 2     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 12   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 3                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 5     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 12   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 3                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 8     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    Example 2: NORM_NACK "nack_payload" for: Object 18, Coding Block 6,
   Segments 5, 6, 7, 8, 9, 10; and Object 19 NORM_INFO and Coding Block
                               1, Segment 3
      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   form = 2    | flags = 0x01  |       length  = 24            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 18   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 6                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 5     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 18   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 6                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 10    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   form = 1    | flags = 0x05  |       length  = 12            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |  fec_id = 129 |   reserved    |    object_transport_id = 19   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    source_block_number = 1                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    source_block_length = 32   |    encoding_symbol_id = 3     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

4.3.2. NORM_ACK Message โœจ

okay bestie, so the NORM_ACK message is mainly for two big jobs: NORM congestion control and round-trip timing measurement ๐Ÿงš the NORM_ACK(CC) type is made for exactly that, and you can read about it in the NORM_CMD(ACK_REQ) message description. how NORM_ACK(CC) gets generated for timing and for congestion control is covered in Section 5.5.1 and Section 5.5.2, respectively. ๐Ÿ’…

but wait, some multicast apps can totally benefit from a little bit of positive acknowledgment too ๐Ÿซถ so there's a simple, scalable positive ack scheme in Section 5.5.3, and protocol implementations can use it when it makes sense. the NORM_CMD(FLUSH) can also be used for OPTIONAL collection of positive acknowledgment of reliable reception to a certain "watermark" transmission point from specific receivers using this mechanism. that's where NORM_ACK(FLUSH) comes in, and its nack_payload format is shown below. ๐ŸŒธ

then there's a whole range of application-defined "ack_type" values that the app can use however it wants ๐ŸŽ€ and implementations doing application-defined positive acks MAY also use the "nack_payload" as needed. the only rule is that the "nack_payload" field size is limited to a maximum of the NormSegmentSize for the sender the NORM_ACK is destined for. โœจ

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |version| type=5|    hdr_len    |          sequence             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           source_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                           server_id                           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           instance_id         |    ack_type  |     ack_id     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       grtt_response_sec                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                       grtt_response_usec                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |               header extensions (if applicable)               |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                   ack_payload (if applicable)                 |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 20: NORM_ACK Message Format ๐Ÿ“

the NORM common message header fields do their usual jobs ๐Ÿ’– and when there are no header extensions, the "hdr_len" field value is 6.

the "server_id", "instance_id", and "grtt_response" fields do the same thing as the matching fields in NORM_NACK messages ๐Ÿฆ‹ and header extensions can be used for congestion control feedback or other stuff in the same way.

the "ack_type" field tells you what kind of NORM_ACK message it is. it directly matches the "ack_type" field of the NORM_CMD(ACK_REQ) message this ack is replying to. ๐Ÿ”ฅ

the "ack_id" field is a sequence number, so the sender can check that a NORM_ACK actually applies to a current ack request. it's not used for NORM_ACK(CC) and NORM_ACK(FLUSH) though, so no "ack_id" drama there ๐Ÿ™ˆ

the "ack_payload" format depends on the "ack_type". a NORM_ACK(CC) has no attached content, it's just the NORM_ACK header, no cap ๐Ÿง for NORM_ACK(FLUSH), there's a specific "ack_payload" format:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |     fec_id    |   reserved    |      object_transport_id      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                        fec_payload_id                         |
     |                              ...                              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

the "object_transport_id" and "fec_payload_id" are what the receiver uses to acknowledge the applicable NORM_CMD(FLUSH) messages sent by the sender identified by the "server_id" field. ๐Ÿ’œ

the "ack_payload" of NORM_ACK messages for application-defined "ack_type" values is up to the app ๐ŸŒˆ but it's still capped at a maximum of the NormSegmentSize of the sender referenced by the "server_id". โœจ

4.4. General Purpose Messages ๐ŸŽ€

some extra message formats are defined for general purpose use in NORM multicast sessions, whether the participant is acting as a sender, a receiver, or both within the group. ๐Ÿงš

4.4.1. NORM_REPORT Message ๐Ÿ’…

this is an OPTIONAL message that NORM participants can generate ๐ŸŒธ it can be used for periodic performance reports from receivers in experimental NORM implementations. the format is currently undefined. experimental implementations MAY define NORM_REPORT formats as needed for test purposes. and these report messages SHOULD be disabled for interoperability testing between different compliant NORM implementations. ๐Ÿ™ˆ (keep it chill during interop testing, periodt)


5. Detailed Protocol Operation ๐Ÿ‘‘

this section is the deep dive into what senders and receivers actually do in a NORM session ๐Ÿ”ฅ here's the quick synopsis first, bestie:

  1. the sender periodically sends NORM_CMD(CC) messages as needed to initialize and collect round-trip timing and congestion control feedback from the receiver set. โฑ๏ธ
  2. the sender transmits an ordinal set of NormObjects, chopped up into NORM_DATA messages labeled with NormTransportIds and logically identified with FEC encoding block numbers and symbol identifiers. when it applies, NORM_INFO messages MAY optionally come before the data content for NORM transport objects. ๐Ÿฆ‹
  3. as receivers notice missing content from the sender, they start repair requests with NORM_NACK messages. receivers track the sender's most recent objectTransportId::fecPayloadId transmit position and only NACK content that's ordinally prior to that current transmit position. they also schedule random backoff timeouts before sending NORM_NACK messages, and wait an appropriate amount of time before repeating the NORM_NACK if the repair request isn't satisfied. ๐Ÿซถ
  4. the sender collects repair requests from the receivers and logically "rewinds" its transmit position to send the right repair messages ๐Ÿ’– it sends repairs for the earliest ordinal transmit position first and keeps that ordinal repair order going. FEC parity content that wasn't previously sent for the applicable FEC coding block gets used for repairs as much as possible. if the sender runs out of FEC parity content over multiple repair cycles for the same coding block, it switches to an explicit repair strategy (possibly using parity content) to finish the repairs. (explicit repair is an exception in general operation, but it's possible for extreme conditions, so stay alert ๐Ÿ˜ญ) once it's done sending pending repairs, the sender immediately moves on to new content. โœจ
  5. the sender sends NORM_CMD(FLUSH) messages when it reaches the end of enqueued transmit content and pending repairs ๐Ÿ“ receivers answer NORM_CMD(FLUSH) with NORM_NACK transmissions (using the same suppression backoff timeout strategy as for data) if they still need repair. ๐Ÿ”ฅ
  6. sender transmissions are subject to rate control limits set by congestion control mechanisms. in the baseline NORM-CC operation, each sender in a NormSession keeps its own independent congestion control state ๐ŸŒˆ receivers send congestion control feedback in NORM_NACK and NORM_ACK messages, and NORM_ACK feedback for congestion control purposes is governed using a suppression mechanism similar to the one for NORM_NACK messages. ๐Ÿง

okay so while the big idea is pretty simple, every one of these parts has details that need sorting out for NORM protocol operation to be successful, efficient, robust, and scalable ๐Ÿ‘‘๐Ÿ’œ

5.1. Sender Initialization and Transmission โœจ

Okay so, the second a NORM sender spins up, it starts blasting NORM_CMD(CC) messages ๐ŸŽ€ to collect round-trip timing and other info from the potential group. If NORM-CC congestion control is turned on, the NORM-CC Rate header extension MUST be included in these messages. Congestion control operation SHALL be observed at all times when not operating using dedicated resources, like out on the general Internet ๐ŸŒ. Even if congestion control is off at the sender, it can still be a really good move to use NORM_CMD(CC) messaging to gather feedback from the group using the baseline NORM-CC feedback mechanisms ๐Ÿ’…. This proactive feedback collection can set up a GRTT estimate before data transmission and any potential NACK operation โœจ.

Sometimes apps need the sender to start sending data right away ๐Ÿƒโ€โ™€๏ธ. Other times the sender wants to hold off until it hears some feedback or a request from the receiver set saying receivers are actually there ๐Ÿ‘€. Note, in some apps (like web push), this indication MAY come out-of-band with respect to the multicast session via other means ๐Ÿ“ฌ. As noted, the periodic transmission of NORM_CMD(CC) messages MAY precede actual data transmission so the sender can get an initial GRTT estimate ๐Ÿงฎ.

With the OPTIONAL NORM FEC Object Transmission Information Header Extension (EXT_FTI) included ๐ŸŽ, the NORM protocol sender message headers can carry everything receivers need to get ready for reliable reception, including FEC coding parameters, the sender NormSegmentSize, and more. If this header extension isn't used, it's presumed receivers got the FEC Object Transmission Information some other way. Also, applications MAY leverage NORM_INFO messages tied to the session data objects to share app-specific context about the session and the data being sent ๐Ÿง . These mechanisms allow operation with minimal pre-coordination between senders and receivers ๐Ÿซถ.

The NORM sender starts chopping app-enqueued data into NORM_DATA segments and sending them to the group. For NORM_OBJECT_DATA and NORM_OBJECT_FILE objects, the segmentation algorithm described in FEC Building Block [RFC5052] is RECOMMENDED. For NORM_OBJECT_STREAM objects, segmentation will typically be into uniform FEC coding block sizes, with individual segment sizes controlled by the app. In most cases, the application and NORM implementation SHOULD strive to produce full-sized (NormSegmentSize) segments when possible ๐Ÿ’ช. The transmission rate is controlled by congestion control mechanisms, or it's a fixed rate if you want that for closed network operations. Receivers in the multicast group give feedback to the sender as needed. When the sender reaches the end of the data it has enqueued for transmission or any pending repairs, it sends a series of NORM_CMD(FLUSH) messages at a rate of one per 2*GRTT_sender ๐Ÿšฐ. Similar to the end of each FEC coding block during transmission, receivers SHALL respond to these NORM_CMD(FLUSH) messages with additional repair requests as needed. A protocol parameter NORM_ROBUST_FACTOR determines how many flush messages get sent. If receivers request repair, the repair is provided, and flushing happens again at the end of repair transmission. The sender MAY attach an OPTIONAL "acking_node_list" to NORM_CMD(FLUSH) containing the NormNodeIds for receivers from which it expects explicit positive acknowledgment of reception. The NORM_CMD(FLUSH) message MAY also be used for this OPTIONAL purpose any time before the end of enqueued data, with the flush messages multiplexed with ongoing data transmissions. The OPTIONAL NORM positive acknowledgment procedure is described in Section 5.5.3 ๐Ÿ“š.

5.1.1. Object Segmentation Algorithm โœ‚๏ธ

NORM senders and receivers MUST use a common algorithm for logically segmenting transport data into FEC encoding blocks and symbols, so appropriate NACKs can be built to request repair of missing data ๐Ÿงฉ. NORM FEC coding blocks are made up of multi-byte symbols (segments) carried in the payload of NORM_DATA messages. Each NORM_DATA message will contain one or more source or encoding symbols identified by the fec_payload_id field, and the NormSegmentSize sender parameter sets the maximum size (in bytes) of the payload_data field holding the content (a "segment") ๐Ÿ“. The FEC encoding type and its parameters govern the source block size (number of source symbols per coding block, etc.). NORM senders and receivers use these FEC parameters, along with NormSegmentSize and the transport object size, to compute the source block structure for transport objects. These parameters are provided in the FEC Object Transmission Information for each object. The block partitioning algorithm described in the FEC Building Block [RFC5052] document is RECOMMENDED for computing a source block structure such that all source blocks are as close to equal length as possible ๐Ÿฅฐ. This helps avoid the performance disadvantages of "short" FEC blocks. Note that this algorithm applies only to the statically sized NORM_OBJECT_DATA and NORM_OBJECT_FILE transport object types, where the object size is fixed and predetermined. For NORM_OBJECT_STREAM objects, the object is segmented according to the maximum source block length given in the FEC Transmission Information, unless the FEC Payload ID indicates an alternative size for a given block.

5.2. Receiver Initialization and Reception ๐ŸŽง

For typical operation, NORM receivers join a specified multicast group and listen on a specific port number for sender transmissions ๐Ÿ‘‚. As a receiver gets NORM_DATA messages, it sets up buffering state and hands content to its app as appropriate for the data type. The NORM protocol lets receivers join and leave the group whenever they want, although some apps might need receivers to be members before data transmission starts. Thus, different NORM applications MAY use different policies to constrain the impact of new receivers joining mid-session ๐Ÿšช. For example, a useful implementation policy is for new receivers joining the group to limit or avoid repair requests for transport objects already in progress. The NORM sender implementation MAY impose additional constraints to limit the ability of receivers to disrupt reliable multicast performance by joining, leaving, and rejoining the group often ๐Ÿ™„. Different receiver "join policies" might suit different apps and scenarios. For general purpose operation, a default policy where receivers are allowed to request repair only for coding blocks with a NormTransportId and FEC coding block number greater than or equal to the first non-repair NORM_DATA or NORM_INFO message received upon joining the group is RECOMMENDED. For NORM_OBJECT_STREAM objects, it is RECOMMENDED the join policy constrain receivers to begin reliable reception at the current FEC coding block for which non-repair content is received.

In some deployments, different multicast receivers might have differing quality of network connectivity ๐Ÿ“ถ. Some receivers may suffer significantly poorer performance, with very limited goodput due to low connection rate or substantial packet loss ๐Ÿ˜ฌ. Similar to the "join policies" described above, a NORM sender implementation MAY choose to enforce different "service policies" to perhaps exclude exceptionally poorly performing (or otherwise badly behaving) receivers from the group ๐Ÿšซ. The sender implementation could choose to ignore NACKs from such receivers and/or force advancement of its logical "repair window" (i.e., enforcing a minimal level of service), and use the NORM_CMD(SQUELCH) message to advise those poor performers of its advance ๐Ÿ“ฃ. Note in some cases, the application may need to support the "weakest member" regardless of the time needed to achieve reliable delivery ๐Ÿข. When implemented, the protocol instantiation SHOULD expose controls to the set of "join" and/or "service" policies available to support the needs of different applications ๐ŸŽ›๏ธ.

5.3. Receiver NACK Procedure โœจ

okay so bestie, when a receiver notices it's missing data from a sender's NORM transmissions, it kicks off its NACKing procedure ๐Ÿ™ˆ The NACKing procedure SHALL be initiated only at FEC coding block boundaries, NormObject boundaries, upon receipt of a NORM_CMD(FLUSH) message, or upon an "inactivity" timeout when NORM_DATA or NORM_INFO transmissions are no longer received from a previously active sender.

The RECOMMENDED value of that inactivity timeout is:

         T_inactivity = NORM_ROBUST_FACTOR * 2 * GRTT_sender

where the GRTT_sender value corresponds to the GRTT estimate advertised in the grtt field of NORM sender messages. ๐Ÿ’… A minimum T_inactivity value of 1 second is RECOMMENDED. The NORM receiver SHOULD reset this inactivity timer and repeat NACK initiation upon timeout for up to NORM_ROBUST_FACTOR times or more, depending on how persistent the application needs its receivers to be. ๐Ÿซถ It's also super important that receivers rescale the T_inactivity timeout whenever the sender's advertised GRTT changes, because the math depends on it ๐Ÿ”ฅ

The NACKing procedure begins with a random backoff timeout ๐Ÿฆ‹ The duration of that backoff is chosen with the "RandomBackoff" algorithm from the Multicast NACK Building Block [RFC5401] document, using (K_sender*GRTT_sender) for the maxTime parameter and the sender-advertised group size (GSIZE_sender) as the groupSize parameter. NORM senders hand over GRTT_sender, K_sender and GSIZE_sender through the grtt, backoff, and gsize fields of their transmitted messages. The GRTT_sender value is determined by the sender based on feedback it has received from the group, while K_sender and GSIZE_sender can be set by application requirements and expectations or by ancillary information. The backoff factor K_sender MUST be greater than one to provide for effective feedback suppression. A value of K_sender = 4 is RECOMMENDED for the Any Source Multicast (ASM) model, while a value of K_sender = 6 is RECOMMENDED for Single Source Multicast (SSM) operation.

So, thus:

       T_backoff = RandomBackoff(K_sender*GRTT_sender, GSIZE_sender)

To avoid NACK implosion ๐Ÿ’€ in the case of sender or network failure during SSM operation, the receiver SHALL automatically suppress its NACK and immediately enter the "holdoff" period described below when T_backoff is greater than (K_sender-1)*GRTT_sender. Otherwise, the backoff period is entered, and the receiver MUST accumulate external pending repair state from NORM_NACK messages and NORM_CMD(REPAIR_ADV) messages it receives. When the backoff time ends, the receiver SHALL generate a NORM_NACK message only if the following conditions are met:

  1. The sender's current transmit position (in terms of objectTransportId::fecPayloadId) exceeds the earliest repair position of the receiver.
  2. The repair state accumulated from NORM_NACK and NORM_CMD(REPAIR_ADV) messages does not equal or supersede the receiver's repair needs up to the sender transmission position at the time the NACK procedure (backoff timeout) was initiated.

If these conditions are met, the receiver immediately generates a NORM_NACK message when the backoff timeout expires. Otherwise, the receiver's NACK is considered "suppressed" and the message is not sent. At that point, the receiver begins a "holdoff" period during which it constrains itself from re-initiating the NACKing process. ๐Ÿงš The whole point of this timeout is to give the sender worst-case time to respond to the repair needs before the receiver asks for repair again. The value of this "holdoff" timeout (T_rcvrHoldoff), as described in [RFC5401], is:

              T_rcvrHoldoff =(K_sender+2)*GRTT_sender

The NORM_NACK message contains repair request content beginning with the lowest ordinal repair position of the receiver, up through the coding block prior to the most recently heard ordinal transmission position for the sender. If the size of the NORM_NACK content exceeds the sender's NormSegmentSize, the NACK content gets truncated, so the receiver only generates a single NORM_NACK message per NACK cycle for a given sender. In summary, one NACK message gets generated containing the receiver's lowest ordinal repair needs. ๐ŸŒธ

For each partially received FEC coding block that needs repair, the receiver SHALL, on its FIRST repair attempt for the block, request the parity portion of the FEC coding block beginning with the lowest ordinal parity "encoding_symbol_id" (i.e., "encoding_symbol_id" = "source_block_len"), and request the number of FEC symbols matching its data segment erasure count for the block. On subsequent repair cycles for the same coding block, the receiver SHALL request only those repair symbols from the first set it has not yet received, up to the remaining erasure count for that coding block. Heads up: the sender might have transmitted other, different, additional parity segments meant for other receivers, and those could also help the local receiver fill its erasures ๐Ÿ‘€ In the case where the erasure count for a partially received FEC coding block exceeds the maximum number of parity symbols available from the sender for the block (as indicated by the NORM_DATA "fec_num_parity" field), the receiver SHALL request all available parity segments plus the ordinally highest missing data segments needed to satisfy its total erasure needs for the block. The goal here is for the whole receiver set to request a lowest common denominator set of repair symbols for a given FEC coding block ๐Ÿ“ That lets the sender build the most efficient repair transmission segment set, and it enables effective NACK suppression among receivers even with uncorrelated packet loss. Bonus: this approach doesn't demand that receivers synchronize their repair requests with each other.

For FEC coding blocks or NormObjects missed in their entirety, the NORM receiver builds repair requests with the NORM_NACK_BLOCK or NORM_NACK_OBJECT flags set as appropriate. A request to retransmit NORM_INFO gets made by setting the NORM_NACK_INFO flag in a corresponding repair request.


5.4. Sender NACK Processing and Response ๐Ÿ’œ

The principal goal of the sender is to make forward progress in transmitting the data its application has enqueued. โœจ Still, the sender will occasionally need to "rewind" its logical transmission point to satisfy the repair needs of receivers who have NACKed. When a NACK event happens, multiple NACKs get aggregated to work out an optimal repair strategy. Since receivers start the NACK process on coding block or object boundaries, the repair process stays loosely synchronized, even when receivers experience uncorrelated data loss. Cute, right? ๐ŸŽ€

5.4.1. Sender Repair State Aggregation ๐ŸŒˆ

When a sender is in its normal state of transmitting new data and receives a NACK, it starts a procedure to accumulate NACK repair state from NORM_NACK messages before beginning any repair transmissions. Note that this period of aggregating repair state does not interfere with the sender's ongoing transmission of new data ๐Ÿฆ‹

As described in [RFC5401], the period during which the sender aggregates NORM_NACK messages is equal to:

             T_sndrAggregate = (K_sender + 1) * GRTT_sender

where K_sender is the backoff scaling value advertised to the receivers, and GRTT_sender is the sender's current estimate of the group's greatest round-trip time. Note that for NORM unicast sessions, the T_sndrAggregate time can be set to zero, since there's only one receiver ๐Ÿงš Similarly, the K_sender value SHOULD be set to zero for NORM unicast sessions, to minimize repair latency.

When this period ends, the sender "rewinds" by incorporating the accumulated repair state into its pending transmission state, and then it begins transmitting repair messages. After the pending repair transmissions are completed, the sender continues with new transmissions of any enqueued data. At this point, the sender also begins a "holdoff" timeout, during which it constrains itself from starting a new repair aggregation cycle, even if NORM_NACK messages arrive. As described in [RFC5401], the value of this sender "holdoff" period is:

                      T_sndrHoldoff = (1 * GRTT_sender)

If more NORM_NACK messages come in during this sender "holdoff" period, the sender will immediately fold these late-arriving messages into its pending transmission state if, and only if, the NACK content is ordinally greater than the sender's current transmission position. This "holdoff" time gives worst-case time for the sender to propagate its current transmission sequence position to the group, which helps avoid redundant repair transmissions ๐Ÿ™Œ After the holdoff timeout expires, a new NACK accumulation period can be started (upon arrival of a NACK) in concert with pending repair and new data transmission. Recall that receivers are not to initiate the NACK repair process until the sender's logical transmission position exceeds the lowest ordinal position of their repair needs. With the new NACK aggregation period, the sender repeats the same process: it incorporates the accumulated repair state into its transmission plan and then "rewinds" to transmit the lowest ordinal repair data when the aggregation period expires. Again, this all happens in concert with ongoing new data and/or pending repair transmissions. โœจ

5.4.2. Sender FEC Repair Transmission Strategy โœจ

Okay so the NORM sender SHOULD lean on FEC parity content for repair as much as humanly possible ๐Ÿงš Quick reminder: receivers ask for the lowest common denominator of explicit repair (parity content included) when they build their NORM_NACK messages. Before the sender goes and explicitly fixes each receiver's specific needs, it can use the general erasure-filling superpower of FEC-generated parity segments ๐Ÿฆ‹ The sender can work out the maximum erasure-filling needs for individual FEC coding blocks from the NORM_NACK messages it gets during the repair aggregation period. So if the sender has a sufficient number (less than or equal to the maximum erasure count) of previously unsent parity segments for the applicable coding blocks, it can send those in lieu of the specific packets the receiver set asked for. The sender SHOULD NOT resort to explicit transmission of the receiver set's repair needs until it has used up its supply of "fresh" (unsent) parity segments for a given coding block ๐Ÿ’…

In general, if a sufficiently powerful FEC code is used, explicit repair is the exception, and reliable multicast can be accomplished quite efficiently. However, being able to fall back on explicit repair means the protocol can keep operating even under very extreme circumstances ๐Ÿ’€

NORM_DATA messages sent as repair transmissions SHALL be flagged with the NORM_FLAG_REPAIR flag. This lets receivers obey any policies that limit new receivers from joining the reliable transmission when they've only received repair transmissions ๐Ÿ™ˆ Additionally, the sender SHOULD flag NORM_DATA transmissions sent as explicit repair with the NORM_FLAG_EXPLICIT flag.

Although NORM end system receivers don't make use of the NORM_FLAG_EXPLICIT flag, intermediate systems could leverage this transmission status to "assist" NORM performance ๐ŸŒธ If those systems are properly positioned with respect to reciprocal reverse-path multicast routing, they need to sub-cast only a sufficient count of non-explicit parity repairs to satisfy a multicast routing sub-tree's erasure-filling needs for a given FEC coding block. When the sender has resorted to explicit repair, the intermediate systems SHOULD sub-cast all of the explicit repair packets to those portions of the routing tree still requiring repair for a given coding block. Note the intermediate systems will need to conduct repair state accumulation for sub-routes in a manner similar to the sender's repair state accumulation, so they have enough information to perform the sub-casting. Additionally, intermediate systems could perform NORM_NACK suppression/aggregation as they conduct this repair state accumulation for NORM repair cycles. The details of this type of operation are beyond the scope of this document, but this information is provided for possible future consideration ๐Ÿ”ฎ

5.4.3. Sender NORM_CMD(SQUELCH) Generation

If the sender receives a NORM_NACK message asking for repair of data it's no longer supporting, it generates a NORM_CMD(SQUELCH) message ๐Ÿ™… This advertises its repair window and squelches any receivers from NACKing invalid data any further. The transmission rate of NORM_CMD(SQUELCH) messages is limited to once per 2*GRTT_sender. The invalid_object_list (if applicable) of the NORM_CMD(SQUELCH) message SHALL begin with the lowest object_transport_id from the invalid NORM_NACK messages received since the last NORM_CMD(SQUELCH) transmission. The list includes as many lower ordinal invalid object_transport_id values as can fit in the payload, keeping it less than or equal to the sender's NormSegmentSize parameter โœจ

5.4.4. Sender NORM_CMD(REPAIR_ADV) Generation

When a NORM sender receives NORM_NACK messages from receivers via unicast transmission, it uses NORM_CMD(REPAIR_ADV) messages to advertise its accumulated repair state to the receiver set ๐Ÿซถ This is because receivers aren't directly sharing their repair needs via multicast communication. A NORM sender implementation MAY use a separate port number from the NormSession port number as the source port for its transmissions. That way, NORM receivers can direct any unicast feedback to this separate sender port, distinct from the NORM session (or destination) port number. The sender implementation can then tell unicast feedback apart from multicast feedback when there's a mix of both kinds of receivers.

The NORM_CMD(REPAIR_ADV) message is multicast to the receiver set by the sender. Its payload has content in the same format as the NORM_NACK receiver message payload, so receivers can perform feedback suppression the same way they do with NORM_NACK messages directly received from other receivers. Note the sender doesn't just retransmit NACK content it receives. Instead, it transmits a representation of its aggregated repair state ๐Ÿง  Transmission of NORM_CMD(REPAIR_ADV) messages is subject to the sender transmit rate limit and the NormSegmentSize limitation. When the NORM_CMD(REPAIR_ADV) message is of maximum size (as indicated by the flag NORM_REPAIR_ADV_FLAG_LIMIT), receivers SHALL consider the maximum ordinal transmission position value embedded in the message as the sender's current transmission position, and implicitly suppress requests for ordinally higher repair.

For congestion control operation, the sender will also need to provide any information needed so dynamic congestion control feedback can be suppressed among receivers. This document specifies the NORM-CC Feedback Header Extension that is applied for baseline NORM-CC operation. If other congestion control mechanisms are used within a NORM implementation, other header extensions MAY be defined. Whatever content format is used for this purpose SHOULD ensure that the maximum possible suppression state is conveyed to the receiver set ๐ŸŒŸ


5.5. Additional Protocol Mechanisms ๐ŸŒˆ

In addition to the main job of data content transmission and repair, NORM has some other protocol mechanisms that help it adapt to network conditions and play fair with the other protocols it coexists with.

5.5.1. Group Round-Trip Time (GRTT) Collection

Okay this part is so clever ๐Ÿ’œ For NORM receivers to scale their backoff timeouts appropriately, and for the senders to use matching timeouts, everyone needs a common timeout basis. Each NORM sender monitors the round-trip time of active receivers and determines the greatest group round-trip time. The sender advertises this GRTT estimate in every message it transmits, so receivers have this value on hand for scaling their timers. To measure the current GRTT, the sender periodically sends NORM_CMD(CC) messages containing a locally generated timestamp. Receivers are expected to record this timestamp along with the time the NORM_CMD(CC) message is received. Then, when receivers generate feedback messages to the sender, an adjusted version of the sender timestamp is embedded in the feedback message (NORM_NACK or NORM_ACK). The adjustment adds the amount of time the receiver held the timestamp before generating its response. Upon receipt of this adjusted timestamp, the sender is able to calculate the round-trip time to that receiver โฑ๏ธ

The round-trip time for each receiver is fed into an algorithm that assigns weights and smooths the values for a conservative estimate of the GRTT. The algorithm and methodology are described in the Multicast NACK Building Block [RFC5401] document in the section entitled "One-to-Many Sender GRTT Measurement". A conservative estimate helps guarantee feedback suppression, at a small cost in overall protocol repair delay ๐Ÿ“ The sender's current estimate of GRTT is advertised in the grtt field found in all NORM sender messages. The advertised GRTT is also limited to a minimum of the nominal inter-packet transmission time, given the sender's current transmission rate and system clock granularity. The reason for this extra limit is to keep the receiver somewhat event-driven, by making sure the sender has had adequate time to generate any response to repair requests from receivers, given transmit rate limitations due to congestion control or configuration.

When the NORM-CC Rate header extension is present in NORM_CMD(CC) messages, receivers respond to NORM_CMD(CC) messages as described in Section 5.5.2, "NORM Congestion Control Operation". The NORM_CMD(CC) messages are periodically generated by the sender as described for congestion control operation. This provides for proactive, but controlled, feedback from the group in the form of NORM_ACK messages, and it provides GRTT feedback even if no NORM_NACK messages are being sent ๐Ÿฆ‹ If operating without congestion control in a closed network, the NORM_CMD(CC) messages MAY be sent periodically without the NORM-CC Rate header extension. In this case, receivers will only provide GRTT measurement feedback when NORM_NACK messages are generated, since no NORM_ACK messages are generated. Under those conditions, the NORM_CMD(CC) messages MAY be sent less frequently, perhaps as little as once per minute, to conserve network capacity. Note the NORM-CC Rate header extension MAY also be used to proactively solicit RTT feedback from the receiver group per congestion control operation, even when the sender is not conducting congestion control rate adjustment. NORM operation without congestion control SHOULD be considered only in closed networks ๐Ÿ”’

5.5.2. NORM Congestion Control Operation ๐Ÿฆ‹

okay bestie, this section is about congestion control, and it's giving main character energy ๐Ÿ’… NORM-CC is the baseline, and it's basically a remix of the equation-based TFMCC approach from [RFC4654] โœจ This scheme is REQUIRED for running on the general Internet, unless your NORM implementation swaps in a different IETF-sanctioned reliable multicast congestion control mechanism ๐Ÿซถ

With TFMCC, senders are rate-based, not window-based like TCP ๐ŸŒธ That said, the NORM message set MAY also be used to support a window-based scheme like PGMCC ๐Ÿ”ฅ Any details about that alternative MAY be described separately or in a future revision of this doc ๐Ÿงš

Either way (rate-based TFMCC or window-based PGMCC), the sender can only control its transmissions well if it collects loss estimates and RTTs from the senders' paths to receivers ๐Ÿ“Š That's how it finds the congestion bottleneck paths in the multicast topology and adjusts its rate. The receiver whose loss and RTT estimates give the lowest calculated transmission rate becomes the "current limiting receiver" (CLR) ๐Ÿ‘‘ If there's a tie (candidate CLRs are within 10% of the same calculated rate), the receiver with the largest RTT SHOULD be designated as the CLR ๐Ÿ’€

As [TcpModel] explains, a steady-state sender rate that stays "friendly" with competing TCP flows can be calculated like this ๐Ÿ“

                                    S
   Rsender = ----------------------------------------------------------
           T_rtt*(sqrt((2/3)*p) + 12*sqrt((3/8)*p) * p * (1 + 32*(p^2)))

where:

  • S = nominal transmitted packet size. (In NORM, the "nominal" packet size can be determined by the sender as an exponentially weighted moving average (EWMA) of transmitted packet sizes, so it handles variable message sizes ๐ŸŒˆ)
  • T_rtt = RTT estimate of the current "current limiting receiver" (CLR) ๐Ÿ“
  • p = loss event fraction of the CLR ๐Ÿ“‰

To make congestion control feedback work, the NORM sender periodically sends NORM_CMD(CC) command messages ๐Ÿ’Œ These get multiplexed with NORM data and repair transmissions, and they do three big jobs:

  1. They get explicit feedback from the general receiver set to collect congestion control info ๐Ÿ—ณ๏ธ
  2. They tell the receivers the sender's current congestion control status, including details of the CLR ๐Ÿ“ฃ
  3. They kick off rapid, immediate feedback from the CLR so everyone can track the congestion control dynamics of the current worst path in the group topology ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

The format of the NORM_CMD(CC) message is described in Section 4.2.3 of this document ๐Ÿ“– It's how RTTs get measured, how the group learns who the CLR is, and how individual RTT measurements get passed back to receivers ๐Ÿค It also gets feedback going from OPTIONAL "potential limiting receiver" (PLR) nodes. Those might be picked administratively, or algorithmically from congestion control feedback ๐Ÿ•ต๏ธโ€โ™€๏ธ PLRs are receivers that could soon become the CLR, so getting their up-to-date feedback right away really helps congestion control perform well ๐Ÿ’– The PLR list MAY be filled with a small number of receivers the sender sees approaching the CLR's loss and delay conditions, based on group feedback ๐ŸŽฏ

5.5.2.1. NORM_CMD(CC) Transmission ๐Ÿ’ซ

The NORM_CMD(CC) message gets sent periodically by the sender, right alongside its normal data transmission ๐Ÿš€ Also, the repeated sending of NORM_CMD(CC) messages MAY start a bit before any user data goes out at session startup ๐ŸŒท That gives the sender a head start on how the multicast topology looks, in terms of group and individual RTT and congestion control state ๐Ÿ‘€

A NORM_CMD(CC) message gets sent right away at sender startup โšก After that, here's how the interval works ๐Ÿง 

  1. By default, the interval is set based on the current sender GRTT estimate. A startup initial value of GRTT_sender = 0.5 seconds is RECOMMENDED when no feedback has come in from the group yet ๐Ÿผ
  2. Until a CLR has been identified (based on earlier receiver feedback), or when there's no data transmission pending, the NORM_CMD(CC) interval doubles from its current value, up to a max of once every 30 seconds ๐Ÿ˜ด That keeps the duty cycle super low for probing when there's no CLR or nothing to send ๐ŸŒ™
  3. When a CLR has been identified (based on receiver feedback) and data transmission is pending, the probing interval gets set to the RTT between the sender and the CLR (RTT_clr) ๐ŸŽฏ
  4. Also, when the data rate is low compared to the RTT_clr probing interval, the implementation SHOULD make sure no more than one NORM_CMD(CC) message goes out per NORM_DATA message while data is pending ๐Ÿ™…โ€โ™€๏ธ That way, control traffic never hogs the spotlight and pushes user data out ๐Ÿซง

The NORM_CMD(CC) cc_sequence field gets incremented with every NORM_CMD(CC) sent ๐Ÿ”ข The greatest cc_sequence recently received by the receivers gets included in their feedback to the sender. That's how the sender figures out how old the feedback is, which helps with congestion avoidance ๐Ÿ•ฐ๏ธ

The NORM-CC Rate Header Extension is applied to the NORM_CMD(CC) message, and the sender advertises its current transmission rate in the send_rate field ๐Ÿ“ˆ Receivers use that rate info to initialize loss estimation when congestion control starts up or restarts ๐Ÿšฆ

The cc_node_list holds entries for receivers and their current congestion control state (the status flags, rtt, and loss estimates) ๐Ÿ—‚๏ธ The list will be empty if the sender hasn't gotten any feedback from the group yet. Once feedback comes in, the list will at minimum include an entry for the CLR ๐Ÿ‘‘ The NORM_FLAG_CC_CLR flag value goes in the cc_flags field to mark the CLR entry, and it's RECOMMENDED that the CLR entry be first in the list, because that's more efficient for implementations ๐Ÿ…

Any extra entries in the list give the sender a way to share individually measured RTT estimates with receivers ๐Ÿค How many extra entries you get depends on what percentage of control traffic the sender app is willing to spend compared to user data ๐Ÿ’ธ More entries means the sender can react faster to congestion control dynamics โšก The length of the list can be figured out on the fly, based on the current transmission rate and how NORM_CMD(CC) messages are scheduled ๐Ÿงฎ The max length of the list matches the sender's NormSegmentSize parameter for the session ๐Ÿ“ When receiver feedback decides which extra entries make it in, these rules apply, in order ๐Ÿ‘‡

  1. Receivers that haven't been given an RTT measurement yet get first priority. Of those, the ones with the greatest loss fraction get the spot first ๐Ÿฅ‡
  2. Next, receivers that have already been given an RTT measurement get included, with the ones yielding the lowest calculated congestion rate getting precedence ๐Ÿฅˆ

There are also cc_flags values beyond NORM_FLAG_CC_CLR for other congestion control jobs ๐Ÿงฉ The NORM_FLAG_CC_PLR flag value marks extra receivers the sender wants immediate, non-suppressed feedback from ๐Ÿ”” These could be receivers the sender algorithmically spotted as possible future CLRs, or ones that were pre-configured as potential congestion control points in the network ๐Ÿ›ค๏ธ The NORM_FLAG_CC_RTT flag shows whether the cc_rtt field is valid for that receiver node ๐Ÿง Usually it'll be set, since receivers on the list will typically be ones the sender already got feedback from. But if the sender was pre-configured with a set of PLR nodes, feedback from those might not have been collected yet, so cc_rtt won't hold a valid value when this flag isn't set ๐Ÿคทโ€โ™€๏ธ And finally, a value of ZERO for the cc_rate field MUST be treated as an invalid value and ignored for feedback suppression and so on ๐Ÿšซ No cap, that one's important ๐Ÿ™ˆ

5.5.2.2. NORM_CMD(CC) Feedback Response

okay so receivers answer NORM_CMD(CC) messages with a NORM_ACK(RTT) message ๐Ÿ’Œ. the whole point of this feedback is figuring out which receivers have the lowest congestion control rates ๐Ÿ‘€. receivers marked as CLR or PLR nodes in the NORM_CMD(CC) cc_node_list jump in immediately with a NORM_ACK to this message ๐Ÿ™‹โ€โ™€๏ธ. when a NORM_CMD(CC) arrives, non-CLR or non-PLR nodes start random feedback backoff timeouts, kinda like the ones receivers use when they start a repair cycle (see Section 5.3) after noticing data loss ๐Ÿซ . the backoff timeout for the congestion control response is generated like this:

T_backoff = RandomBackoff(K_backoff * GRTT_sender, GSIZE_sender)

RandomBackoff() gives you a truncated exponentially distributed random number, and it's explained in the Multicast NACK Building Block [RFC5401] document ๐Ÿ“š. the same backoff factor, K_backoff = K_sender, that's used with NORM_NACK suppression is generally RECOMMENDED ๐Ÿ’…. however, if the application deliberately picks a very small K_sender backoff factor to cut down NACK repair latency (trading off group size scalability), it is RECOMMENDED a larger backoff factor for congestion control feedback be maintained ๐Ÿ™ˆ. that's because there can be a bigger volume of congestion control feedback than NACKs in many cases, and some congestion control feedback latency might be tolerable where reliable delivery latency isn't ๐ŸŒธ. as noted earlier, a backoff factor value of K_sender = 4 is generally RECOMMENDED for ASM operation, and K_sender = 6 for SSM operation โœจ. a receiver SHALL cancel the backoff timeout, and therefore its pending transmission of a NORM_ACK(RTT) message, under the following conditions:

  1. the receiver generates another feedback message (NORM_NACK or other NORM_ACK) before the congestion control feedback timeout expires. these messages carry the current congestion control feedback information ๐Ÿซถ.
  2. a NORM_CMD(CC) or other receiver feedback with an ordinally greater "cc_sequence" field value is received before the congestion control feedback timeout expires. this is kinda like the TFMCC feedback round number ๐Ÿ”ฅ.
  3. when the T_backoff is greater than 1*GRTT_sender. this prevents NACK implosion in the event of sender or network failure ๐Ÿ’€.
  4. "suppressing" congestion control feedback is heard from another receiver (in a NORM_ACK or NORM_NACK) or via a NORM_CMD(REPAIR_ADV) message from the sender. the local receiver's feedback is "suppressed" if the rate of the competing feedback (Rfb) is sufficiently close to or less than the local receiver's calculated rate (Rcalc). the local receiver's feedback is canceled when Rcalc > (0.9 * Rfb). also, receivers that haven't received an RTT measurement from the sender yet are suppressed only by other receivers that haven't measured RTT yet either ๐Ÿงš. receivers whose RTT estimate has aged a lot (meaning they haven't been in the NORM_CMD(CC) cc_node_list in a long time) might want to compete as a receiver with no prior RTT measurement after some long-term expiration period ๐Ÿฆ‹.

when the backoff timer expires, the receiver SHALL generate a NORM_ACK(RTT) message to give feedback to the sender and the group ๐Ÿ“ฃ. this message MAY be multicast to the group for the most effective suppression in ASM topologies, or unicast to the sender, depending on how NORM is deployed and configured ๐ŸŒˆ.

whenever any feedback gets generated (this NORM_ACK(RTT) included), receivers add an adjusted version of the sender timestamp from the most recently received NORM_CMD(CC) message, plus its "cc_sequence" value, to the corresponding NORM_ACK or NORM_NACK message fields ๐ŸŽ€. for NORM-CC operation, any generated feedback message SHALL also contain the NORM-CC Feedback header extension ๐Ÿ’œ. the receiver shares its current "cc_rate" estimate, "cc_loss" estimate, "cc_rtt" if it's known, and any applicable "cc_flags" through this header extension ๐Ÿ’–.

during slow start (when the receiver hasn't detected loss from the sender yet), the receiver puts two times its measured rate from the sender into the "cc_rate" field ๐Ÿš€. for steady-state congestion control operation, the receiver's "cc_rate" value comes from the equation-based value, using its current loss event estimate and sender<->receiver RTT information. (GRTT_sender is used when the receiver hasn't measured its individual RTT yet ๐Ÿซ .)

the "cc_loss" field value reflects the receiver's current loss event estimate with respect to the sender in question ๐Ÿ“Š.

when the receiver has a valid individual RTT measurement, it SHALL include this value in the "cc_rtt" field ๐Ÿง . the NORM_FLAG_CC_RTT MUST be set when the "cc_rtt" field is valid ๐Ÿ™Œ.

after a congestion control feedback message gets generated, or when the feedback is suppressed, a non-CLR receiver starts a "holdoff" timeout period. during this time it holds back from giving congestion control feedback, even if NORM_CMD(CC) messages come in from the sender (unless the receiver becomes marked as a CLR or PLR node) ๐Ÿ™…โ€โ™€๏ธ. the value of this holdoff timeout (T_ccHoldoff) period is:

T_ccHoldoff = (K_sender * GRTT_sender)

so non-CLR receivers are limited to giving explicit congestion control feedback once per K_sender*GRTT_sender interval ๐Ÿ•ฐ๏ธ. however, as the session goes on, different receivers respond to different NORM_CMD(CC) messages, and there's pretty much continuous feedback of congestion control information while the sender is active ๐ŸŒŠ.


5.5.2.3. Congestion Control Rate Adjustment

during steady-state operation, the sender directly adjusts its transmission rate to match the rate in the feedback from its currently selected CLR ๐ŸŽฏ. as noted in [TfmccPaper], estimating the CLR's parameters (loss and RTT) will generally limit how much the rate can change, keeping it within acceptable bounds ๐Ÿง. for rate increases, the sender SHALL observe a maximum rate of increase of one packet per RTT at all times during steady-state operation ๐Ÿข.

the sender processes congestion control feedback from the receivers and picks the CLR based on the lowest rate receiver ๐Ÿ‘‘. receiver rates are determined either directly from the slow start "cc_rate" that the receiver provides in the NORM-CC Feedback header extension, or by running the equation-based calculation with individual RTT and loss estimates ("cc_loss") as feedback comes in ๐Ÿงฎ.

the sender can calculate a current RTT for a receiver (RTT_rcvrNew) using the "grtt_response" timestamp included in feedback messages ๐Ÿ•. when the "cc_rtt" value in a response isn't valid, the sender just uses this RTT_rcvrNew value as the receiver's current RTT (RTT_rcvr) ๐Ÿคทโ€โ™€๏ธ. for non-CLR and non-PLR receivers, the sender SHOULD use the "cc_rtt" provided in the NORM-CC Feedback header extension as the receiver's previous RTT measurement (RTT_rcvrPrev), averaged with the current measurement ("RTT_rcvrNew") to get the receiver's RTT value ๐Ÿ’…:

RTT_rcvr = 0.5 * RTT_rcvrPrev + 0.5 * RTT_rcvrNew

for CLR receivers, where feedback arrives more regularly, the sender SHOULD keep a more smoothed RTT estimate every time new feedback comes in from the CLR ๐ŸŒท:

RTT_clr = 0.9 * RTT_clr + 0.1 * RTT_clrNew

RTT_clrNew is the new RTT calculated from the timestamp in the feedback message received from the CLR ๐Ÿงพ. RTT_clr is set to RTT_clrNew on the first feedback message received ๐Ÿฅ‡. note that the sender follows the same procedure for PLR receivers too, and if a PLR gets "promoted" to CLR status, the smoothed estimate can keep going ๐Ÿš€.

besides steady-state operation, there are some other periods to think about in NORM-CC operation. these are:

  1. during session startup,
  2. when no feedback is received from the CLR, and
  3. when the sender has a break in data transmission.

during session startup, the congestion control operation SHALL observe a "slow-start" procedure to quickly reach its fair bandwidth share ๐Ÿƒโ€โ™€๏ธ. an initial sender startup rate is assumed, where:

Rinit = MIN(NormSegmentSize/GRTT_sender, NormSegmentSize) bytes/sec

the rate only goes up when feedback comes in from the receiver set ๐Ÿ“ˆ. the "slow start" phase keeps going until any receiver gives feedback saying loss has happened ๐Ÿ™€. the rate increase during slow start is applied as:

Rnew = Rrecv_min

where Rrecv_min is the minimum reported receiver rate in the "cc_rate" field of congestion control feedback messages received from the group ๐Ÿ”. note that during slow start, receivers put two times their measured rate from the sender into the "cc_rate" field of their feedback โœŒ๏ธ. the rate increase adjustment is limited to once per GRTT during slow start โณ.

if the CLR or any receiver plans to leave the group, it sets the NORM_FLAG_CC_LEAVE in its congestion control feedback message to signal that the sender SHOULD NOT select it as the CLR ๐Ÿšช. when the CLR changes to a lower rate receiver, the sender SHOULD immediately adjust to the new lower rate ๐Ÿ“‰. the sender is limited to increasing its rate by one additional packet per RTT toward any new, higher CLR rate ๐ŸŒ.

the sender SHOULD also keep track of the age of the feedback it has received from the CLR, by comparing its current "cc_sequence" value (Seq_sender) to the last "cc_sequence" value received from the CLR (Seq_clr) ๐Ÿ•ต๏ธโ€โ™€๏ธ. as the CLR feedback gets older with no new feedback, the sender SHALL begin reducing its rate once per RTT_clr as a congestion avoidance measure ๐Ÿ›ก๏ธ. the following algorithm determines the decrease in sender rate (Rsender bytes/sec) as the CLR feedback unexpectedly and excessively ages ๐Ÿซฃ:

Age = Seq_sender - Seq_clr;
if (Age > 4) Rsender = Rsender * 0.5;

this rate reduction is limited to the lower bound on NORM transmission rates ๐Ÿงฑ. after NORM_ROBUST_FACTOR consecutive NORM_CMD(CC) rounds without any feedback from the CLR, the sender SHOULD assume the CLR has left the group and pick the receiver with the next lowest rate as the new CLR ๐Ÿ‘‹. note this assumes the sender doesn't explicitly know the CLR intentionally left the group ๐Ÿค”. if no receiver feedback comes in, the sender MAY wish to hold off on further NORM_DATA segment transmissions and only keep sending NORM_CMD(CC) transmissions until feedback is detected ๐Ÿซธ. after a CLR timeout like this, the sender will be transmitting at a minimal rate and SHOULD return to slow start, as described here for a break in data transmission ๐Ÿ”„.

when the sender has a break in its data transmission, it can keep probing the group with NORM_CMD(CC) messages to keep RTT collection going ๐Ÿ›ฐ๏ธ. this lets the sender quickly figure out an appropriate CLR when data transmission restarts ๐Ÿ.

however, the sender SHOULD exponentially reduce its target rate, the one used for transmission restart, as time since the break goes on ๐Ÿ‚. the target rate SHOULD be recalculated once per RTT_clr as:

Rsender = Rsender * 0.5;

if the minimum NORM rate is reached, the sender SHOULD set the NORM_FLAG_START flag in its NORM_CMD(CC) messages upon restart, and the group SHOULD observe slow-start congestion control procedures until any receiver experiences a new loss event ๐ŸŒŸ.

5.5.3. NORM Positive Acknowledgment Procedure โœจ

Okay bestie, so NORM lets the source app ask the group for a positive acknowledgment (ACK) ๐Ÿซถ of NORM_CMD(FLUSH) and NORM_CMD(ACK_REQ) messages. There are a few specific ack requests already defined, plus a whole range of ack_type values left for the app to define itself ๐ŸŽ€. One predefined type is NORM_ACK(FLUSH). It's how the sender finds out whether receivers have finished reliably receiving everything up through a specific point in its transmission sequence ๐Ÿฆ‹. If the sender knows about some of the receivers, NORM_ACK(FLUSH) MAY be used to help with application flow control ๐Ÿ’….

Another predefined type is NORM_ACK(CC), which gives explicit congestion control feedback in reply to NORM_CMD(CC) messages the sender transmits for NORM-CC operation. Note that the NORM_ACK(CC) response does NOT follow the positive acknowledgment procedure described here ๐Ÿ‘‘. Both NORM_CMD(ACK_REQ) and NORM_ACK messages have an ack_type field, which says what kind of ack was requested and what kind was provided ๐Ÿ’œ. The app is the one that starts the ack request and interprets its own ack_type values, but the acknowledgment procedure SHOULD be run inside the protocol implementation, so it can use the timing and transmission scheduling info that NORM has ๐Ÿงš.

The NORM Positive Acknowledgment Procedure uses polling, where the sender asks the receiver group to respond ๐ŸŒธ. Heads up, this polling is NOT meant to scale to very large groups ๐Ÿ™ˆ. It can still work in a big group if you're querying a critical subset of it. Either NORM_CMD(ACK_REQ), or NORM_CMD(FLUSH) when that applies, is used for polling. Each one carries a list of the NormNodeIds of the receivers that are expected to respond โœจ. The source app decides who goes on that list, either from prior knowledge of the participating nodes or through some other app-level mechanism ๐Ÿ“.

The ack process starts when the sender generates NORM_CMD(FLUSH) or NORM_CMD(ACK_REQ) messages in periodic rounds ๐Ÿ”ฅ. For NORM_ACK(FLUSH) requests, the NORM_CMD(FLUSH) has an object_transport_id and a fec_payload_id that mark the watermark transmission point being asked about. Receivers echo that watermark point back in the matching fields of their NORM_ACK(FLUSH) response ๐Ÿ’–. NORM_CMD(ACK_REQ) messages have an ack_id field that gets echoed back the same way, so the sender can match each response to the right request ๐Ÿฆ‹.

When a NORM_CMD(ACK_REQ) arrives, the listed receivers each pick a random time, uniformly distributed, and send their NORM_ACK messages somewhere inside a window of (1*GRTT_sender) โฐ. These NORM_ACK messages are usually unicast back to the sender. (Heads up, NORM_ACK(CC) messages SHALL be multicast or unicast in the same way NORM_NACK messages are ๐Ÿ’….)

This whole ack process is self-limiting, which means it avoids ACK implosion, because:

  1. Only a single NORM_CMD(ACK_REQ) message is generated once per (2*GRTT_sender), and
  2. The size of the acking_node_list of NormNodeIds that ack is requested from is capped at the sender's NormSegmentSize setting for each round of the positive acknowledgment process ๐ŸŒˆ.

Because that list is capped at NormSegmentSize, it sometimes takes several NORM_CMD(ACK_REQ) rounds to hear back from everyone on the list ๐Ÿ™ˆ. The NormNodeId list in the attached acking_node_list keeps getting updated as the process goes on and NORM_ACK responses come in from the receivers on it. Every time the sender gets a valid response (one that matches the watermark point or ack_id), it SHALL drop that receiver from the next NORM_CMD(ACK_REQ) acking_node_list, and add any pending receiver NormNodeIds, as long as the list stays within the NormSegmentSize limit โœจ. Each receiver only gets asked a maximum number of times, which is NORM_ROBUST_FACTOR by default ๐ŸŽ€. If a receiver doesn't respond within that many requests, it gets removed from the payload list to make room for other pending receivers. The NORM_CMD(ACK_REQ) keeps getting sent until nobody needs a response anymore, or until every pending receiver has gone past the repeat threshold ๐Ÿ’€.

Sending NORM_CMD(ACK_REQ) or NORM_CMD(FLUSH) for the positive ack process is multiplexed with the sender's ongoing data transmissions ๐Ÿงš. The NORM_CMD(FLUSH) positive acknowledgment process MAY be interrupted to deal with negative acknowledgment repair requests (NACKs) that come in from receivers during the ack period ๐Ÿ˜ญ. Once any repairs have gone out, the NORM_CMD(FLUSH) positive acknowledgment process restarts for the receivers that are still pending acknowledgment ๐Ÿ’œ.

For NORM_CMD(FLUSH) commands that have an attached acking_node_list, receivers won't ACK until they've received the complete transmission of all data up to and including the given watermark transmission point ๐Ÿซถ. All receivers SHALL interpret the watermark point given in a request NACK for repairs, if repairs are needed, the same way they interpret it for NORM_CMD(FLUSH) commands with no attached acking_node_list ๐Ÿ‘‘.


5.5.4. Group Size Estimate ๐ŸŒˆ

NORM sender messages have a gsize field, which is an estimate of the group size. Receivers use it to scale their random backoff timer ranges โฐ. The estimate doesn't need to be precise to work well. If it's within an order of magnitude of the real group size, that's fine ๐Ÿ’…. By default, the NORM sender group size estimate MAY be administratively configured ๐ŸŽ€. Since NORM is expected to scale well for general use, a default value of 10,000 is RECOMMENDED for the group size estimate โœจ. The group size MAY also be algorithmically approximated from the volume of congestion control feedback messages, based on the exponentially weighted random backoff ๐Ÿฆ‹. The specification for that kind of algorithm is currently beyond the scope of this document ๐Ÿ™ˆ.

6. Configurable Elements โœจ

okay bestie, NORM has a modest number of configurable parameters that control how it runs ๐ŸŽ€ Most of them only need to be set at the NORM sender(s), and then the sender tells the receiver set about them through NORM header and/or header extension fields ๐Ÿ’Œ The big exception is NORM_ROBUST_FACTOR, which is presumed to be a common value preset among senders and receivers for a given NORM session ๐Ÿซถ Here's the whole lineup:

+--------------------+----------------------------------------------+
| Configurable       | Purpose                                      |
| Element            |                                              |
+--------------------+----------------------------------------------+
| Sender initial     | Sender's initial estimate of greatest group  |
| GRTT Estimate      | round-trip time.  Affects timing of feedback |
| (GRTT_sender)      | suppression and sender command transmissions |
|                    | at sender startup.                           |
| Backoff Factor     | Sender's scaling factor used for timer-based |
| (K_sender)         | feedback suppression.                        |
| Group Size         | Sender's rough estimate of receiver group    |
| Estimate           | size used in generation of random feedback   |
| (GSIZE_sender)     | backoff timeout.                             |
| NORM_ROBUST_FACTOR | Integer factor determining how persistently  |
|                    | (i.e., robust) senders transmit repeated     |
|                    | control messages and receivers self-initiate |
|                    | timeout-based NACKing in the absence of      |
|                    | sender activity.                             |
| FEC Type           | Sender FEC encoding type.                    |
| ("fec_id")         |                                              |
| Sender segment     | Maximum size (in bytes) of the payload       |
| size               | portion of NORM_DATA and other messages.     |
| (NormSegmentSize)  |                                              |
| NormNodeId         | Unique identifiers pre-assigned to all NORM  |
|                    | session participants.                        |
+--------------------+----------------------------------------------+

The sender-controlled GRTT estimate (aka GRTT_sender) is the thing that sets and scales the various timers used in NORM โฑ๏ธ During steady-state operation, the sender probes the receiver set, adapts to the group round-trip timing state, and advertises its estimate to the receiver set in the grtt field of relevant NORM protocol messages ๐Ÿ“ก But an initial value has to be assumed at sender startup, so that's where it gets interesting ๐Ÿ‘€ A large initial estimate is conservative and safer when it comes to preventing feedback implosion and starting up congestion control operation ๐Ÿ›ก๏ธ The tradeoff is that it requires the sender and receivers to allocate more buffering resources for a given transmission rate (i.e., larger effective delay*bandwidth product) to keep things running efficiently ๐Ÿง  A default initial value of GRTT_sender = 0.5 seconds is RECOMMENDED ๐Ÿ“

The sender-controlled Backoff Factor (referred to as K_sender in this document) scales protocol timers and contributes to generating the random backoff timeout value that makes timer-based feedback suppression work ๐Ÿฆ‹ The sender advertises its configured Backoff Factor to the receiver set in the backoff field of applicable NORM messages, so no receiver configuration is necessary, periodt โœจ For ASM operation, a default value of K_sender = 4 is RECOMMENDED; for SSM operation, a default value of K_sender = 6 is RECOMMENDED ๐Ÿ’…


The sender estimate of session Group Size (referred to as GSIZE_sender in this document) also plays a role in randomly picking feedback suppression timeout values ๐ŸŽฒ The sender advertises its configured Group Size estimate to the receiver set in the gsize field of applicable NORM messages, so again, no receiver configuration needed ๐Ÿ™Œ Only a rough estimate (i.e., "order-of-magnitude") is needed for effective feedback suppression, and a default value of GSIZE_sender = 10,000 is RECOMMENDED as a conservative estimate for most uses ๐Ÿ’œ

The NORM_ROBUST_FACTOR is an integer parameter that determines how persistently NORM senders transmit control messages (NORM_CMD messages) such as end-of-transmission flushing, OPTIONAL positive acknowledgment requests, etc. ๐Ÿ“ฃ On top of that, receivers use their knowledge of NORM_ROBUST_FACTOR to decide when to consider a NORM sender inactive, and they MAY use the factor in deciding how persistently to self-initiate repeated NACK repair requests when those timeouts hit ๐ŸŒธ This parameter is NOT communicated in NORM protocol message headers, and it's presumed to be preset to a consistent value among sender and receivers for a given NORM session ๐Ÿค A default value of NORM_ROBUST_FACTOR = 20 is RECOMMENDED ๐ŸŒˆ

Another NORM sender configuration element is the FEC type used to encode NORM_DATA message content ๐Ÿงš The FEC type is communicated from the sender to the receiver set in the fec_id field of relevant NORM message headers. The fec_id value corresponds to an IANA-assigned value that identifies the FEC encoding type as described in the FEC Building Block [RFC5052] document ๐Ÿ“š Typically, a sender SHOULD use a consistent FEC encoding for its participation in a session, which keeps receiver state allocation and maintenance simple ๐Ÿงธ Its implementations MAY vary the FEC encoding type on a per-object basis if necessary ๐Ÿ”„

The sender NormSegmentSize setting determines the maximum size of the payload portion of NORM_DATA and other messages that the sender transmits ๐Ÿ“ฆ The payload size of feedback messages from receivers to a given sender is also limited to that sender's NormSegmentSize ๐Ÿซง The NormSegmentSize SHOULD be configured to be compatible with expected network MTU limitations, once you factor in the added overhead of NORM, UDP, and IP protocol message headers ๐Ÿงฎ MTU Discovery MAY be employed by the sender to determine an appropriate NormSegmentSize ๐Ÿ” Receivers can work out the NormSegmentSize for a given sender from the FEC Object Transmission Information (FTI) provided either in applied EXT_FTI header extensions or in pre-configured session information ๐Ÿ•ต๏ธโ€โ™€๏ธ

Although it's not technically a configurable element, the receivers MUST have FEC Object Transmission Information for transmitted NormObjects so they can properly buffer, decode, and reassemble the original content ๐Ÿงฉ For loosely organized NORM protocol sessions, the sender MAY apply the EXT_FTI Header Extension to NORM_DATA and NORM_INFO (if applicable) messages, so receivers can get this information without prior coordination ๐Ÿค™ An implementation MAY also apply the EXT_FTI only to NORM_INFO messages for reduced overhead ๐Ÿ’จ And finally, applications MAY also provide the FTI out-of-band prior to sender transmission ๐Ÿ“ฌ


Each participant in a NORM protocol session MUST be configured with a unique NormNodeId value ๐Ÿชช Receivers use the NormNodeId to identify the sender that their NACK or other feedback messages are addressed to, and senders use the NormNodeId to tell receivers apart for congestion control and OPTIONAL positive acknowledgment collection ๐Ÿ‘‘ Unique NormNodeId values can be assigned through a priori coordination and/or a deconfliction mechanism that lives outside the NORM protocol itself ๐Ÿค

the values NORM_NODE_NONE = 0x00000000 and NORM_NODE_ANY = 0xffffffff are reserved, so they MUST NOT be assigned to NORM participants ๐Ÿšซ๐Ÿ’€

7. Security Considerations ๐Ÿ›ก๏ธโœจ

okay bestie, security time ๐Ÿซถ The same security considerations that apply to the Multicast NACK [RFC5401], TFMCC [RFC4654], and FEC [RFC5052] Building Blocks also apply to the NORM protocol ๐Ÿ’…. On top of the usual vulnerabilities that any IP and IP multicast protocol implementation has, malicious hosts might go on an excessive NACKing spree ๐Ÿ˜ญ to stop NORM senders from making forward progress in reliable transmission. If that kind of activity is detected, receiver "join" and "service" policy enforcement (as described in Section 5.2) can be applied ๐Ÿšซ.

The use of cryptographic peer authentication, integrity checks, and/or confidentiality mechanisms can be used to give a more effective degree of protection from objectionable transmissions from unauthorized hosts ๐Ÿ”. But in some cases, even with authentication and integrity checks, the NACK-based feedback of NORM can be exploited by replay attacks that force the NORM sender to unnecessarily transmit repair information ๐Ÿ’€. This MAY be addressed in part with network-layer IP security implementations that guard against this potential security exploitation, or alternatively with a security mechanism using the EXT_AUTH header extension for similar purposes. Such security mechanisms SHOULD be deployed and used when available ๐Ÿ‘‘. Using security mechanisms will add extra "a priori" configuration to the NORM deployment, depending on the techniques used ๐ŸŽ€.

The NORM protocol is compatible with the use of IP security (IPsec) [RFC4301], and the IPsec Encapsulating Security Payload (ESP) protocol or Authentication Header (AH) extension can be used to secure IP packets transmitted by NORM participants ๐Ÿฆ‹. A baseline approach to secure NORM operation using IPsec is described below. Compliant implementations of this specification are REQUIRED to be compatible with IPsec usage as described in Section 7.1 ๐ŸŒธ. IPsec can be used to provide peer authentication, integrity protection, and/or encryption of packets containing NORM messages โœจ.

Additionally, the EXT_AUTH header extension (HET = 1) is reserved for use by security mechanisms that provide alternatives to IPsec for the security of NORM messages ๐Ÿงš. The format of this header extension and its processing is outside the scope of this document, and it is to be communicated out-of-band as part of the session description ๐Ÿ“œ. It is possible an EXT_AUTH implementation MAY also provide for encryption of NORM message payloads as well as peer authentication and integrity protection ๐Ÿ”‘. Using this approach instead of IPsec can allow header compression techniques to be applied jointly to IP and NORM protocol headers, which is giving efficiency energy ๐Ÿ“. In cases where security analysis deems encryption of NORM protocol header content to be beneficial or necessary, the aforementioned use of IPsec ESP might be more appropriate ๐Ÿ™ˆ. The EXT_AUTH header extension can also be used when NORM is implemented in a network with Network Address Translation (NAT) systems that are incompatible with use of the IPsec AH extension ๐ŸŒˆ.

If EXT_AUTH is present, whatever packet authentication or integrity checks can be performed immediately upon reception of the packet MUST be performed before accepting the packet and performing any congestion-control-related action on it ๐Ÿšฆ. Some packet authentication schemes impose a delay of several seconds between when a packet is received and when the packet can be fully authenticated ๐Ÿข. Any appropriate congestion control related action MUST NOT be postponed by any such packet security mechanism. In other words, security mechanisms MUST NOT result in poor congestion control behavior ๐Ÿ˜ค.

Security is not a side quest, bestie. Keep this part in your main storyline ๐Ÿ‘‘

Consideration MUST also be given to the potential for replay attacks that would transplant authenticated packets from one NORM session to another to disrupt service ๐Ÿ”. To avoid this, unique keys SHOULD be assigned on a per-session basis, or NORM sender nodes SHOULD be configured to use unique instance_id identifiers managed as part of the security association for the sessions ๐Ÿ—๏ธ.

Note that NORM implementations can use the sequence field from the NORM common message header to detect replay attacks ๐Ÿ•ต๏ธโ€โ™€๏ธ. This can be accomplished if the NORM sender maintains state on actively NACKing receivers. A cache of such receiver state can be used to provide protection against NACK replay attacks ๐Ÿ’œ. NORM receivers MUST also maintain similar state for protection against possible replay of other receiver messages in ASM operation as well ๐Ÿง . For example, a receiver could be suppressed from providing NACK or congestion control feedback by replay of certain receiver messages ๐Ÿ™€. For these reasons, authentication of NORM messages (e.g., via IPsec) SHOULD be applied to protect against similar attacks that use fabricated messages ๐Ÿ›ก๏ธ. Also, encryption of messages to provide confidentiality of application data and to protect the privacy of users MAY also be applied using IPsec or similar mechanisms ๐ŸŒท.

When applicable security measures are used, automated key management mechanisms such as those described in the Group Domain of Interpretation (GDOI) [RFC3547], Multimedia Internet KEYing (MIKEY) [RFC3830], or Group Secure Association Key Management Protocol (GSAKMP) [RFC4535] specifications SHOULD be applied ๐Ÿ—‚๏ธ.

While NORM does leverage FEC-based repair for scalability, this alone does not guarantee integrity of received data ๐Ÿ™ƒ. Application-level integrity-checking of received data content is highly RECOMMENDED ๐Ÿ’–. This recommendation also applies when the IPsec security approach described below is used for added assurance in data content integrity, given the shared use of IPsec Security Association information among the group ๐Ÿซง.

7.1. Baseline Secure NORM Operation ๐ŸŽ€

This section describes a baseline mode of secure NORM protocol operation based on application of the IPsec security protocol ๐Ÿง. This approach is documented here to provide a baseline interoperable secure mode of operation ๐Ÿค. This particular approach represents one possible trade-off between the level of assurance that can be achieved and the scalability of multicast group size, given current IPsec mechanisms and the state required to support them โš–๏ธ. For example, this baseline approach specifies the use of a Security Association that is shared among the receiver set for feedback messages to the sender ๐Ÿ‘ฏ. This model requires that the receiver membership receiving the session keys is trusted, and it only provides protection from attacks that are external to the NORM group membership ๐Ÿšช. More stateful and complex IPsec approaches and key management schemes may be applied for higher levels of assurance, but those are beyond the scope of this transport protocol specification ๐Ÿงฉ. Additional approaches to NORM security, including other forms of IPsec application, MAY be specified in the future ๐Ÿ”ฎ. For example, the use of the EXT_AUTH header extension could enable NORM-specific authentication or security encapsulation headers similar to those of IPsec to be specified and inserted into the NORM protocol message headers ๐Ÿช„. This would allow header compression techniques to be applied to IP and NORM protocol headers when needed, in a similar fashion to RTP [RFC3550] and as preserved in the specification for Secure Real Time Protocol (SRTP) [RFC3711] ๐ŸŒŸ.

The baseline approach described is applicable to NORM operation configured for SSM (or SSM-like) operation, where there is a single sender and the receivers are providing unicast feedback ๐Ÿ“ก. This form of NORM operation allows IPsec to be used with a manageable number of security associations (SA) ๐Ÿฅฐ.

7.1.1. IPsec Approach ๐Ÿ”

okay so bestie, for NORM one-to-many SSM with unicast feedback from receivers, every node SHALL be configured with two transport mode IPsec security associations and matching Security Policy Database (SPD) entries ๐ŸŽ€. One entry handles sender-to-group multicast packet authentication and, optionally, encryption. The other entry protects the unicast feedback from the receiver(s) back to the sender. Also note that this single SA for NORM receiver feedback is shared, so it protects traffic from possibly many receivers going to the one sender ๐Ÿ’….

For each NormSession, the NORM sender SHALL use an IPsec SA set up for ESP protocol [RFC4303] operation, with data origin authentication turned on ๐Ÿ”ฅ. It is also RECOMMENDED that this ESP SA provide confidentiality for the IP packets carrying NORM protocol messages. This is suggested because it makes complex replay attacks way harder to pull off ๐Ÿ™ˆ. The encryption key for this SA SHALL be preplaced at the sender and receiver(s) before NORM protocol operation starts. Automated key management is RECOMMENDED, because a rekey SHALL be REQUIRED before the sequence space for the SA runs out โœจ. That's what lets receivers use the built-in IPsec replay attack protection, which works for an IPsec SA with a single source (the NORM sender). So the receivers SHALL enable replay attack protection for this SA that secures NORM sender traffic ๐Ÿซถ. An IPsec SPD entry MUST be configured to process outbound packets going to the session (destination) address and UDP port number of the NormSession ๐Ÿฆ‹.

The NORM receiver(s) MUST be configured with the SA and SPD entry so they can properly process the IPsec-secured packets from the sender ๐Ÿ’œ. The receivers SHALL also use a common, second IPsec SA (same Security Parameter Index (SPI) and encryption key) set up for ESP operation, with data origination authentication turned on. Just like the sender, it is RECOMMENDED that this ESP SA also provide confidentiality for the IP packets carrying NORM protocol messages ๐ŸŒธ. The receivers MUST have an IPsec SPD entry that processes outbound NORM/UDP packets headed to the NORM sender's source address and port number using this second SA. To support NORM unicast feedback, the sender's transmission port number SHOULD be different from the multicast session port number ๐Ÿ“. That way you can tell unicast feedback apart from multicast feedback when you can't access the IP destination address (for example, a user-space NORM implementation). To process packets from receivers, the NORM sender SHALL be configured with this common, second SA (and the SPD entry it needs) so it can properly handle messages from receivers ๐Ÿงš.

Multiple receivers sharing a common IPsec SA for traffic going to the NORM sender (that's many-to-one) usually stops the NORM sender from using built-in IPsec replay attack protection with current IPsec implementations ๐Ÿ˜ญ. So the built-in replay protection for this second SA at the sender MUST be disabled, unless the particular IPsec implementation manages replay protection per source (which isn't typical of existing IPsec implementations). Therefore, to get a fully secure mode of operation, the NORM sender implementation MUST provide replay attack protection based on the "sequence" field of NORM protocol messages from receivers ๐Ÿ‘‘. This can be done with high assurance, even though that field is only 16 bits, and here's why ๐Ÿ’–:

  1. NORM receiver NACK and non-CLR ACK feedback messages are sparse โœจ.
  2. The more frequent NORM_ACK feedback from CLR or PLR nodes comes from only a small set of receivers, so the sender only needs to keep more persistent replay attack state for them ๐ŸŒˆ.
  3. NORM_NACK feedback messages that come before the sender's current repair window don't really affect protocol operation (generation of NORM_CMD(SQUELCH) is limited) and could actually be ignored ๐Ÿ’…. This means the sender can prune any replay attack state that comes before the current repair window.
  4. NORM_ACK messages match either a specific sender "ack_id", the sender "cc_sequence" for ACKs sent in response to NORM_CMD(CC), or the sender's current repair window for ACKs sent in response to NORM_CMD(FLUSH). So the sender can prune any replay attack state for receivers that comes before the current applicable sequence or repair window space ๐Ÿฆ‹.

Using ESP confidentiality for secure NORM operation makes replay attacks harder for adversaries, which is iconic ๐Ÿ™Œ. Also, a NORM sender implementation with access to the full ESP protocol header could use the ESP sequence information to make replay protection even stronger, by keeping per-source ESP sequence state (something existing IPsec implementations usually don't give you) ๐Ÿ’. The whole design of this baseline approach intentionally puts the more complex state and processing (like replay attack protection across multiple receivers) on the NORM sender, since NORM receiver implementations might often need to be less complex ๐ŸŽ€.

This baseline approach can also work for NORM protocol sessions with multiple senders, as long as the SA pairs described here are set up for each sender ๐Ÿ’œ. For small groups, it's even possible to have a many-to-many (ASM) IPsec configuration, where each participant uses a unique SA (with a unique SPI). In that case, the senders would keep an SA for each other participant rather than one shared SA for receiver feedback messages. This doesn't scale to larger groups, though, because each participant would have to maintain a complicated set of SA and SPD entries ๐Ÿ˜ตโ€๐Ÿ’ซ.

Early deployments of this baseline approach to NORM security are expected to handle key management out-of-band, separate from NORM protocol operation ๐Ÿ—๏ธ. For one-to-many NORM operation, receivers might fetch keying information from a central server as needed, or do group key updates with a similar centralized approach. Another option is that, with some key management schemes, rekey messages can be sent to the group as a message or transport object inside the NORM reliable transfer session ๐ŸŒธ. Similarly, for group-wise communication sessions, potential group participants can request keying and/or rekeying as part of NORM communications. An in-band key management scheme for NORM sessions would need more specification, possibly using the mechanisms of the automated group key management specifications cited in this document โœจ. Defining an interoperable approach to key management in-band of a NORM reliable transport session would take additional specification outside the scope of this document ๐Ÿซง.


7.1.2. IPsec Requirements ๐Ÿ“‹

to actually run this secure mode of NORM protocol operation, the following IPsec capabilities are REQUIRED ๐Ÿ’….

7.1.2.1. Selectors

the implementation MUST be able to use the source address, destination address, protocol (UDP), and UDP port numbers as selectors in the SPD ๐ŸŽฏ.

7.1.2.2. Mode

IPsec in transport mode MUST be supported ๐Ÿšš. The use of IPsec [RFC4301] processing for secure NORM traffic MUST be configured so that unauthenticated packets are not received by the NORM protocol implementation ๐Ÿ›ก๏ธ.

7.1.2.3. Key Management

an automated key management scheme for group key distribution and rekeying, such as GDOI [RFC3547], GSAKMP [RFC4535], or MIKEY [RFC3830], is RECOMMENDED ๐Ÿ”‘. Note that key update messages (like the GDOI GROUPKEY-PUSH message) can be included as part of the NORM application reliable data transmission, as long as there are suitable interfaces between the NORM application and the key management daemon ๐Ÿงšโ€โ™€๏ธ. Relatively short-lived NORM sessions MAY be able to use Manual Keying with a single, preplaced key, especially if Extended Sequence Numbering (ESN) [RFC4303] is available in the IPsec implementation being used โณ. When manual keys are used, it's important to select cryptographic algorithms that are suitable for manual key use ๐Ÿ™ˆ.

7.1.2.4. Security Policy

Receivers MUST accept protocol messages only from the designated, authorized sender(s) ๐Ÿšซ. Appropriate key management will provide authentication, integrity and/or encryption keys only to receivers authorized to take part in a designated session ๐ŸŽ€. The approach outlined here lets receiver sets be controlled on a per-sender basis ๐Ÿ‘‘.

7.1.2.5. Authentication and Encryption

large NORM group sizes will need some form of key management that doesn't rely on shared secrets ๐ŸŒˆ. The GDOI and GSAKMP protocols mentioned here allow certificate-based authentication. It is RECOMMENDED that these certificates use IP addresses for authentication ๐Ÿซถ.

7.1.2.6. Availability

the IPsec requirements profile outlined here is commonly available on many potential NORM hosts ๐Ÿ’œ. Configuring and operating IPsec typically requires privileged user authorization, and automated key management implementations are typically configured with the privileges needed to change system IPsec configuration ๐Ÿ”.


8. IANA Considerations ๐ŸŽ€

values of NORM Header Extension Types, Stream Control Codes, and NORM_CMD message sub-types are subject to IANA registration ๐Ÿ“š. They are in the registry named "Reliable Multicast Transport (RMT) NORM Protocol Parameters", available from http://www.iana.org.

Keep in mind that the reliable multicast building block components used by this specification have their own IANA considerations too, and those documents SHOULD be consulted accordingly ๐Ÿ”. In particular, the FEC Building Block used by NORM does REQUIRE IANA registration of the FEC codecs it uses. The registration instructions for FEC codecs are in RFC 5052 ๐Ÿง. It's possible that additional extensions of the NORM protocol might be specified in the future (for example, additional NORM message types), and that additional registries might be set up at that time through appropriate IETF standards action ๐ŸŒŸ.

8.1. Explicit IANA Assignment Guidelines

this document introduces three registries for the NORM Header Extension Types, Stream Control Codes, and NORM_CMD Message sub-types ๐Ÿ—‚๏ธ. This section describes explicit IANA assignment guidelines for each of these โœจ.

8.1.1. NORM Header Extension Types ๐ŸŽ€

This document makes a registry for NORM Header Extensions called "NORM Header Extension Types" ๐Ÿ—‚๏ธโœจ

The NORM Header Extension Type field is an 8-bit value ๐Ÿ”ข These values tell you what extra header stuff is in the packet, so the protocol can grow new features and operating modes ๐ŸŒฑ The numbers you can assign in the "NORM Header Extensions" registry are {0, 255}, boundaries included. Values in {0,127} mean variable-length extended header fields ๐Ÿ“ and values in {128,255} mean extensions with a fixed 4-byte length ๐Ÿงฑ This specification registers these NORM Header Extension Types:

              +-------+----------+--------------------+
              | Value | Name     | Reference          |
              +-------+----------+--------------------+
              | 1     | EXT_AUTH | This specification |
              | 3     | EXT_CC   | This specification |
              | 64    | EXT_FTI  | This specification |
              | 128   | EXT_RATE | This specification |
              +-------+----------+--------------------+

New values are granted on a "Specification Required" basis, as defined by IANA Guidelines [RFC5226] ๐Ÿ“‹๐Ÿ’– Any new header extension spec MUST include a description of what the protocol should do when the extension type shows up at an implementation that doesn't support that option ๐Ÿง It's often possible for implementations to just ignore unknown header extensions, fr ๐Ÿ™ˆ

8.1.2. NORM Stream Control Codes ๐Ÿ›ฐ๏ธ

This document makes a registry for NORM Stream Control Codes called "NORM Stream Control Codes" ๐Ÿ—‚๏ธ

NORM Stream Control Codes are 16-bit values ๐Ÿ’ซ You can put them inside a NORM_OBJECT_STREAM delivery object to send sequenced control signals that are out-of-band (with respect to the stream data) and apply to the stream object they point to ๐ŸŽฏ These control codes get delivered to the application or protocol implementation with reliable delivery, in order with respect to where they were inserted in the stream ๐Ÿ“ This specification registers this NORM Stream Control Code:

          +-------+-----------------+--------------------+
          | Value | Name            | Reference          |
          +-------+-----------------+--------------------+
          | 0     | NORM_STREAM_END | This specification |
          +-------+-----------------+--------------------+

New NORM Stream Control Code values are granted on a "Specification Required" basis, as defined by IANA Guidelines [RFC5226] ๐Ÿ“‹ The full 16-bit space outside the value assigned in this specification is free for future assignment ๐ŸŒˆ Besides describing how the control code should be understood, those specs MUST include a description of what the protocol should do when the control code shows up at an implementation that doesn't support that specific option ๐Ÿซถ

8.1.3. NORM_CMD Message Sub-Types ๐Ÿ“จ

This document makes a registry for NORM_CMD message sub-types called "NORM Command Message Sub-types" ๐Ÿ—‚๏ธ

The NORM_CMD message "sub-type" field is an 8-bit value with valid values in the range 1-255 ๐Ÿ”ข Heads up, the value 0 is reserved to mean an invalid NORM_CMD message sub-type ๐Ÿ™…โ€โ™€๏ธ The current spec defines a bunch of NORM_CMD message sub-types senders can use to tell receivers about different parts of NORM protocol operation ๐Ÿ’… This specification registers these NORM_CMD Message Sub-types:

       +-------+-----------------------+--------------------+
       | Value | Name                  | Reference          |
       +-------+-----------------------+--------------------+
       | 0     | reserved              | This specification |
       | 1     | NORM_CMD(FLUSH)       | This specification |
       | 2     | NORM_CMD(EOT)         | This specification |
       | 3     | NORM_CMD(SQUELCH)     | This specification |
       | 4     | NORM_CMD(CC)          | This specification |
       | 5     | NORM_CMD(REPAIR_ADV)  | This specification |
       | 6     | NORM_CMD(ACK_REQ)     | This specification |
       | 7     | NORM_CMD(APPLICATION) | This specification |
       +-------+-----------------------+--------------------+

Future specs extending NORM MAY define additional NORM_CMD messages to boost protocol functionality โœจ New NORM_CMD message sub-type value requests are granted on a "Specification Required" basis, as defined by IANA Guidelines [RFC5226] ๐Ÿ“‹ Besides describing how the command sub-type should be interpreted, specs MUST include a description of what the protocol should do when the command shows up at an implementation that doesn't support that specific option ๐Ÿง 

There's already an "application-defined" NORM_CMD message sub-type ๐ŸŽ‰ Individual applications using NORM for transport can use it however they like ๐Ÿ’œ These "application-defined" commands are great for lots of app-specific stuff and don't need any standards action ๐Ÿ™Œ Still, those extra messages SHALL be subject to the same congestion control constraints as the existing NORM sender message set ๐Ÿšฆ


9. Suggested Use ๐ŸŒธ

NORM is seen as a super useful tool for reliable data transfer over generic IP multicast services ๐Ÿ“ก The authors aren't saying it's suitable for every multicast reliability need out there, so don't come for them ๐Ÿ™ˆ NORM gives you a simple and flexible framework for multicast apps, and it's got some concern for network traffic implosion and protocol overhead efficiency ๐Ÿ’– NORM-like protocols were successfully demoed on the MBone for bulk data dissemination ๐Ÿ›ฐ๏ธ Think weather satellite compressed imagery updates going out to a huge group of receivers, plus a generic web content reliable "push" app ๐ŸŒค๏ธ

This framework also has design features that make it attractive for bulk transfer in asymmetric and wireless internetwork applications ๐Ÿฆ‹ NORM works fine no matter the network structure, even in environments with high packet loss, delay, and out-of-order delivery ๐ŸŒˆ Hybrid proactive/reactive FEC-based repairing boosts performance in some multicast scenarios ๐Ÿ“ˆ Sender-only repair often makes more engineering sense in asymmetric networks ๐Ÿงฉ NORM's unicast feedback capability is great for asymmetric networks, or networks where only unidirectional multicast routing/delivery exists ๐Ÿซถ Asymmetric architectures that support multicast delivery will probably be a big part of the future Internet (think direct broadcast satellite (DBS) or cable and public-switched telephone network (PSTN) hybrids, etc.) ๐Ÿ›ฐ๏ธ Efficient, reliable bulk data transfer will be a major capability for serving large groups of subscribed receivers ๐Ÿ‘‘


10. Changes from RFC 3940 ๐Ÿ”

This section lists the changes between the Experimental version of this specification, RFC 3940, and this version ๐Ÿ“

  1. Removed NORM_FLAG_MSG_START for NORM_OBJECT_STREAM, and replaced it with the payload_msg_start field in the FEC-encoded preamble of the NORM_OBJECT_STREAM NORM_DATA payload ๐Ÿง
  2. Defined an IANA registry for header extension and other assignments ๐Ÿ—‚๏ธ
  3. Removed the file blocking scheme description, which is now specified in the FEC Building Block document [RFC5052] ๐Ÿ“ฆ
  4. Removed the restriction of NORM receiver feedback message rate to local NORM sender rate. This caused congestion control failures in high speed operation. The extremely low feedback rate of the NORM protocol compared to TCP avoids any resultant impact to the network, as shown in [Mdpcc] ๐Ÿš€๐Ÿ’…
  5. Corrected errors in some message format descriptions ๐Ÿ› ๏ธ
  6. Corrected an inconsistency in the specification of the inactivity timeout โฐ
  7. Added an IPsec secure mode description with IPsec requirements ๐Ÿ”
  8. Added the EXT_AUTH header extension definition ๐Ÿชช
  9. Clarified the interpretation of "Source Block Length" when FEC codes are arbitrarily shortened by the sender ๐Ÿงฎ

11. Acknowledgments ๐Ÿซถ

(and these are not Negative)

The authors would like to thank Rick Jones, Vincent Roca, Rod Walsh, Toni Paila, Michael Luby, and Joerg Widmer for their valuable input and comments on this document ๐Ÿ’– They'd also like to thank the RMT working group chairs, Roger Kermode and Lorenzo Vicisano, for their support in developing this specification ๐Ÿ‘‘ And a big hug to Sally Floyd for her early input into this document ๐Ÿฆ‹


12. References ๐Ÿ“š

12.1. Normative References ๐Ÿ’œ

[RFC1112]        Deering, S., "Host extensions for IP multicasting",
                 STD 5, RFC 1112, August 1989.

[RFC2119]        Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC4301]        Kent, S. and K. Seo, "Security Architecture for the
                 Internet Protocol", RFC 4301, December 2005.

[RFC4303]        Kent, S., "IP Encapsulating Security Payload (ESP)",
                 RFC 4303, December 2005.

[RFC4607]        Holbrook, H. and B. Cain, "Source-Specific Multicast
                 for IP", RFC 4607, August 2006.

[RFC4654]        Widmer, J. and M. Handley, "TCP-Friendly Multicast
                 Congestion Control (TFMCC): Protocol Specification",
                 RFC 4654, August 2006.

[RFC5052]        Watson, M., Luby, M., and L. Vicisano, "Forward
                 Error Correction (FEC) Building Block", RFC 5052,
                 August 2007.

[RFC5226]        Narten, T. and H. Alvestrand, "Guidelines for
                 Writing an IANA Considerations Section in RFCs",
                 BCP 26, RFC 5226, May 2008.

[RFC5401]        Adamson, B., Bormann, C., Handley, M., and J.
                 Macker, "Multicast Negative-Acknowledgment (NACK)
                 Building Blocks", RFC 5401, November 2008.

12.2. Informative References ๐Ÿ“š

okay bestie, these are the extra reading picks. They're not required to implement the spec, but they're the papers and RFCs the authors leaned on, so they're lowkey essential if you want the deep dive ๐Ÿง โœจ

[FecHybrid]      Gossink, D. and J. Macker, "Reliable Multicast and
                 Integrated Parity Retransmission with Channel
                 Estimation", IEEE GLOBECOMM, 1998.

[McastFeedback]  Nonnenmacher, J. and E. Biersack, "Optimal Multicast
                 Feedback", IEEE INFOCOM, p. 964, March/April 1998.

[MdpToolkit]     Macker,  J. and B. Adamson, "The Multicast
                 Dissemination Protocol (MDP) Toolkit", Proc.
                 IEEE MILCOM, October 1999.

[Mdpcc]          Adamson,  B. and J. Macker, "A TCP-Friendly, Rate-
                 based Mechanism for NACK-Oriented Reliable Multicast
                 Congestion Control", Proc. IEEE GLOBECOMM,
                 November 2001.

[NormFeedback]   Adamson, B. and J. Macker, "Quantitative Prediction
                 of NACK-Oriented Reliable Multicast (NORM)
                 Feedback", IEEE MILCOM, October 2002.

[PgmccPaper]     Rizzo, L., "pgmcc: A TCP-Friendly Single-Rate
                 Multicast Congestion Control Scheme", ACM SIGCOMM,
                 August 2000.

[RFC2357]        Mankin, A., Romanov, A., Bradner, S., and V. Paxson,
                 "IETF Criteria for Evaluating Reliable Multicast
                 Transport and Application Protocols", RFC 2357,
                 June 1998.

[RFC2974]        Handley, M., Perkins, C., and E. Whelan, "Session
                 Announcement Protocol", RFC 2974, October 2000.

[RFC3048]        Whetten, B., Vicisano, L., Kermode, R., Handley, M.,
                 Floyd, S., and M. Luby, "Reliable Multicast
                 Transport Building Blocks for One-to-Many Bulk-Data
                 Transfer", RFC 3048, January 2001.

[RFC3269]        Kermode, R. and L. Vicisano, "Author Guidelines for
                 Reliable Multicast Transport (RMT) Building Blocks
                 and Protocol Instantiation documents", RFC 3269,
                 April 2002.

[RFC3453]        Luby, M., Vicisano, L., Gemmell, J., Rizzo, L.,
                 Handley, M., and J. Crowcroft, "The Use of Forward
                 Error Correction (FEC) in Reliable Multicast",
                 RFC 3453, December 2002.

[RFC3547]        Baugher, M., Weis, B., Hardjono, T., and H. Harney,
                 "The Group Domain of Interpretation", RFC 3547,
                 July 2003.

[RFC3550]        Schulzrinne, H., Casner, S., Frederick, R., and V.
                 Jacobson, "RTP: A Transport Protocol for Real-Time
                 Applications", STD 64, RFC 3550, July 2003.

[RFC3711]        Baugher, M., McGrew, D., Naslund, M., Carrara, E.,
                 and K. Norrman, "The Secure Real-time Transport
                 Protocol (SRTP)", RFC 3711, March 2004.

[RFC3830]        Arkko, J., Carrara, E., Lindholm, F., Naslund, M.,
                 and K. Norrman, "MIKEY: Multimedia Internet KEYing",
                 RFC 3830, August 2004.

[RFC3940]        Adamson, B., Bormann, C., Handley, M., and J.
                 Macker, "Negative-acknowledgment (NACK)-Oriented
                 Reliable Multicast (NORM) Protocol", RFC 3940,
                 November 2004.

[RFC4535]        Harney, H., Meth, U., Colegrove, A., and G. Gross,
                 "GSAKMP: Group Secure Association Key Management
                 Protocol", RFC 4535, June 2006.

[RFC4566]        Handley, M., Jacobson, V., and C. Perkins, "SDP:
                 Session Description Protocol", RFC 4566, July 2006.

[RFC5445]        Watson, M., "Basic Forward Error Correction (FEC)
                 Schemes", RFC 5445, March 2009.

[RmComparison]   Pingali, S., Towsley, D., and J. Kurose, "A
                 Comparison of Sender-Initiated and Receiver-
                 Initiated Reliable Multicast Protocols", Proc.
                 INFOCOMM, San Francisco CA, October 1993.

[TcpModel]       Padhye,  J., Firoiu, V., Towsley, D., and J. Kurose,
                 "Modeling TCP Throughput: A Simple Model and its
                 Empirical Validation", ACM SIGCOMM, 1998.

[TfmccPaper]     Widmer, J. and M. Handley, "Extending Equation-Based
                 Congestion Control to Multicast Applications",
                 ACM SIGCOMM, August 2001.

Authors' Addresses ๐Ÿ’Œ

the squad behind this one, with their contact info ๐Ÿซถ

Brian Adamson
Naval Research Laboratory
Washington, DC  20375
USA

EMail: adamson@itd.nrl.navy.mil


Carsten Bormann
Universitaet Bremen TZI
Postfach 330440
D-28334 Bremen
Germany

EMail: cabo@tzi.org


Mark Handley
University College London
Gower Street
London  WC1E 6BT
UK

EMail: M.Handley@cs.ucl.ac.uk


Joe Macker
Naval Research Laboratory
Washington, DC  20375
USA

EMail: macker@itd.nrl.navy.mil
๐Ÿ“ฆ where this page comes from