CS 43 Lab 5: Reliable Transport

Due: Thursday, November 16, 11:59 PM


Handy references:


Lab Audio
Lab Audio, Day 2

For this lab, you'll be designing and implementing reliable data transfer over an unreliable (simulated) link. Your submission will be in the form of a library that mimics the type of functionality that you would expect to get from an OS's transport-layer implementation.

Your transport protocol should be a stop-and-wait protocol for now. We'll introduce high-performance pipelining features in lab 6.

Requirements

  1. You must use C to implement your library code, and the underlying transport that it uses to transfer messages must be UDP. TCP would give you reliability, which would obviously defeat the purpose...

  2. You should build a stop-and-wait style of protocol that works even when links have very small packet buffers (e.g., size 2 packets).

  3. The example code includes a test application that sits above your library and uses it to transfer a file. You may edit the test application for your own testing, but when grading, I will use the default version, so do not rely on changes to these files for correct operation. Your library (lab5.h and lab5.c) should allow any application that's built on top of it to achieve reliable communication. When transferring files with your library, you should get byte-for-byte identical copies. Use diff, md5sum, etc. to veryify that everything is transferred properly.

  4. As a part of your implementation of reliability, you'll need to perform RTT estimation to determine how you should set timeout values. You should use an EWMA-based mechanism like TCP does. The library function my_rtt() should always return your library's current estimate of the RTT. Normally you wouldn't export such information up to the application/user, but I'll use this to check your RTT calculation.

    Like TCP, you should compute your timeout as a function of the current RTT estimate, sampling only those segments for which no retransmission is necessary. If a timeout occurs, you should double the timeout for each subsequent retransmission of the same segment.

  5. Your implementation should cleanly shut down connections on both ends, even if packets get lost. You do NOT need to implement the TCP behavior that allows each side to shutdown independently. TCP is substantially more complex than the protocol you're building because your protocol is unidirectional. Like TCP though, in my_close(), you may want to wait for some time, to make sure the last ACK didn't get lost (leaving one end hanging).

    You should NOT rely on ICMP error messages to help your closing procedure. To be safe, it's best to disable ICMP from both hosts before starting the sender and receiver with:

    iptables -I OUTPUT -p icmp -j DROP

  6. You should provide a brief (~1/2 - 1 page) description of the testing and debugging strategy you used to convince yourself that the protocol you've implemented is correct. If you encountered major hurdles, what were they, and how did you solve the problem?

Environment - Setup

For this lab, we'll be using an emulation package called mininet to create virtual links that allow us to vary their performance characteristics (latency, loss rate, etc.). Because it requires special permissions to execute, we'll be running it inside of a virtual machine. The VM image will NOT fit in your home directory, so you'll need to work in /local, which is the local hard disk of the machine you're using.

Storing things on /local has two major implications that you need to account for:

  1. The data on /local is stored on a single disk (unlike your home directory, which is split across multiple disks for redundancy). When you're done working, you should save your important lab files elsewhere (e.g., push them to github) to avoid data loss in the event of a disk failure. When you're done working on your VM, you should shut it down nicely: "sudo shutdown -h now"
  2. The /local partition on each machine is only available on that machine. This means that if you want to move and work a different machine, you'll need to set up a new VM at the new location. You could also copy your VM image from /local on one machine to /local on another with scp.

To get started, you'll need to import a copy of the starter VM image:

  1. Run virtualbox in a terminal or open it from within your favorite graphical menu.
  2. Go to File->Preferences, set your "Default Machine Folder" to "/local", and then close the preferences window.
  3. Go to File->Import Applicance. Choose: /local/CS43-Mininet-VM.ovf and push next once.
  4. You should now be seeing "Appliance settings". Edit the name to include your username. For example, CS43-Mininet-VM-kwebb.
  5. Click import and wait a minute for it to complete.

After you've completed these steps, you should see the your VM in the list of VMs available to start. Go ahead and turn it on.

While you could work from within the new VM window that just came up, doing so is a huge pain if you enjoy nice things like graphical interfaces. Instead, it's much easier to connect to the VM via ssh with X11 forwarding turned on. The VM is already configured such that you can connect to it by sshing to your local machine on port 22222. (Port 22222 on your machine gets forwarded to port 22 on the VM):

ssh -Y localhost -p 22222 -l mininet
(The password is: mininet)

Before going any further, you should use the passwd command to set a new password to protect your VM. After that, you'll need to configure an SSH key so that you can access GitHub. You have to options:

  1. Create a new key for the VM and add it to your GitHub account. (Instructions)
  2. Copy your existing ssh key from your CS account to the VM (e.g., with scp).

Environment - Mininet

Once you've connected to the VM, you can run mininet:
  1. From your terminal that's ssh'ed to the VM, run mininet, and tell it to create a minimal network topology with two hosts connected to a switch with 10ms latency on each link, 5% packet loss on each link, and a buffer of size 2. Note that there is no space between parameters:
    sudo mn --link tc,delay='10ms',loss=5,max_queue_size=2 -x
    This will pop up four terminal windows: one for each of the two hosts (h1 and h2), one for the switch (s1), and one for a controller (c0). Close the controller and switch terminals, you won't be using those for this lab. All the operations you perform within these windows are as if you were ssh'ed to two lab machines. They work independently like different machines but share the same files. If you run 'ifconfig' on each of them, you'll see that h1 has an IP address of 10.0.0.1 and h2 has 10.0.0.2. You should be able to transmit data between the two. Test that by running the ping command at h1:
    ping 10.0.0.2
    You should see a (round trip time) delay of ~40 ms with approximately a 19% loss rate (each link has an independent 5% chance of dropping a packet). You'll find the example code in the lab5 directory, which is shared between the VM and each of the fake hosts.

  2. Edit/execute code and work on the lab. You'll want to periodically make a backup of your changes (push to GitHub), since the VM image is stored on the machine's local disk. If the disk fails, you don't want to lose your changes...

  3. When you're done, you can tell the VM to shutdown by executing:
    sudo shutdown -h now

Grading Rubric

This assignment is worth five points.

Tips

If you have any questions about the lab requirements or specification, please post on Piazza.

Submitting

Please remove any debugging output prior to submitting.

Please do not submit output file(s) that you used in testing.

To submit your code, simply commit your changes locally using git add and git commit. Then run git push while in your lab directory.