RFC 2687

PPP in a Real-time Oriented HDLC-like Framing

๐Ÿ“… published September 1999, from ietf

RFC 2687: PPP in a Real-time Oriented HDLC-like Framing ๐ŸŽ€

Okay bestie, here's the title block first so you know the basics ๐Ÿ’–

  • Working group: Network Working Group
  • RFC number: 2687
  • Title: PPP in a Real-time Oriented HDLC-like Framing
  • Author: C. Bormann, Universitaet Bremen TZI
  • Category: Standards Track
  • Date: September 1999
  • Obsoletes / updates: the header doesn't list anything it obsoletes or updates ๐Ÿซถ

Status of this Memo โœจ

Okay so this doc is a Standards Track protocol spec for the Internet community, and it's basically asking everyone to discuss it and send in suggestions ๐Ÿ’… For the official standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). And distribution of this memo is unlimited, so share it with everyone ๐ŸŒธ

Copyright (C) The Internet Society (1999). All Rights Reserved.

Abstract ๐Ÿงš

So there's a companion doc that describes an architecture for giving integrated services over low-bitrate links, like modem lines, ISDN B-channels, and sub-T1 links [1]. The main pieces of that architecture are a real-time encapsulation format for asynchronous and synchronous low-bitrate links, a header compression architecture that's optimized for real-time flows, elements of negotiation protocols used between routers (or between hosts and routers), and announcement protocols that applications use so this negotiation can happen ๐Ÿ’œ

This document proposes the suspend/resume-oriented solution for the real-time encapsulation format part of that architecture. The general vibe is to start from the PPP Multilink fragmentation protocol [2] and its multi-class extension [5], then add suspend/resume in a way that's as compatible with existing hard- and firmware as possible โœจ

1. Introduction ๐Ÿฆ‹

Okay so the Internet is famous for its "best-effort" services, right? But now there are additional types of services ("integrated services") that support real-time multimedia, and they're actually being developed and deployed on the Internet ๐ŸŒˆ

This document defines the suspend/resume-oriented solution for the real-time encapsulation format part of the architecture. The architecture document goes into more detail, but the short version is that a real-time encapsulation format is needed because, for example, a 1500 byte packet on a 28.8 kbit/s modem link makes that link unavailable for real-time traffic for about 400 ms ๐Ÿ˜ญ That adds a worst-case delay, which means real-time apps end up with round-trip delays of at least a second, and that's honestly unacceptable for real-time conversation ๐Ÿ’€

A true suspend/resume-oriented approach can only be implemented on a type-1 sender [1], but it gives those senders the best possible delay performance ๐Ÿ† The format in this document might also be interesting for certain type-2 senders who want to use the better bit-efficiency of this format compared to [5]. And the format was designed so that both type-1 and type-2 receivers can implement it ๐Ÿซถ

1.1. Specification 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 [8] ๐Ÿ“–

2. Requirements ๐ŸŽ€

The requirements for this doc are pretty similar to the ones in [5] ๐Ÿ’–

Okay so a suspend/resume-oriented solution can give you better worst-case latency than the pre-fragmenting-oriented solution defined in [5] โœจ And since this solution needs a new encapsulation scheme anyway, there's a chance to make the format a little more efficient ๐ŸŒธ

Predictability, robustness, and cooperation with PPP and existing hard- and firmware installations matter just as much with suspend/resume as they do with pre-fragmenting ๐Ÿ”ฅ A good suspend/resume solution gets good performance even with type-2 receivers [1], and it has to work with PPP hardware like async-to-sync converters ๐Ÿงš

Finally, a partial non-requirement: the format in this draft is based on the PPP multilink protocol ([2], also abbreviated as MP), but operating over multiple links is in many cases not required ๐Ÿฆ‹

3. General Approach ๐Ÿ’œ

Same as in [5], the general approach starts from PPP multilink and adds multiple classes to get multiple levels of suspension โœจ The difference is that, unlike [5], it needs more significant changes so that a packet's transmission can be suspended at any point and a higher priority packet can be injected ๐Ÿ”ฅ

Here's the catch: the multilink header isn't a great fit for suspend/resume implementations, because the "end" bit lives in the multilink header, which is the wrong place for suspend/resume operation ๐Ÿ™ˆ To make a big packet suspendable, it has to be sent with the "end" bit off. Unless the packet was suspended a small number of bytes before its end, an empty fragment then has to be sent afterwards to "close" the packet ๐Ÿ˜ญ So the minimum overhead for sending a suspendable packet is twice the multilink header size (six bytes, including a compressed multilink protocol field) plus one PPP framing (three bytes). Each suspension costs another six bytes (not counting the framing overhead of the intervening packet) ๐Ÿ’€

The existing multi-link header is also pretty large, and as small high-priority packets become more frequent, that overhead becomes a big deal ๐Ÿ‘‘

So the general approach of this document is to start from PPP Multilink with classes, then add a bunch of extensions to add functionality and cut down the overhead of using PPP Multilink for real-time transmission ๐Ÿงš

This document introduces two new features:

  1. A compact fragment format and header, and
  2. a real-time frame format.

4. The Compact Fragment Format ๐Ÿฆ‹

This section describes an optional multilink fragment format. It's more optimized for single-link operation and frequent suspension (type 1 senders)/a small fragment size (type 2 senders), with optional support for multiple links ๐Ÿ’…

When you're operating over a single link, the Multilink sequence number is only used for loss detection. Honestly, even a 12-bit sequence number is way bigger than this application needs on most kinds of links ๐Ÿ™„ So we define a compact multilink header format option with a three-bit sequence number โœจ

With a compact header there's little need to send packets outside the multilink, so we can add another compression mechanism for this format: the MP protocol identifier isn't sent with the compact fragment header ๐ŸŒˆ This obviously requires prior negotiation (kind of like how address and control field compression get negotiated). It also needs a way to avoid the bit combination 0xFF (the first octet in an LCP frame before any LCP options have been negotiated), because otherwise the start of a new LCP negotiation couldn't be reliably detected ๐Ÿ˜ญ

                  Figure 1:  Compact Fragment Format

                    0   1   2   3   4   5   6   7
                  +---+---+---+---+---+---+---+---+
                  | R |  sequence |   class   | 1 |
                  +---+---+---+---+---+---+---+---+
                  |            data               |
                  :                               :
                  +---+---+---+---+---+---+---+---+

Having the least significant bit always be 1 helps HDLC chips that do special things with the least significant bits in HDLC addresses ๐Ÿค“ (Initial bytes with the least significant bit set to zero are used for the extended compact fragment format, see next section.)

The R bit is the inverted version of the B bit in the other multilink fragment formats. So R = 1 means this fragment resumes a packet whose previous fragments have already been sent ๐Ÿ”„

Now here's a clever trick to avoid a header byte of 0xFF, which would mean R=1, sequence=7, and class=7 ๐Ÿ’€ If the class field is set to 7, the R bit MUST never be set to one. So class 7 frames by design can't be suspended/resumed ๐Ÿ™…โ€โ™€๏ธ (This is also why the sense of the B bit got flipped to an R bit in the compact fragment format. Without that, class 7 would be useless, because a new packet could never begin.)

Since the sequence number isn't particularly useful when the class field is set to 7, it gets used to distinguish eight more classes. It adds a little complexity, but prefix elision becomes way more applicable because there are more classes that can have different elided prefixes ๐ŸŽ€

For purposes of prefix elision, the actual class number of a fragment is computed like this:

  • If the class field is 0 to 6, the class number is 0 to 6,
  • if the class field is 7 and the sequence field is 0 to 7, the class number is 7 to 14.

So the result is that classes 0 to 6 can be used for suspendable packets, and classes 7 to 14 (where the class field is 7 and the R bit must always be off) can be used for non-suspendable high-priority classes, like eight highly compressed voice streams ๐ŸŽค๐Ÿ’–

5. The Extended Compact Fragment Format ๐ŸŒธ

For operation over multiple links, a three-bit sequence number is rarely going to be enough ๐Ÿ˜ฉ So we define an optional extended compact fragment format. When it's negotiated, it lets both the basic compact fragment format and the extended compact fragment format be used, and each fragment says which format it's in ๐Ÿงš

               Figure 1:  Extended Compact Fragment Format

                     0   1   2   3   4   5   6   7
                   +---+---+---+---+---+---+---+---+
                   | R |  seq LSB  |   class   | 0 |
                   +---+---+---+---+---+---+---+---+
                   |      sequence -- MSB      | 1 |
                   +---+---+---+---+---+---+---+---+
                   |            data               |
                   :                               :
                   +---+---+---+---+---+---+---+---+

In the extended compact fragment format, the sequence number is made up of three least significant bits from the first octet of the fragment header and seven most significant bits from the second octet ๐Ÿงฎ (Again, the least significant bit of the second octet is always set to one for compatibility with certain HDLC chips.)

For prefix elision purposes, fragments with a class field of 7 can use the basic format to indicate classes 7 to 14, and the extended format to indicate classes 7 to 1030 โœจ Different classes can use different formats at the same time without problems. (This lets some classes be spread over a multi-link while other classes stay confined to a single link, which is more efficient.) For class fields 0 to 6, which are the suspendable classes, one of the two compact fragment formats SHOULD be used consistently within each class ๐Ÿ’…

If the extended compact fragment format has been negotiated, receivers MAY keep 10-bit sequence numbers for all classes, so senders can switch formats within a class more easily ๐Ÿ”„ When a sender starts sending basic format fragments in a class that was using extended format fragments, the 3-bit sequence number can be taken as a modulo-8 version of the 10-bit sequence number, so there's no discontinuity ๐Ÿ™Œ In the other direction, if the receiver has kept a 10-bit sequence number throughout (and no major slips of the sequence number have happened), no discontinuity will result. But this can't be guaranteed in the presence of errors โš ๏ธ (Discontinuity, in this context, means a receiver has to resynchronize sequence numbers by discarding fragments until a fragment with R=0 has been seen.)

6. Real-Time Frame Format โœจ

okay so this section is where compact fragment headers get mapped into real-time frames ๐ŸŽ€ the big vibe is that the HDLC-based frame shape stays the same, so existing synchronous HDLC chips and async-to-sync converters can still be used on the link ๐Ÿ”Œ ngl that's giving backwards compatibility realness. there's a note that if the design were only optimized for async operation, more design options would open up [4]. with V.80 style modems around, async is lowkey going to matter less though ๐Ÿฅน

the compact fragment format is a compact version of the PPP multilink header with classes and a smaller sequence number space ๐Ÿ’– BUT it doesn't encode the E-bit from the PPP multilink header, which tells you whether a fragment is the last one of a packet. bestie that's the gap this section fills ๐Ÿซถ

for a solution where packets can be suspended at any point, the E-bit has to be encoded near the end of each fragment ๐Ÿฆ‹ the real-time frame format keeps maximum compatibility with type 2 receivers, so it encodes E like this: any normal frame ending also ends the current fragment, and E is implicitly set to one. the iconic part is that packets ready for delivery to upper layers immediately trigger a receive interrupt, even at type-2 receivers ๐Ÿ”ฅ no waiting around, periodt.

fragments of packets that are being suspended get terminated inside the HDLC frame by a special "fragment suspend escape" byte (FSE) ๐ŸŒธ the overall HDLC frame structure doesn't change. FSE detection and handling happens in a layer above HDLC framing โœจ

the suspend/resume format with FSE detection is an alternative to address/control field compression (ACFC, LCP option 8) ๐Ÿ’… it does not apply to frames that start with 0xFF, which is the standard PPP-in-HDLC address field. those frames get handled as defined in [6] and [7]. (this is there so attempts to renegotiate LCP don't cause ambiguities ๐Ÿ™ˆ)

for frames that don't start with 0xFF, suspend/resume processing scans every HDLC frame received. the FCS of the HDLC frame is checked and then stripped ๐Ÿงš compact fragment format headers (basic and extended) get handled without any further FSE processing. (and because the FSE byte was picked so it never shows up in compact fragment format headers, you don't need any special code for this ๐Ÿ“)

within the remaining bytes of the HDLC frame (the "data part"), an FSE byte marks the end of the current fragment, with E implicitly cleared ๐Ÿ‘‘ all fragments up to the last FSE count as suspended (E = 0). the final fragment is terminated (E = 1), or, if it's empty, it's just ignored. so the data part of an HDLC frame can end in an FSE to say the last fragment has E = 0 ๐Ÿ’œ

each fragment starts with a normal header, so a frame could look like this ๐ŸŒˆ

Figure 2: Example frame with FSE delimiter

  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| R |  sequence |   class   | 1 |
+---+---+---+---+---+---+---+---+
|            data               |
:                               :
+---+---+---+---+---+---+---+---+
+              FSE              + previous fragment implicitly E = 0
+---+---+---+---+---+---+---+---+
| R |  sequence |   class   | 1 |
+---+---+---+---+---+---+---+---+
|            data               |
:                               :
+---+---+---+---+---+---+---+---+
|             Frame             | previous fragment implicitly E = 1
|              CRC              |
+---+---+---+---+---+---+---+---+

the value chosen for FSE is 0xDE ๐Ÿฆ‹ it's a relatively unlikely byte in today's data streams, it doesn't trigger octet stuffing, and it only triggers bit stuffing for 1/8 of the possible preceding bytes. very strategic, very intentional ๐Ÿ’…

the remaining problem is data transparency ๐Ÿ˜ญ in the scheme so far, an FSE is always followed by a compact fragment header. in those headers, a class field set to 7 with R=1 is reserved. data transparency comes from making an FSE byte followed by one of 0x8F, 0x9F, ... to 0xFF special ๐ŸŽ€

Figure 3: Data transparency with FSE bytes present

       0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | R |  sequence |   class   | 1 |
      +---+---+---+---+---+---+---+---+
      |            data               |
      :                               :
      +---+---+---+---+---+---+---+---+
      +              FSE              + fragment NOT terminated
      +---+---+---+---+---+---+---+---+
      | R | S | T | U | 1 | 1 | 1 | 1 | R always is 1
      +---+---+---+---+---+---+---+---+
      |            data               | fragment continues
      :                               :

in an FSE/0xnF combo (where n is the first four-bit field in the second byte, RSTU in Figure 3), the n field is a sequence of four bits that says where FSE bytes get added by the receiver ๐Ÿง  these are FSE bytes that couldn't just be sent in the data stream. the combos are:

0x8F: insert one FSE, back to data
0x9F: insert one FSE, copy two data bytes, insert one FSE, back to data
0xAF: insert one FSE, copy one data byte, insert one FSE, back to data
0xBF: insert one FSE, copy one data byte, insert two FSE bytes, back
      to data
0xCF: insert two FSE bytes, back to data
0xDF: insert two FSE bytes, copy one data byte, insert one FSE, back
      to data
0xEF: insert three FSE bytes, back to data
0xFF: insert four FSE bytes, back to data

the data bytes that follow an FSE/0xnF combo, corresponding to the zero bits in the N field, may not be FSE bytes โœจ

this scheme caps the worst-case expansion from FSE processing at about 25 % ๐ŸŒธ it's also designed so that one data stream can trigger either worst-case expansion from octet stuffing (or bit stuffing) or worst-case FSE processing, but never both. genius, honestly ๐Ÿ‘‘ Figure 4 shows the scheme in a few examples, with FSE/0xnF pairs written in lower case ๐Ÿ’–

Figure 4: Data transparency examples

        Data stream                     FSE-stuffed stream

        DD DE DF E0                     DD de 8f DF E0
        01 DE 02 DE 03                  01 de af 02 03
        DE DA DE DE DB                  de bf DA DB
        DE DE DE DE DE DA               de ff de 8f DA

to sum up: the real-time frame format is an HDLC-like frame, delimited by flags, with a final FCS as defined in [7], but without address and control fields. its data is a sequence of FSE-stuffed fragments in compact fragment format, delimited by FSE bytes ๐Ÿฆ‹ as a special case, the final FSE can be the last byte of the data content (right before the FCS bytes). that tells you the last fragment in the frame is suspended and no final fragment is in the frame, for example because the desired maximum frame size was reached ๐Ÿซถ


7. Implementation notes โœจ

7.1. MRU Issues

okay this one is about the MRU ๐ŸŽ€ the LCP parameter MRU defines the maximum size of packets sent on the link. async-to-sync converters that monitor the LCP negotiations on the link may read the MRU value as the maximum HDLC frame size they should expect ๐Ÿงš

implementations of this specification should preferably negotiate an MRU big enough to cover the worst-case 25 % increase in frame size, plus the increase caused by suspended fragments ๐Ÿ’… if that isn't possible, the HDLC frame size should be limited by monitoring the HDLC frame sizes and possibly suspending the current fragment. you do that by sending an FSE with an empty final fragment (an FSE right before the end of the information field, so right before the CRC bytes and a flag). then you can continue in a new HDLC frame ๐ŸŒˆ this strategy also helps reduce the impact of a longer HDLC frame on the safety of the 16-bit FCS at the end of the frame ๐Ÿ˜ญ

7.2. Implementing octet-stuffing and FSE processing in one automaton

the simplest way to add real-time framing to an implementation is to do HDLC processing as usual, then run FSE processing on the result ๐ŸŒธ a more advanced implementation might want to combine the two levels of escape character processing. but note that FSE processing has to wait until two bytes from the HDLC frame are available and a third one follows, so you can be sure those bytes aren't the final HDLC FCS bytes (those aren't subject to FSE processing) ๐Ÿ™ˆ so, when a normal data byte arrives, look for an FSE in the second-to-previous byte. when a frame-end arrives, look for an FSE as the last data byte ๐Ÿ”ฅ

8. Negotiable options ๐Ÿ’œ

the following options are already defined by MP [2]:

  • Multilink Maximum Received Reconstructed Unit
  • Multilink Short Sequence Number Header Format
  • Endpoint Discriminator

the following options are already defined by MCML [5]:

  • Multilink Header Format
  • Prefix Elision

this document defines two new code points for the Multilink Header Format option ๐Ÿ‘‘

the multilink header format option is defined in [5] ๐Ÿฆ‹ a summary of its format is shown below. the fields are transmitted from left to right.

Figure 5: Multilink header format option

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type = 27   |  Length = 4   |     Code      | # Susp Clses  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

as defined in [5], this LCP option tells the peer that the implementation wants to receive fragments in the format given by the code number, with the maximum number of suspendable classes (see below) included ๐ŸŽ€ this specification adds two more values for Code, on top of the ones in [5]:

  • Code = 11: basic and extended compact real-time fragment format with classes, in FSE-encoded HDLC frame
  • Code = 15: basic compact real-time fragment format with classes, in FSE-encoded HDLC frame

an implementation MUST NOT request a combination of both LCP Address-and-Control-Field-Compression (ACFC) and the code values 11 or 15 for this option ๐Ÿšซ bestie, that one's non-negotiable.

the number of suspendable classes negotiated for the compact real-time fragment format only limits which class numbers are allowed to suspend ๐Ÿงš class numbers 7 and higher don't need extra reassembly space, so they aren't subject to the negotiated class number limit โœจ

9. Security Considerations ๐Ÿ”ฅ

operation of this protocol is believed to be no more and no less secure than operation of the PPP multilink protocol [2] ๐Ÿ™ˆ but a small sequence number range makes it more likely that fragments from different packets get incorrectly reassembled into one packet. most of those packets will be thrown out by the receiver because of higher-layer checksum failures or other inconsistencies ๐Ÿ˜ญ still, there's a higher chance that the contents of packets meant for one host could be delivered to another host. this is the serious part, babe: links that carry packets where this raises security considerations SHOULD use the extended sequence number range for multi-fragment packets ๐Ÿซถ

10. References โœจ

Okay bestie, here's the reading list ๐Ÿ“š Every source is listed with all its details, no cuts.

  • [1] Bormann, C., "Providing Integrated Services over Low-bitrate Links", RFC 2689, September 1999. ๐Ÿฆ‹
  • [2] Sklower, K., Lloyd, B., McGregor, G., Carr, D. and T. Coradetti, "The PPP Multilink Protocol (MP)", RFC 1990, August 1996. ๐Ÿ’œ
  • [3] Simpson, W., "PPP in Frame Relay", RFC 1973, June 1996. ๐ŸŒธ
  • [4] Andrades, R. and F. Burg, "QOSPPP Framing Extensions to PPP", Work in Progress. ๐Ÿงš
  • [5] Bormann, C., "The Multi-Class Extension to Multi-Link PPP", RFC 2686, September 1999. ๐ŸŽ€
  • [6] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", STD 51, RFC 1661, July 1994. ๐Ÿ‘‘
  • [7] Simpson, W., Editor, "PPP in HDLC-like Framing", STD 51, RFC 1662, July 1994. ๐Ÿ“
  • [8] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. ๐Ÿซถ

11. Author's Address ๐Ÿ’–

Here's where you can find the author, Carsten Bormann ๐Ÿ’…

Carsten Bormann
Universitaet Bremen FB3 TZI
Postfach 330440
D-28334 Bremen, GERMANY

Phone: +49.421.218-7024
Fax:   +49.421.218-7000
EMail: cabo@tzi.org

Acknowledgements ๐Ÿซถ

Big thank yous, bestie! The people at a lunch BOF during the Montreal IETF in 1996 gave really useful input on the design tradeoffs across different environments ๐Ÿฑ Richard Andrades, Fred Burg, and Murali Aravamudan were the ones who insisted on a suspend/resume solution alongside the pre-fragmenting one defined in [5]. Honestly iconic behaviour ๐Ÿ‘‘ Also, the members of the ISSLL subgroup on low bitrate links (ISSLOW) helped put together a set of requirements that shaped this whole solution โœจ


Copyright (C) The Internet Society (1999). All Rights Reserved. ๐ŸŒˆ

Here's the permission situation, and it's pretty generous ๐Ÿฆ‹ You're allowed to copy and share this document and translations of it, and you can make derivative works that comment on or explain it or help with implementing it. You can prepare, copy, publish, and distribute those, in whole or in part, with no restrictions, as long as the copyright notice and this paragraph are included on all copies and derivative works. โœจ

Now the one catch: the document itself can't be modified in any way. You can't remove the copyright notice or the references to the Internet Society or other Internet organizations. The exceptions are when you need it to develop Internet standards, in which case the copyright procedures in the Internet Standards process must be followed, or when you're translating it into a language other than English. ๐Ÿ™ˆ

The permissions above are perpetual and will not be revoked by the Internet Society or its successors or assigns. Forever and ever ๐Ÿ’œ

The document and the information in it are provided on an "AS IS" basis, and the warranty disclaimer is important, so here it is in full: THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ๐Ÿ’€

Acknowledgement ๐ŸŒธ

Funding for the RFC Editor function is currently provided by the Internet Society. So the people keeping this whole library running are supported by them right now ๐Ÿซถโœจ

๐Ÿ“ฆ where this page comes from