5.4.3 Control de congestión en TCP

El método utilizado por TCP para control de la congestión es el basado en la regulación del tráfico inyectado a la red. Esto supone que implementa funciones que le permiten estudiar cuándo es posible enviar más tráfico por el enlace, y cuándo se ha superado la capacidad del mismo y se debe disminuir la carga.

TCP emplea 4 algoritmos relacionados entre sí a los efectos de efectuar el control de congestión. Ellos son conocidos con slow start, congestion avoidance, fast retransmit y fast recovery.

Los algoritmos slow start y congestion avoidance, deben ser utilizados por la fuente TCP a los efectos de controlar la cantidad de tráfico inyectado en la red. Para esto se cuenta con tres variables de estado del protocolo. Estas son cwnd (congestion Windows), que controla del lado de la fuente la cantidad de datos que se puede enviar sin haber recibido un ACK, rwnd (receiver’s advertised window) que indica la cantidad de datos que puede recibir el destino y ssthresh (slow start threshold) que indica en qué fase de control de congestión se encuentra el transmisor (slow start si es mayor que cwnd o congestion avoidance si es menor; de ser iguales, se puede utilizar cualquiera de los dos algoritmos). El mínimo de cwnd y rwnd gobierna la transmisión. El algoritmo slow start es utilizado al comienzo de una transmisión a los efectos de que TCP pueda testear la red y conocer su capacidad evitando congestionarla. También es utilizado en el momento de recuperación ante la pérdida de algún segmento, indicada por timeout. Luego del three-way handshake, el tamaño de la ventana inicial de envío (IW: initial Windows) debe ser menor o igual que 2 x SMSS1 bytes y no mayor a dos segmentos. El valor de ssthresh debería ser lo más alto posible al comienzo (por ejemplo, igual a rwnd) y deberá reducirse en caso de congestión. Durante la fase slow start se aumenta cwnd en a lo sumo SMSS bytes por cada ACK recibido de datos nuevos entregados al receptor. Esta fase culmina cuando cwnd alcanza a ssthresh o cuando se detecta congestión.



A partir de allí se inicia la fase de congestion avoidance donde cwnd se incrementa en un segmento por round-trip time (tiempo que transcurre entre que sale un segmento y llega el ACK asociado). Esta fase continúa hasta que se alcanza la congestión nuevamente.

Durante la fase de congestion avoindance, la actualización de la variable cwnd, se realiza con la siguiente fórmula:

cwnd = cwnd + SMSS x SMSS / cwnd
Calculándose cada vez que llega un ACK no duplicado.

Cuando el transmisor detecta la pérdida de un segmento, a partir del timer de retransmisión, el valor de ssthresh debe pasar a ser:

ssthresh = max (FS / 2, 2 x SMSS)

Siendo FS (Flight Size) la cantidad de datos enviados pero aún no reconocidos o ACKed. Al mismo tiempo, cwnd no puede ser mayor que LW (Loss Window) que vale 1 segmento y sin importar el valor de IW. Se identifica con LW al tamaño de cwnd luego de detectar, a través del timer de retransmisión, una pérdida.



Posteriormente se pasa a la fase de slow start hasta alcanzar el ssthresh y luego se seguirá con la fase congestion avoidance.

Cuando se detecta la primera pérdida en una ventana de datos, mientras no se reparen todos los segmentos de dicha ventana, la cantidad de segmentos transmitidos e cada RTT no podrán ser mayor a la mitad de los segmentos salientes cuando la pérdida fue detectada. Luego que todos los segmentos fueran exitosamente retransmitidos, cwnd no podrá tomar un valor mayor a ssthresh y la fase siguiente será congestion avoidance. Pérdidas en dos ventanas de datos sucesivas o en retransmisiones indica congestión e implica que cwnd y ssthresh deben bajar dos veces.

El receptor TCP debería enviar inmediatamente un ACK duplicado si recibe un segmento fuera de orden. Con ello busca informar al transmisor el número de secuencia esperado. Las conclusiones a las que puede arribar el transmisor ante la llegada de ACK duplicados pueden ser varias. Primero, puede concluir que está ante la presencia de segmentos descartados; segundo, que por razones de tránsito en la red, los segmentos están llegando en desorden al receptor y tercero, que ocurre por duplicación de los segmentos o de los ACKs en la propia red. El receptor también debería enviar inmediatamente un ACK para aquel segmento que recibe y que se encuentra en el hueco del espacio de número de secuencia esperado de forma de colaborar con el transmisor.



El algoritmo fast retransmit debería ser utilizado para detectar y reparar pérdidas basado en la recepción de ACK duplicados. El algoritmo emplea la recepción de 3 ACK duplicados (4 ACKs idénticos) para concluir que un segmento se ha perdido. El transmisor envía el segmento que deduce se ha perdido sin esperar que expire el timer  de retransmisión, sstresh toma el valor dado por la ecuación  y cwnd toma un valor dado por la ecuación:

cwnd = ssthresh + 3 x SMSS
(Lo que se conoce como inflado artificial de cwnd).

Esto hace crecer cwnd en la cantidad de segmentos (ACK en este caso) que abandonaron la red. Un criterio similar seguirá por cada ACK duplicado recibido. Luego de ello, el algoritmo fast recovery gobierna la transmisión mientras no se reciban nuevos ACK duplicados. De ser posible (según los valores de cwnd y rwnd), se transmite un nuevo segmento y ante la llegada de un ACK de datos nuevos lleva el valor de cwnd al de ssthresh (lo que se conoce como desinflado de cwnd). El no pasar a la fase de slow start ante la pérdida del segmento se justifica en el hecho de que la llegada de ACK duplicado implica que quien lo envió recibió un segmento, por lo tanto, hay segmentos que están abandonando la red y por lo tanto dejan de consumir recursos en ella.

Estos algoritmos no se comportan adecuadamente ante pérdidas múltiples en un “single flight” de segmentos lo que motivó el desarrollo de un conjunto de implementaciones adicionales.

Para calcular el RTO actual, el transmisor mantiene 2 variables de estado llamadas SRTT (smothed round-trip time) y RTTVAR (round-trip time variation). Mientras no se calcule un RTT, el mismo debe valer como máximo 3 segundos. Cuando se calcula el primer RTT (R), las variables tomarán los siguientes valores:

SRTT = R
RTTVAR = R/2
RTO = SRTT + max (G, K x RTTVAR)

Donde K = 4 y G es la granularidad del reloj, medida en segundos.

Para el siguiente cálculo de RTT (R') los nuevos valores de las variables serán:

RTTVAR = (1 - β) x RTTVAR + β x |SRTT - R'|
SRTT = (1 - α) x SRTT + α x R'
Donde los valores de α y β deberían ser 1/8 y ¼ respectivamente.
RTO = SRTT + max (G, K x RTTVAR)

RTO no debería ser menor que 1 ni mayor que 60 segundos.


La toma de las muestras RTT se debe realizar utilizando el algoritmo de Karn. Ello implica que no debe hacerse utilizando segmentos retransmitidos (salvo que se utilice la opción timestamp) y que en caso de expirar, se debería retransmitir el primer segmento no ACKed y efectuar un backoff, pasando RTO a valer el doble y lanzarlo nuevamente. Se debe realizar como mínimo una medida por round-trip time de forma de evitar el efecto de aliasing en el cálculo de RTO para el caso de ventanas de congestión grandes.