Section A. Appendix: Ack Vector Implementation Notes

This appendix discusses particulars of DCCP acknowledgement handling
   in the context of an abstract implementation for Ack Vector.  It is
   informative and not normative.
   The first part of our implementation runs at the HC-Receiver, and
   therefore acknowledges data packets.  It generates Ack Vector
   options.  The implementation has the following characteristics:
   o  At most one byte of state per acknowledged packet.
   o  O(1) time to update that state when a new packet arrives (normal
      case).
   o  Cumulative acknowledgements.
   o  Quick removal of old state.
   The basic data structure is a circular buffer containing information
   about acknowledged packets.  Each byte in this buffer contains a
   state and run length; the state can be 0 (packet received), 1 (packet
   ECN marked), or 3 (packet not yet received).  The buffer grows from
   right to left.  The implementation maintains five variables, aside
   from the buffer contents:
   o  "buf_head" and "buf_tail", which mark the live portion of the
      buffer.
   o  "buf_ackno", the Acknowledgement Number of the most recent packet
      acknowledged in the buffer.  This corresponds to the "head"
      pointer.
   o  "buf_nonce", the one-bit sum (exclusive-or, or parity) of the ECN
      Nonces received on all packets acknowledged by the buffer with
      State 0.
   We draw acknowledgement buffers like this:
      +---------------------------------------------------------------+
      |S,L|S,L|S,L|S,L|   |   |   |   |S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|
      +---------------------------------------------------------------+
                    ^                   ^
                 buf_tail     buf_head, buf_ackno = A     buf_nonce = E
                <=== buf_head and buf_tail move this way <===
   Each "S,L" represents a State/Run length byte.  We will draw these
   buffers showing only their live portion and will add an annotation
   showing the Acknowledgement Number for the last live byte in the
   buffer.  For example:
        +-----------------------------------------------+
      A |S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L| T    BN[E]
        +-----------------------------------------------+
   Here, buf_nonce equals E and buf_ackno equals A.
   We will use this buffer as a running example.
         +---------------------------+
      10 |0,0|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]   [Example Buffer]
         +---------------------------+
   In concrete terms, its meaning is as follows:
      Packet 10 was received.  (The head of the buffer has sequence
      number 10, state 0, and run length 0.)
      Packets 9, 8, and 7 have not yet been received.  (The three bytes
      preceding the head each have state 3 and run length 0.)
      Packets 6, 5, 4, 3, and 2 were received.
      Packet 1 was ECN marked.
      Packet 0 was received.
      The one-bit sum of the ECN Nonces on packets 10, 6, 5, 4, 3, 2,
      and 0 equals 1.
   Additionally, the HC-Receiver must keep some information about the
   Ack Vectors it has recently sent.  For each packet sent carrying an
   Ack Vector, it remembers four variables:
   o  "ack_seqno", the Sequence Number used for the packet.  This is an
      HC-Receiver sequence number.
   o  "ack_ptr", the value of buf_head at the time of acknowledgement.
   o  "ack_runlen", the run length stored in the byte of buffer data at
      buf_head at the time of acknowledgement.
   o  "ack_ackno", the Acknowledgement Number used for the packet.  This
      is an HC-Sender sequence number.  Since acknowledgements are
      cumulative, this single number completely specifies all necessary
      information about the packets acknowledged by this Ack Vector.
   o  "ack_nonce", the one-bit sum of the ECN Nonces for all State 0
      packets in the buffer from buf_head to ack_ackno, inclusive.
      Initially, this equals the Nonce Echo of the acknowledgement's Ack
      Vector (or, if the ack packet contained more than one Ack Vector,
      the exclusive-or of all the acknowledgement's Ack Vectors).  It
      changes as information about old acknowledgements is removed (so
      ack_ptr and buf_head diverge) and as old packets arrive (so they
      change from State 3 or State 1 to State 0).
A.1.  Packet Arrival
   This section describes how the HC-Receiver updates its
   acknowledgement buffer as packets arrive from the HC-Sender.
A.1.1.  New Packets
   When a packet with Sequence Number greater than buf_ackno arrives,
   the HC-Receiver updates buf_head (by moving it to the left
   appropriately), buf_ackno (which is set to the new packet's Sequence
   Number), and possibly buf_nonce (if the packet arrived unmarked with
   ECN Nonce 1), in addition to the buffer itself.  For example, if
   HC-Sender packet 11 arrived ECN marked, the Example Buffer above
   would enter this new state (changes are marked with stars):
         ** +***----------------------------+
         11 |1,0|0,0|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]
         ** +***----------------------------+
   If the packet's state equals the state at the head of the buffer, the
   HC-Receiver may choose to increment its run length (up to the
   maximum).  For example, if HC-Sender packet 11 arrived without ECN
   marking and with ECN Nonce 0, the Example Buffer might enter this
   state instead:
             ** +--*------------------------+
             11 |0,1|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]
             ** +--*------------------------+
   Of course, the new packet's sequence number might not equal the
   expected sequence number.  In this case, the HC-Receiver will enter
   the intervening packets as State 3.  If several packets are missing,
   the HC-Receiver may prefer to enter multiple bytes with run length 0,
   rather than a single byte with a larger run length; this simplifies
   table updates if one of the missing packets arrives.  For example, if
   HC-Sender packet 12 arrived with ECN Nonce 1, the Example Buffer
   would enter this state:
      ** +*******----------------------------+         *
      12 |0,0|3,0|0,1|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[0]
      ** +*******----------------------------+         *
   Of course, the circular buffer may overflow when the HC-Sender is
   sending data at a very high rate, when the HC-Receiver's
   acknowledgements are not reaching the HC-Sender, or when the
   HC-Sender is forgetting to acknowledge those acks (so the HC-Receiver
   is unable to clean up old state).  In this case, the HC-Receiver
   should either compress the buffer (by increasing run lengths when
   possible), transfer its state to a larger buffer, or, as a last
   resort, drop all received packets, without processing them at all,
   until its buffer shrinks again.
A.1.2.  Old Packets
   When a packet with Sequence Number S <= buf_ackno arrives, the
   HC-Receiver will scan the table for the byte corresponding to S.
   (Indexing structures could reduce the complexity of this scan.)  If S
   was previously lost (State 3), and it was stored in a byte with run
   length 0, the HC-Receiver can simply change the byte's state.  For
   example, if HC-Sender packet 8 was received with ECN Nonce 0, the
   Example Buffer would enter this state:
               +--------*------------------+
            10 |0,0|3,0|0,0|3,0|0,4|1,0|0,0| 0    BN[1]
               +--------*------------------+
   If S was not marked as lost, or if it was not contained in the table,
   the packet is probably a duplicate and should be ignored.  (The new
   packet's ECN marking state might differ from the state in the buffer;
   Section 11.4.1 describes what is allowed then.)  If S's buffer byte
   has a non-zero run length, then the buffer might need to be
   reshuffled to make space for one or two new bytes.
   The ack_nonce fields may also need manipulation when old packets
   arrive.  In particular, when S transitions from State 3 or State 1 to
   State 0, and S had ECN Nonce 1, then the implementation should flip
   the value of ack_nonce for every acknowledgement with ack_ackno >= S.
   It is impossible with this data structure to shift packets from State
   0 to State 1, since the buffer doesn't store individual packets' ECN
   Nonces.
A.2.  Sending Acknowledgements
   Whenever the HC-Receiver needs to generate an acknowledgement, the
   buffer's contents can simply be copied into one or more Ack Vector
   options.  Copied Ack Vectors might not be maximally compressed; for
   example, the Example Buffer above contains three adjacent 3,0 bytes
   that could be combined into a single 3,2 byte.  The HC-Receiver
   might, therefore, choose to compress the buffer in place before
   sending the option, or to compress the buffer while copying it;
   either operation is simple.
   Every acknowledgement sent by the HC-Receiver SHOULD include the
   entire state of the buffer.  That is, acknowledgements are
   cumulative.
   If the acknowledgement fits in one Ack Vector, that Ack Vector's
   Nonce Echo simply equals buf_nonce.  For multiple Ack Vectors, more
   care is required.  The Ack Vectors should be split at points
   corresponding to previous acknowledgements, since the stored
   ack_nonce fields provide enough information to calculate correct
   Nonce Echoes.  The implementation should therefore acknowledge data
   at least once per 253 bytes of buffer state.  (Otherwise, there'd be
   no way to calculate a Nonce Echo.)
   For each acknowledgement it sends, the HC-Receiver will add an
   acknowledgement record.  ack_seqno will equal the HC-Receiver
   sequence number it used for the ack packet; ack_ptr will equal
   buf_head; ack_runlen will equal the run length stored in the buffer's
   buf_head byte; ack_ackno will equal buf_ackno; and ack_nonce will
   equal buf_nonce.
A.3.  Clearing State
   Some of the HC-Sender's packets will include acknowledgement numbers,
   which ack the HC-Receiver's acknowledgements.  When such an ack is
   received, the HC-Receiver finds the acknowledgement record R with the
   appropriate ack_seqno and then does the following:
   o  If the run length in the buffer's R.ack_ptr byte is greater than
      R.ack_runlen, then it decrements that run length by
      R.ack_runlen + 1 and sets buf_tail to R.ack_ptr.  Otherwise, it
      sets buf_tail to R.ack_ptr + 1.
   o  If R.ack_nonce is 1, it flips buf_nonce, and the value of
      ack_nonce for every later ack record.
   o  It throws away R and every preceding ack record.
   (The HC-Receiver may choose to keep some older information, in case a
   lost packet shows up late.)  For example, say that the HC-Receiver
   storing the Example Buffer had sent two acknowledgements already:
   1. ack_seqno = 59, ack_runlen = 1, ack_ackno = 3, ack_nonce = 1.
   2. ack_seqno = 60, ack_runlen = 0, ack_ackno = 10, ack_nonce = 0.
   Say the HC-Receiver then received a DCCP-DataAck packet with
   Acknowledgement Number 59 from the HC-Sender.  This informs the
   HC-Receiver that the HC-Sender received, and processed, all the
   information in HC-Receiver packet 59.  This packet acknowledged
   HC-Sender packet 3, so the HC-Sender has now received HC-Receiver's
   acknowledgements for packets 0, 1, 2, and 3.  The Example Buffer
   should enter this state:
               +------------------*+ *       *
            10 |0,0|3,0|3,0|3,0|0,2| 4    BN[0]
               +------------------*+ *       *
   The tail byte's run length was adjusted, since packet 3 was in the
   middle of that byte.  Since R.ack_nonce was 1, the buf_nonce field
   was flipped, as were the ack_nonce fields for later acknowledgements
   (here, the HC-Receiver Ack 60 record, not shown, has its ack_nonce
   flipped to 1).  The HC-Receiver can also throw away stored
   information about HC-Receiver Ack 59 and any earlier
   acknowledgements.
   A careful implementation might try to ensure reasonable robustness to
   reordering.  Suppose that the Example Buffer is as before, but that
   packet 9 now arrives, out of sequence.  The buffer would enter this
   state:
                +----*----------------------+
             10 |0,0|0,0|3,0|3,0|0,4|1,0|0,0| 0     BN[1]
                +----*----------------------+
   The danger is that the HC-Sender might acknowledge the HC-Receiver's
   previous acknowledgement (with sequence number 60), which says that
   Packet 9 was not received, before the HC-Receiver has a chance to
   send a new acknowledgement saying that Packet 9 actually was
   received.  Therefore, when packet 9 arrived, the HC-Receiver might
   modify its acknowledgement record as follows:
   1. ack_seqno = 59, ack_ackno = 3, ack_nonce = 1.
   2. ack_seqno = 60, ack_ackno = 3, ack_nonce = 1.
   That is, Ack 60 is now treated like a duplicate of Ack 59.  This
   would prevent the Tail pointer from moving past packet 9 until the
   HC-Receiver knows that the HC-Sender has seen an Ack Vector
   indicating that packet's arrival.
A.4.  Processing Acknowledgements
   When the HC-Sender receives an acknowledgement, it generally cares
   about the number of packets that were dropped and/or ECN marked.  It
   simply reads this off the Ack Vector.  Additionally, it should check
   the ECN Nonce for correctness.  (As described in Section 11.4.1, it
   may want to keep more detailed information about acknowledged packets
   in case packets change states between acknowledgements, or in case
   the application queries whether a packet arrived.)
   The HC-Sender must also acknowledge the HC-Receiver's
   acknowledgements so that the HC-Receiver can free old Ack Vector
   state.  (Since Ack Vector acknowledgements are reliable, the
   HC-Receiver must maintain and resend Ack Vector information until it
   is sure that the HC-Sender has received that information.)  A simple
   algorithm suffices: since Ack Vector acknowledgements are cumulative,
   a single acknowledgement number tells HC-Receiver how much ack
   information has arrived.  Assuming that the HC-Receiver sends no
   data, the HC-Sender can ensure that at least once a round-trip time,
   it sends a DCCP-DataAck packet acknowledging the latest DCCP-Ack
   packet it has received.  Of course, the HC-Sender only needs to
   acknowledge the HC-Receiver's acknowledgements if the HC-Sender is
   also sending data.  If the HC-Sender is not sending data, then the
   HC-Receiver's Ack Vector state is stable, and there is no need to
   shrink it.  The HC-Sender must watch for drops and ECN marks on
   received DCCP-Ack packets so that it can adjust the HC-Receiver's
   ack-sending rate in response to congestion, for example, with Ack
   Ratio.
   If the other half-connection is not quiescent -- that is, the
   HC-Receiver is sending data to the HC-Sender, possibly using another
   CCID -- then the acknowledgements on that half-connection are
   sufficient for the HC-Receiver to free its state.