Subject: [tcpm] thoughts on newcwv-05

From: Mark Allman <[email-masked]>
Date: Tue, 18 Feb 2014 10:51:28 -0500

Hi folks!

I took a spin through newcwv-05 yesterday.  I scribbled down some
thoughts and figured I'd share.  I am mostly a lurker and haven't really
followed the discussion of this document on the list.  So, this is
perhaps old stuff, but I prefer to think of it as I am coming with fresh
eyes. :-)

  + This:

       Standard TCP [RFC5681] requires the cwnd to be reset to the
       restart window (RW) when an application becomes idle.

    is just wrong.  RFC 5681 says 

       Therefore, a TCP SHOULD set cwnd to no more than RW before
       beginning transmission if the TCP has not sent data in an
       interval exceeding the retransmission timeout.

    I.e., there is no requirement, just a strong recommendation.

  + I would suggest using the terminology of RFC 2681.  I.e.,
    "application limited periods" not "rate-limiting".  Unless of course
    you mean something different.  If that is the case then you should
    sketch the difference.  But, be consistent where you can.

  + By the end of sections 1 & 2 I figured I'd have some notion about
    why we are inventing a new CWV.  But, the best I can come up with is
    the old CWV is "too conservative for many common rate-limited
    applications".  And, that might be fine if that was well explained,
    but it doesn't really go further than that partial sentence.

    Why is CWV too conservative?  Why is it OK to be more aggressive?
    What sorts of applications does the old version hinder?

    RFC 2681 is a very nicely methodical treatment of why the mechanism
    is defined as it is.  It clearly highlights that it is
    conservative.  But, it roots that conservativism in the rest of
    TCP's operation and principles.  I would expect that if you were
    going to update CWV and/or make it more conservative that you would
    likewise articulate why you think it is OK to be more aggressive and
    what sorts of principles you are using to guide how much
    aggressiveness is OK.  

    Unfortunately, this document offers none of that.  It reads as an
    ad-hoc bag of tricks that makes CWV more aggressive for nebulous
    reasons and with mechanisms/constants/algorithms that are simply
    pulled from thin air.  I assume pulling this spec out of thin air is
    not the approach that was used.  So, it shouldn't be a big deal to
    explain why you did what you did and why that is a reasonable
    change.

  + Specifically, it has always seemed to me like CWV tries to stay out
    of the way.  The only time it really limits transmissions is when
    those transmissions (by the application) are sent at a higher rate
    than is currently validated by the load being placed on the network.
    So, reading the tea leaves on this document it seems that you aim to
    support applications that place a load on the network that is more
    volatile than nicely accommodated by CWV.  This is the sort of thing
    I'd expect to see systematically described in this document.  But, I
    am left to working this notion up myself.

  + Also, along the same lines the document says things like "It is
    expected that this update will satisfy the requirements of many
    rate-limited applications".  Well, OK.  But, **what are those
    requirements**?  You never tell us.  Why do you expect us to believe
    your algorithm addresses them?  There is no basis for statements
    like this.  I could say "newcwv does not satisfy the requirements of
    many rate-limited applications" and be on just as firm of ground as
    you when you make the statement you do.

  + Given the above it is difficult to really inhale the rest of the
    document (the algorithm) because I am not sure what you're really
    trying to accomplish.  So, the rest of these comments could well be
    half-baked.

  + "[newcwv] also reduces the incentive for an application to send data
    simply to keep transport congestion state.  (This is sometimes known
    as "padding")."

    Fair enough.  But, wouldn't it also be fair to sketch the other side
    of the coin?  I.e., that by treating state as "valid" for longer
    periods of time you increase the chances that the "valid" state is
    actually wrong?  Seemingly a balanced treatment would call out the
    pros and the cons.

  + This:
 
      [RFC5681] defines a variable, FlightSize, that indicates the
      amount of outstanding data in the network.  This is assumed to be
      equal to the value of Pipe calculated based on the pipe algorithm
      [RFC3517].

    is just wrong.  FlightSize and Pipe seek to assess the same sort of
    thing.  But, they are not **equal**.  And, Pipe is only valid for
    loss recovery.  FlightSize is the amount of data sent by not
    cumulatively acknowledged.  During loss recovery that value is not
    an accurate representation of the data that is in the network.
    Therefore, we calculate a *different* variable called Pipe that
    takes into account SACK information to form a more precise notion of
    what is in the network.

  + "The method RECOMMENDS that the TCP SACK option [RFC3517]"

    This should be [RFC2018], which defines the option.

  + Also, [RFC3517] should be [RFC6675] unless there is a specific
    reason to cite the old version.

  + I find this:

      The value 1/2 was selected to reduce the effects of variations in
      the pipeACK variable, and to allow the sender some flexibility in
      when it sends data.
    
    To be isomorphic of "The value of 1/2 was selected out of the thin
    blue air."

    I.e., wouldn't a sentence with a different value like this: 

      The value 5/8 was selected to reduce the effects of variations in
      the pipeACK variable, and to allow the sender some flexibility in
      when it sends data.

    Be just as valid?

    You are just pretending to justify the magic number you have chosen
    when in fact you are saying nothing at all.

  + Now, I could better justify the choice of 1/2 based on TCP's
    operation.  I think perhaps you could note that:

    (1) When TCP is not filling the network during slow start we find it
        acceptable to double the load from one RTT to the next.
        Therefore, as long as we treat the validated phase as being at
        least 1/2*cwnd we will not cause more than a doubling from one
        RTT to the next and hence this is consistent with TCP's
        principles.

    (2) On the other hand, when we store more than 1/2*cwnd worth of
        permission to send then we can increase the rate (from one RTT
        to the next) faster than TCP would naturally and therefore in
        this regime we need to be more careful and adjust the cwnd.

    That roots your choice in something more fundamental than thin air
    and at least attempts to justify things.

    One might argue that the constant really should be 2/3 because with
    delayed ACKs---which are commonplace---the increase between two RTTs
    is at most 50%.  We could discuss this, I suppose.  On the one hand,
    that is probably closer to operationally correct.  On the other
    hand, I wrote the ABC spec. :)

  + "A TCP sender that enters the non-validated phase will preserve the
    cwnd"

    I don't like "will".  I think you mean "MUST" or perhaps "SHOULD".
    Something prescriptive anyway.

  + A general comment is that I find this document very hard to follow.
    There are forward references all over the place.  Can't this be
    simplified into a linear discussion of the algorithm?

  + I think this:

      Reception of congestion feedback while in the non-validated phase
      is interpreted as an indication that it was inappropriate for the
      sender to use the preserved cwnd.  The sender is therefore
      required to quickly reduce the rate to avoid further congestion.
      Since the cwnd does not have a validated value, a new cwnd value
      must be selected based on the utilised rate.

    is exactly what RFC 5681 says.  I.e., it is why we changed things to
    be based on FlightSize.  I.e., it doesn't matter what is poked into
    "cwnd" at a given time, FlightSize is the load being imposed on the
    network and so that is the basis for the reaction to congestion.

    So, my reading of things is that RFC 5681 **already does** what you
    say you want in the above blurb.  And, yet, you go off and sketch a
    different reaction.  That may be fine, but you should at least
    sketch why the current standard is not germane here and why we need
    to go invent some new reaction.  

    This is the sort of thing that makes this entire algorithm feel
    ad-hoc.  It reads like you didn't realize what already exists and so
    you invent new things.  I know that to not be the case, but that is
    exactly how this document comes off.

  + You claim this is a "safe" cwnd in response to congestion:

       cwnd = (Max(pipeACK,LossFlightSize))/2.

    But, let's think about that for a moment.  Say LossFlightSize is X.
    And so we took a loss (congestion) when imposing a load of X.  And,
    we know that cwnd can be up to 2*X at this point.  So, pipeACK could
    also be 2*X (from three RTTs ago, say).  So, after running the above
    we could have a cwnd of LossFlightSize---which is the load imposed
    when we observe congestion.  So, we could see no effective change in
    the imposed load.  Is that "safe"?  Is no reduction in sending rate
    "safe"?  I would minimally expect a discussion of why this is to be
    viewed as "safe" when it seemingly flies in the face of the way we
    have worked congestion control for a long time.

    And, yes, you further reduce FlightSize or pipeACK by R.  But,
    consider the case where R=1.  It hardly matters.

    (Note, I have purposely sketched the bounds cases.  Certainly things
    may not be like this in every case.  But, we should think about the
    worst case for what is being proposed.)

  + Then there is this:

      The sender MUST then update cwnd to be not greater than:

            cwnd = max((1/2)*cwnd, IW).

      Where IW is the appropriate TCP initial window, used by the TCP
      sender (e.g. [RFC5681]).

      (This adjustment ensures that sender responds conservatively at the
      end of the non-validated phase by reducing the cwnd to better reflect
      the current rate of the sender.  The cwnd update does not take into
      account FlightSize or pipeACK value because these values only reflect
      historical data and do not reflect the current sending rate.)

    I don't understand this.  FlightSize is not "historical data".
    FlightSize is the amount of outstanding data ***at each instant***.
    If there is no unacknowledged data then FlightSize is zero.  If we
    have 15K of unACKed data then FlightSize is 15K.  The above text is
    just confused.

I can't tell if newcwv is needed or sound or whatnot.  The document
needs to be a whole bunch better.  I am happy to extend the benefit of
the doubt and believe there are some improvements we can make to CWV.
But, this document didn't convince me of it.  And, if I suspend
disbelief I can't even figure out if the algorithm is particularly
appropriate as it is not well explained.

FWIW.

allman