# tc-dualpi2

## NAME



           DUALPI2 - Dual Queue Proportional Integral Controller AQM -
           Improved with a square
    


## SYNOPSIS



           **tc qdisc**... **dualpi2**
                   [ **limit** _PACKETS_ ]
                   [ **memlimit** _BYTES_ ]
                   [ **coupling_factor** _NUMBER_ ]
                   [ **step_thresh** _TIME_ |_PACKETS_ ]
                   [ **min_qlen_step** _PACKETS_ ]
                   [ **drop_on_overload** | **overflow**]
                   [ **drop_enqueue** | **drop_dequeue**]
                   [ **l4s_ect** | **any_ect**]
                   [ **classic_protection** _PERCENTAGE_ ]
                   [ **max_rtt** _TIME_  [ **typical_rtt** _TIME_ ]]
                   [ **target** _TIME_ ]
                   [ **tupdate** _TIME_ ]
                   [ **alpha** _float_ ]
                   [ **beta** _float_ ]
                   [ **split_gso** | **no_split_gso**]
    


## DESCRIPTION



           DUALPI2 AQM is a combination of the DUALQ Coupled-AQM with a PI2
           base-AQM. The PI2 AQM (details can be found in the paper cited
           below) is in turn both an extension and a simplification of the
           PIE AQM. PI2 makes quite some PIE heuristics unnecessary, while
           being able to control scalable congestion controls like TCP-
           Prague. With PI2, both Reno/Cubic can be used in parallel with
           Prague, maintaining window fairness. DUALQ provides latency
           separation between low latency Prague flows and Reno/Cubic flows
           that need a bigger queue. The main design goals are:
           •   L4S - Low Loss, Low Latency and Scalable congestion control
               support
           •   DualQ option to separate the L4S traffic in a low latency
               queue (L-queue), without harming remaining traffic that is
               scheduled in classic queue (C-queue) due to congestion-
               coupling
           •   Configurable overload strategies
           •   Use of sojourn time to reliably estimate queue delay
           •   Simple implementation
           •   Guaranteed stability and fast responsiveness
    
           The detailed PI2 parameters (alpha, beta, and tupdate) of DualPI2
           are hard to get right and typically give bad results if just tried
           or guessed. These parameters need to be calculated to a coherent
           set with a typical objective in mind. DualPI2 has a set of default
           parameters that can be used for the general Internet, where the
           maximum RTT is around 100ms and the typical RTT is around 15ms. It
           is highly recommended to use  _max_rtt_ and  _typical_rtt_ (or target)
           helper parameters if your deployment is deviating from the above
           objectives (e.g., in a data center). These helpers are used to
           provide the theoretically optimal PI2 parameters (alpha, beta, and
           tupdate) for those objectives, and that can be used as a basis for
           further finetuning, experimentation, and testing if desired.
    


## ALGORITHM



           DUALPI2 is designed to provide low loss and low latency to L4S
           traffic, without harming classic traffic. Every update interval, a
           new internal base probability is calculated based on queue delay.
           The base probability is updated with a delta based on the
           difference between the current queue delay and the  _target_ delay,
           and the queue growth compared with the queuing delay during the
           previous  _tupdate_ interval. The integral gain factor **alpha** is used
           to correct slowly enough any persistent standing queue error to
           the user specified target delay, while the proportional gain
           factor **beta** is used to quickly compensate for queue changes
           (growth or shrink).
    
           The updated base probability is used as input to decide to mark
           and drop packets. DUALPI2 scales the calculated probability for
           each of the two queues accordingly. For the L-queue, the
           probability is multiplied by a **coupling_factor** , while for the C-
           queue, it is squared to compensate the squareroot rate equation of
           Reno/Cubic. The ECT identifier ( **l4s_ect** |**any_ect**) is used to
           classify traffic into respective queues.
    
           If DUALPI2 AQM has detected overload (when excessive non-
           responsive traffic is sent), it can signal congestion solely using
           **drop** , irrespective of the ECN field, or alternatively limit the
           drop probability and let the queue grow and eventually **overflow**
           (like tail-drop).
    
           Additional details can be found in the RFC cited below.
    


## PARAMETERS



           **limit** _PACKETS_
                  Limit the number of packets that can be enqueued. Incoming
                  packets will be dropped once this limit is reached. This
                  limit is common for the L-queue and C-queue. Defaults to
                  _10000_ packets. This is about 125ms delay on a 1Gbps link.
    
           **memlimit** _BYTES_
                  Limit the total amount of memory that can be used. Incoming
                  packets will be dropped once this memlimit is reached. This
                  memlimit is common for the L-queue and C-queue. Defaults to
                  _10000 * interface MTU bytes._
    
           **coupling_factor** _NUMBER_
                  Set the coupling rate factor between Classic and L4S.
                  Defaults to _2_
    
           **l4s_ect** _|_**any_ect**
                  Configures the ECT classifier. Packets whose ECT codepoint
                  matches this are sent to the L-queue, where they receive a
                  scalable marking. Defaults to _l4s_ect_ , i.e., the L4S
                  identifier ECT(1). Setting this to _any_ect_ causes all
                  packets whose ECN field is not zero to be sent to the L-
                  queue. This enables it to be backward compatible with,
                  e.g., DCTCP. Note DCTCP should only be used for intra-DC
                  traffic with very low RTTs and AQM delay targets bigger
                  than those RTTs, separated from Internet traffic (also if
                  Prague compliant CC), as it does not support all Prague
                  requirements that make sure that a congestion control can
                  work well with the range of RTTs on the Internet.
    
           **step_thresh** _TIME | PACKETS_
                  Set the step threshold for the L-queue. This will cause
                  packets with a sojourn time exceeding the threshold to
                  always be marked. This value can either be specified using
                  time units (i.e., us, ms, s), or in packets (p, pkt,
                  packet(s)). A value without units is assumed to be in time
                  (us). If defining the step in packets, be sure to disable
                  GRO on the ingress interfaces. Defaults to _1ms_
    
           **min_qlen_step** _PACKETS_
                  Incoming packets enqueued to the L-queue may apply the step
                  threshold when the queue length of the L-queue exceeds this
                  value. Default to _0_ packets. This means that every enqueued
                  packets to the L-queue with a sojourn time exceeds the step
                  threshold will be marked.
    
           **drop_on_overload | overflow**
                  Control the overload strategy.  _drop_on_overload_ preserves
                  the delay in the L-queue by dropping in both queues on
                  overload.  _overflow_ sacrifices delay to avoid losses,
                  eventually resulting in a taildrop behavior once the _limit_
                  is reached. Defaults to _drop_on_overload_
    
           **drop_enqueue | drop_dequeue**
                  Decide when packets are PI-based dropped or marked. The
                  _step_thresh_ based L4S marking is always at dequeue.
                  Defaults to _drop_dequeue_
    
           **classic_protection** _PERCENTAGE_
                  Protects the C-queue from unresponsive traffic in the L-
                  queue. This bounds the maximal scheduling delay in the C-
                  queue to be _(100 - PERCENTAGE)_ times greater than the one
                  in the L-queue. Defaults to _10_
    
           **typical_rtt** _TIME_
           **max_rtt** _TIME_
                  Specify the maximum round trip time (RTT) and/or the
                  typical RTT of the traffic that will be controlled by
                  DUALPI2. These values are specified using time units (i.e.,
                  us, ms, s). A value without units is assumed to be in us.
                  If either _max_rtt_ or _typical_rtt_ is not specified, the
                  missing value will be computed from the following
                  relationship: _max_rtt = typical_rtt * 6._  If any of these
                  parameters is given, it will be used to automatically
                  compute suitable values for _alpha, beta, target, and_
                  _tupdate,_ according to the relationship from the appendix
                  A.1 in the IETF RFC cited below, to achieve a stable
                  control. Consequently, those derived values will override
                  their eventual user-provided ones. The default range of
                  operation for the qdisc uses _max_rtt = 100ms_ and
                  _typical_rtt = 15ms_ , which is suited to controlling
                  Internet traffic.
    
           **target** _TIME_
                  Set the expected queue delay. Defaults to _15_ ms. A value
                  without units is assumed to be in us.
    
           **tupdate** _TIME_
                  Set the frequency at which the system drop probability is
                  calculated. Defaults to _16_ ms. A value without units is
                  assumed to be in microseconds. This should be less than
                  one-third of the maximum RTT supported.
    
           **alpha** _float_
           **beta** _float_
                  Set alpha and beta, the integral and proportional gain
                  factors in Hz for the PI controller. These can be
                  calculated based on control theory. Defaults are _0.16_ and
                  _3.2_ Hz, which provide stable control for RTT's up to 100ms
                  with tupdate of 16ms. Be aware, unlike with PIE, these are
                  the real unscaled gain factors. If not provided, they will
                  be automatically derived from _typical_rtt and max_rtt_ , if
                  one of them or both are provided.
    
           **split_gso | no_split_gso**
                  Decide how to handle aggregated packets. Either treat the
                  aggregate as a single packet (thus all share fate with
                  respect to marks and drops) with _no_split_gso_ , trading
                  some tail latency for CPU usage, or treat each packet
                  individually (i.e., split them) with _split_gso_ to enable
                  fine-grained marking/dropping of packets to control
                  queueing latencies. Defaults to _split_gso_
    


## EXAMPLES



           Setting DUALPI2 for the Internet with default parameters:
            # sudo tc qdisc add dev eth0 root dualpi2
    
           Setting DUALPI2 for datacenter with legacy DCTCP using ECT(0):
            # sudo tc qdisc add dev eth0 root dualpi2 any_ect
    


## FILTERS



           This qdisc can be used in conjunction with tc-filters. More
           precisely, it will honor filters "stealing packets", as well as
           accept other classification schemes.
    
           Packets whose priority/classid are set to
                  _1_ will be enqueued in the L-queue, alongside L4S traffic,
                  and thus subject to the increased marking probability (or
                  drops if they are marked not-ECT).
    
           Packets whose priority/classid are set to
                  _2_ will also be enqueued in the L-queue, but will never be
                  dropped if they are not-ECT (unless the qdisc is full and
                  thus resorts to taildrop).
    
           Finally, all the other classid/priority map to the C-queue.
    


## SOURCES



           •   IETF RFC9332 : https://datatracker.ietf.org/doc/html/rfc9332
    
           •   CoNEXT '16 Proceedings of the 12th International on Conference
               on emerging Networking Experiments and Technologies : "PI2: A
               Linearized AQM for both Classic and Scalable TCP"
    


* * *