TCP Tahoe Algorithm



The Transmission Control Protocol (TCP) is one of the most widely used protocols in computer networking. It provides a reliable, ordered, and error-checked delivery of data between applications running on hosts communicating over an IP network.

TCP Tahoe algorithm is a congestion control algorithm by which TCP controls the amount of data that can be sent over a network for avoiding network congestion.

What is TCP Tahoe Algorithm?

TCP Tahoe is one of the earliest congestion control algorithms used in Transmission Control Protocol (TCP) that automatically adjusts its packet sending rate based on the network conditions. It assumes a packet loss as a sign of network congestion and drastically reduces the data transmission rate.

The primary objective of TCP Tahoe was to provide a reliable and efficient approach to controlling congestion in computer networks. This involved detecting network congestion and implementing mechanisms to reduce data transmission rates to prevent packet loss.

The following graph depicts how the TCP Tahoe algorithm works −

TCP Tahoe Algorithm

The most important characteristics of TCP Tahoe algorithm are as follows −

  • It ensures reliable packet delivery by allowing retransmission of lost packets.
  • TCP Tahoe is easy and simple to implement.
  • It is good for low-congestion or low-bandwidth networks.
  • Any packet loss is treated as congestion.

Working of TCP Tahoe Algorithm

TCP Tahoe works in three main phases that are mentioned below −

  • Slow start − In slow start phase, the congestion window (cwnd) starts with a small value and then increases exponentially with each acknowledgment received. It keeps increasing until it reaches a threshold (ssthresh) or packet loss occurs.
  • Congestion avoidance − It uses the AIMD (Additive Increase Multiplicative Decrease) method. Once the cwnd reaches the ssthresh, the congestion avoidance phase starts. In this phase, the cwnd increases linearly (earlier it was increasing exponentially) with each acknowledgment received.
  • Fast retransmit − When a packet loss occurs , TCP Tahoe immediately reduces the cwnd to 1 MSS and sets the ssthresh to half of the current cwnd. It then enters the slow start phase again.

Here is an example based on the above working of TCP tahoe algorithm. Initially, cwnd = 1 MSS, ssthresh = 8 MSS, and a packet loss occurs when cwnd = 8 MSS

1. Start in Slow Start, cwnd = 1
Receive ACK -> cwnd = 2
Receive ACK -> cwnd = 4
Receive ACK -> cwnd = 8
cwnd = ssthresh = 8 => stop exponential growth.

2. Congestion Avoidance Phase:
cwnd = 8, increase slowly (approx +1 per RTT): cwnd = 9

3. Packet Loss at cwnd = 9
=> New ssthresh = (cwnd / 2) = (9 / 2) = 4
Reset cwnd to 1

4. Restart Slow Start
Restart and grow only until new ssthresh (4):
cwnd = 1 -> ACK -> cwnd = 2
cwnd = 2 -> ACK -> cwnd = 4

cwnd = new ssthresh (4)
=> Repeat from step 2. 

Steps to Implement TCP Tahoe Algorithm

Here are the steps to implement TCP Tahoe algorithm given below −

  • Set the cwnd = 1 MSS and initial value of ssthresh and the number of iterations.
  • In Slow Start phase increase cwnd by 1 MSS for every ACK received.
  • When cwnd reaches ssthresh, switch to Congestion Avoidance phase and increase cwnd slowly.
  • In case of packet loss, i.e., when timeout or in case of 3 duplicate ACKs, it is considered as congestion.
  • Now, set ssthresh = cwnd / 2, reset cwnd to 1 MSS, and go back to Slow Start.

Code Implementation

Here is the code implementation of the above steps for TCP Tahoe algorithm in C++, Java, and python −

#include <iostream>
using namespace std;

int main() {
    int cwnd = 1;       // congestion window (in MSS units)
    int ssthresh = 8;   // slow start threshold
    int maxRounds = 8;  // Updated to 8 rounds

    cout << "Initial cwnd = " << cwnd 
         << ", ssthresh = " << ssthresh << "\n\n";

    for (int round = 1; round <= maxRounds; ++round) {
        cout << "Round " << round << ":";

        // Loss simulation at 5th round
        bool loss = (round == 5);  

        if (loss) {
            cout << "  Packet loss detected!\n";
            ssthresh = cwnd / 2;
            if (ssthresh < 1) 
                ssthresh = 1;
            cwnd = 1;
            cout << "  New ssthresh = " << ssthresh << "\n";
            cout << "  cwnd reset to " << cwnd << " (Slow Start)\n";
        } else {
            if (cwnd < ssthresh) {
                cout << "  Phase: Slow Start\n";
                cwnd *= 2;
            } else {
                cout << "  Phase: Congestion Avoidance\n";
                cwnd += 1;
            }
            cout << "  cwnd = " << cwnd << ", ssthresh = " << ssthresh << "\n";
        }
    }
    return 0;
}

The output of the above code is as follows −

Initial cwnd = 1, ssthresh = 8

Round 1:  Phase: Slow Start
  cwnd = 2, ssthresh = 8
Round 2:  Phase: Slow Start
  cwnd = 4, ssthresh = 8
Round 3:  Phase: Slow Start
  cwnd = 8, ssthresh = 8
Round 4:  Phase: Congestion Avoidance
  cwnd = 9, ssthresh = 8
Round 5:  Packet loss detected!
  New ssthresh = 4
  cwnd reset to 1 (Slow Start)
Round 6:  Phase: Slow Start
  cwnd = 2, ssthresh = 4
Round 7:  Phase: Slow Start
  cwnd = 4, ssthresh = 4
Round 8:  Phase: Congestion Avoidance
  cwnd = 5, ssthresh = 4
public class Main {
    public static void main(String[] args) {
        int cwnd = 1;       // congestion window
        int ssthresh = 8;   // slow start threshold
        int maxRounds = 8;  // total 8 rounds

        System.out.println("Initial cwnd = " + cwnd + ", ssthresh = " + ssthresh + "\n");

        for (int round = 1; round <= maxRounds; round++) {
            System.out.print("Round " + round + ":");

            boolean loss = (round == 5); // Loss simulation only at 5th round

            if (loss) {
                System.out.println("  Packet loss detected!");
                ssthresh = cwnd / 2;
                if (ssthresh < 1)
                    ssthresh = 1;
                cwnd = 1;
                System.out.println("  New ssthresh = " + ssthresh);
                System.out.println("  cwnd reset to " + cwnd + " (Slow Start)");
            } else {
                if (cwnd < ssthresh) {
                    System.out.println("  Phase: Slow Start");
                    cwnd *= 2;
                } else {
                    System.out.println("  Phase: Congestion Avoidance");
                    cwnd += 1;
                }
                System.out.println("  cwnd = " + cwnd + ", ssthresh = " + ssthresh);
            }
        }
    }
}

The output of the above code is as follows −

Initial cwnd = 1, ssthresh = 8

Round 1:  Phase: Slow Start
  cwnd = 2, ssthresh = 8
Round 2:  Phase: Slow Start
  cwnd = 4, ssthresh = 8
Round 3:  Phase: Slow Start
  cwnd = 8, ssthresh = 8
Round 4:  Phase: Congestion Avoidance
  cwnd = 9, ssthresh = 8
Round 5:  Packet loss detected!
  New ssthresh = 4
  cwnd reset to 1 (Slow Start)
Round 6:  Phase: Slow Start
  cwnd = 2, ssthresh = 4
Round 7:  Phase: Slow Start
  cwnd = 4, ssthresh = 4
Round 8:  Phase: Congestion Avoidance
  cwnd = 5, ssthresh = 4
def tcp_tahoe():
    cwnd = 1       # congestion window
    ssthresh = 8   # slow start threshold
    max_rounds = 8 # total 8 rounds

    print(f"Initial cwnd = {cwnd}, ssthresh = {ssthresh}\n")

    for round_num in range(1, max_rounds + 1):
        print(f"Round {round_num}:", end="")

        loss = (round_num == 5)  # Packet loss at round 5

        if loss:
            print("  Packet loss detected!")
            ssthresh = max(cwnd // 2, 1)
            cwnd = 1
            print(f"  New ssthresh = {ssthresh}")
            print(f"  cwnd reset to {cwnd} (Slow Start)")
        else:
            if cwnd < ssthresh:
                print("  Phase: Slow Start")
                cwnd *= 2
            else:
                print("  Phase: Congestion Avoidance")
                cwnd += 1

            print(f"  cwnd = {cwnd}, ssthresh = {ssthresh}")


if __name__ == "__main__":
    tcp_tahoe()

The output of the above code is as follows −

Initial cwnd = 1, ssthresh = 8

Round 1:  Phase: Slow Start
  cwnd = 2, ssthresh = 8
Round 2:  Phase: Slow Start
  cwnd = 4, ssthresh = 8
Round 3:  Phase: Slow Start
  cwnd = 8, ssthresh = 8
Round 4:  Phase: Congestion Avoidance
  cwnd = 9, ssthresh = 8
Round 5:  Packet loss detected!
  New ssthresh = 4
  cwnd reset to 1 (Slow Start)
Round 6:  Phase: Slow Start
  cwnd = 2, ssthresh = 4
Round 7:  Phase: Slow Start
  cwnd = 4, ssthresh = 4
Round 8:  Phase: Congestion Avoidance
  cwnd = 5, ssthresh = 4

Pros and Cons of TCP Tahoe Algorithm

The following list highligths the advantages of TCP Tahoe algorithm

  • It is simple to implement. It is effective in controlling congestion in networks.
  • It helps to avoid network collapse due to congestion.
  • It is a stable congestion control mechanism.
  • It increases the reliability of data transmission.

The limitations of TCP Tahoe are as follows −

  • The network resources remain underutilized.
  • It is not suitable for high-speed networks.
  • It can cause high latency.
  • Bandwidth utilization remains inefficient as window size drops to 1 MSS.
  • It restarts from slow Start on packet loss.
  • It treats a loss like a congestion.

Conclusion

TCP Tahoe is a congestion control algorithm that provides a reliable, ordered, and error-checked delivery of data packets. In this chapter, we covered the features, working, implementation steps, code implementation, advantages, and limitations of the TCP Tahoe algorithm.

Advertisements