English French
In question 1, we assumed that the receiver acknowledged every segment received from the sender. In practice, many deployed TCP implementations use delayed acknowledgments. Assuming a delayed acknowledgment timer of 50 milliseconds, modify the time-sequence diagram below to reflect the impact of these delayed acknowledgment. Does their usage decreases or increased the transmission delay ?
In the example above, packetdrill_ injects a segment containing two bytes. This segment is acknowledged and after that the :manpage:`read` system call succeeds and reads the available data with a buffer of 1000 bytes. It returns the amount of read bytes, i.e. ``2``.
In this series of exercises, you will explore in more details the operation of TCP and its congestion control scheme. TCP is a very important protocol in today's Internet since most applications use it to exchange data. We first look at TCP in more details by injecting segments in the Linux TCP stack and analyze how the stack reacts. Then we study the TCP congestion control scheme.
Let us first explore how a TCP connection can be established. In the previous script, we have injected the segments that a client would send to a server. We can also use the Linux stack as a client and inject the segments that a server would return. Such a client process would first create its :manpage:`socket`` and then issue the :manpage:`connect` system call. At this point, the stack sends a ``SYN`` segment. To simplify the scripts, we have configured the stack to use a ``MSS`` of 1000 bytes and disabled the TCP extensions (the details of this configuration may be found at the beginning of the script). The server replies with a ``SYN+ACK`` and the stack sends acknowledges it to finish the three-way-handshake.
Let us first use packetdrill_ to explore the evolution of the TCP retransmission timeout. The value of this timeout is set based on the measured round-trip-time and its variance. When the retransmission timer expires, TCP doubles the retransmission timer. This exponential backoff mechanism is important to ensure that TCP slowdowns during very severe congestion periods. We use the ``tcpi_rto`` variable from ``TCP_INFO`` to track the evolution of the retransmission timer. This script is available from :download:`/exercises/packetdrill_scripts/rto.pkt`.
Let us now explore the impact of congestion on the slow-start and congestion avoidance mechanisms. Consider the scenario below. For graphical reasons, it is not possible anymore to show information about the segments on the graph, but you can easily infer them.
Let us start with a very simple example that uses packetdrill_ to open a TCP connection on a server running on the Linux kernel. A packetdrill_ script is a sequence of lines that are executed one after the other. There are three main types of lines in a packetdrill_ script.
Let us start with the execution of a system call. A simple example is shown below.
More complex scenarios can be written. The script below demonstrates how the TCP stack behaves when three segments are lost. This script is available from :download:`/exercises/packetdrill_scripts/frr-rto2.pkt`.
On Linux, most of the parameters to tune the TCP stack are accessible via :manpage:`sysctl`. These parameters are briefly described in https://github.com/torvalds/linux/blob/master/Documentation/networking/ip-sysctl.txt and in the :manpage:`tcp` manpage. Each script sets some of these configuration variables.
Open questions
Our last scenario is when the first segment sent is lost. In this case, two round-trip-times are required to retransmit the missing segment and recover from the loss. This script is available from :download:`/exercises/packetdrill_scripts/slow-start-frr3.pkt`.
Packet capture tools like tcpdump_ and Wireshark_ are very useful to observe the segments that transport protocols exchange. TCP is a complex protocol that has evolved a lot since its first specification :rfc:`793`. TCP includes a large number of heuristics that influence the reaction of a TCP implementation to various types of events. A TCP implementation interacts with the application through the ``socket`` API.
packetdrill_ can also inject data that will be read by the stack as shown by the lines below.
packetdrill_ compares a packet transmitted by the instrumented Linux kernel with the packet that the script expects
packetdrill_ executes a system call and verifies its return value
packetdrill_ injects [#ftcpdump_pdrill]_ a packet in the instrumented Linux kernel as if it were received from the network
packetdrill_ injects the ``FIN`` segment and the instrumented kernel returns an acknowledgment. If packetdrill_ issues the :manpage:`close` system call, the kernel will send a ``FIN`` segment to terminate the connection. packetdrill_ injects an acknowledgment to confirm the end of the connection.
packetdrill_ is a TCP test suite that was designed to develop unit tests to verify the correct operation of a TCP implementation. A more detailed description of packetdrill_ may be found in [CCB+2013]_. packetdrill_ uses a syntax which is a mix between the C language and the tcpdump_ syntax. To understand the operation of packetdrill_, we first discuss several examples. The TCP implementation in the Linux kernel supports all the recent TCP extensions to improve its performance. For pedagogical reasons, we disable [#fsysctl]_ most of these extensions to use a simple TCP stack. packetdrill_ can be easily installed on recent Linux kernels [#finstall]_.
packetdrill_ requires root privileges since it inject raw IP packets. The easiest way to install it is to use a virtualbox image with a Linux kernel 4.x or 5.x. You can clone its git repository from https://github.com/google/packetdrill and follow the instructions in https://github.com/google/packetdrill/tree/master/gtests/net/packetdrill. The packetdrill_ scripts used in this section are available from https://github.com/cnp3/ebook/tree/master/exercises/packetdrill_scripts