Grading Policy
  Drop Box
  1. Netimg
  2. A Peer Node
  3. ImageDB
  4. DHT O(N) Case
  5. BE Netimg
  6. FEC
  7. TBF
  8. WFQ
  1. P2P Search
  2. DHT Search
  3. RDP+FEC
  4. Virtualization

Don't see the menu?

EECS 489 PA4: Link-Rate Virtualization

EECS 489 PA4: Link-Rate Virtualization

This assignment is due on Monday, 18 April 2016, 5 pm.

Plain Page for Printing


In this programming assignment, you are to implement link-rate virtualization to support two clients. The first client schedules packets onto its virtual link using weighted-fair queueing (WFQ). The second client uses first-in first-out (FIFO) scheduling with token-bucket filter (TBF) to control its transmission rate and burstiness. The first client can have one or more flows utilizing its share of the link bandwidth. To simplify the assignment, we allow only one flow to the second client. The assignment consists of the following graded tasks.

Graded tasks (100 points total)

  1. Link-rate virtualization (60 pts)
  2. Client 1: Weighted-fair queueing (Lab 8) (25 pts)
  3. Client 2: FIFO with rate control using token-bucket filter (Lab 7) (15 pts)
  4. Writeup

The specification of this assignment relies heavily on Labs 7 and 8. The support code for this assigment consists of the support codes for Labs 7 and 8. We do provide a reference implementation of the new server refvirtdb in /afs/umich.edu/class/eecs489/w16/pa4/ along with a Makefile to make virtdb. The client is the same as the client provided for Lab 7. If you have not been able to complete Lab 7 and would like the solution so that you can complete this assignment, you may choose to forfeit the 15 points associated with it and obtain a solution from us. Similarly for Lab 8, you can get the solution by forfeiting the 25 points associated with it.


No client management

Ideally, our link virtualization mechanism can support a variable number of clients. For this assignment, we bake into the code support for only two clients. One way to implement this is by refactoring the imgdb class in Labs 7 and 8 into three classes: a FIFO class, a WFQ class, and an overall imgdb class. Support for the two clients then simply requires an instantiation of the WFQ class and an instantiation of the FIFO class within the imgdb class. The command line argument -f of the provided refvirtdb can be used to specify the fraction of link bandwidth to assign to client 1 (the WFQ client). Client 2, the FIFO client, is then assigned the remainder of the link bandwidth.

No flow-setup protocol

Ideally, we have a flow-setup protocol to communicate to the link virtualization mechanism the parameters of each flow, including to which client a flow belongs. Instead, we assume that the client running the FIFO scheduler can support only one flow. The provided netimg code, from Lab 7, allows for flow setup with rate 0 (-r 0). We use this as the signalling mechanism to set up a client 2 flow. When the provided refvirtdb server receives an iqry_t packet with iq_frate set to 0, it automatically rewrites iq_frate to be the virtual link rate of client 2 and assigns the flow to client 2's FIFO scheduler. Any iqry_t packet with non-zero iq_frate is assigned to client 1 and is added to client 1's WFQ schedule, resources permitting.

No idle flow

As in Labs 7 and 8, we assume no flow ever goes idle; that is, each flow always has something to send until the end of transmission. So the service start time of each packet is the service finish time of the packet immediately preceding it.

Link-Rate Virtualization

Link-rate virtualization allocates a certain fraction of the physical link rate to a client. To the client, the virtual link so allocated should be indistinguishable from a physical link, i.e., if the client is allocated half of a 1 Gbps link, it should experience a peak transmission rate of 500 Mbps, no more, no less. Even when a physical link is not fully subscribed, a client should not experience transmission rate faster than its allocated virtual link rate.

Command line arguments

We use -f command line argument of the server to specify client 1's fraction of the link rate, which should be stored in the imgdb::frac member variable (reference default: IMGDB_INITFRAC defined in Lab 8's imgdb.h).

Server states

Refactoring the imgdb class into a WFQ class and a FIFO class and setting up two queues managed by these schedulers takes about 30 lines of code in imgdb.h (these are mostly re-shuffling and duplication of code from Labs 7 and 8).

Flow setup and transmission

In imgdb::handleqry(), if iq_frate of the incoming query packet is 0, set it to client 2's fraction of the link rate and pass the query along to client 2's FIFO query handler. Otherwise, pass it along to client 1's WFQ query handler. The FIFO query handler should check whether (1) there's at least IMGDB_MINFRAC fraction of link rate available to client 2 and (2) there's no other active flow in the FIFO queue. If either of these conditions is false, return an imsg_t packet with im_type set to NETIMG_EFULL to the client. Otherwise, initialize the flow by calling Flow::init() to load the image and setup the necessary token-bucket filter variables as in Lab 7. The WFQ query handler can pretty much re-use the flow addition code in Lab 8.

Back in imgdb::handleqry(), if a new flow has been added, update the imgdb::nflow member variable and start transmissions if the requisite number of flows have been added. (Since client 2's flow doesn't reserve a rate, we can no longer start transmission based on reserved rates reaching link rate.)

Once all the flows are added, imgdb::sendpkt() is called to transmit the next packet. When packets are transmitted back-to-back, the gap between packet i and packet i+1 is the length of packet i divided by the transmission rate. Since we assume all flows are active until they cease transmission, we simply alternate between the flows, sending the packet with the smallest transmission time first.

One way to implement this is to write a FIFO::nextxmission() and a WFQ::nextxmission() method that return the amount of time (in microseconds) until the transmission of the next packet from the FIFO and WFQ respectively. imgdb::sendpkt() then sleeps for the smaller of the two time amounts by calling usleep().

Upon waking up, imgdb::sendpkt() sends the packet with the smallest transmission time, by calling FIFO::sendpkt() or WFQ::sendpkt() as appropriate, update the transmission time of the other client's next transmission by subtracting the amount of time spent sleeping, and repeat the whole process.

You may want to have a member variable in the imgdb class to help you track the times until next transmission of both clients. You may want to initialize this variable and start the process of establishing the next packet to be transmitted in the imgdb::handleqry() function. This is arguably the only "new code" you need to write for PA4. It should be less than 30 lines total.

The function WFQ::nextxmission() comprises the first half of imgdb::sendpkt() from Lab 8 that calls Flow::nextFi() and determines the smallest finish time. Once the packet with the smallest finish time has been selected, compute the transmission time of the packet, in microseconds, given the virtual link rate (fraction of link rate) given to the WFQ and return it to the caller.

FIFO::nextxmission() comprises the Task 2 portion of imgdb::sendimg() from Lab 7. It may be convenient to call Flow::nextFi() from FIFO::nextxmission() to compute the current segment size even if we don't need to compute any finish time. Similar to WFQ::nextxmission(), in FIFO::nextxmission() we compute and return the transmission time, in microseconds, of the next packet in the FIFO queue. If the token bucket is empty and we need to accumulate tokens, include this accumulation time, also in microseconds, in the return value. In this assignment, we assume tokens are accumulated only when there is insufficient tokens left in the bucket to transmit a packet. We also assume that tokens are not accumulated during packet transmission time.

Finally, both WFQ::sendpkt() and FIFO::sendpkt() are variations on the second half of imgdb::sendpkt() from Lab 8 that calls Flow::sendpkt() and handles the accounting and cleaning up once a flow has completed transmission.

You may also want to consult the lecture notes on PA4 walk-through. Your implementation of the server must interoperate with the netimg client provided as part of Lab 7 support code.

Testing Your Code

You may want to start by testing your WFQ and FIFO queues separately. Run imgdb with -g 1 and connect a netimg client to it, with -r 0 to test the FIFO queue and -r non-zero to test the WFQ. The FIFO flow is labeled "flow -1" by refvirtdb.

The reference refvirtdb uses default link rate (-l) of 10 Mbps and default WFQ share (-f) of .5. The reference netimg client uses default flow rate (-r) of 512 Kbps.

Running the server with -g 2 should allow you to test 2 clients, each getting half of the link rate, each supporting 1 flow:

% netimg -q BlueMarble2004-08.tga -m 10240 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 0 -s localhost:<port>

Both flows should complete about the same time.

Next, specifying a smaller token bucket for the FIFO flow would let the WFQ flow to complete transmission first:

% netimg -q BlueMarble2004-08.tga -m 10240 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 0 -w 10 -s localhost:<port>

If you run the server with -g 3 -f .67, you can have the WFQ client supports 2 flows, with the FIFO client supporting 1 flow with the remaining link rate:

% netimg -q BlueMarble2004-08.tga -m 10240 -r 3430 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 3430 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 0 -s localhost:<port>

and all flows should end transmission at about the same time. In this case, the WFQ client (client 1) should receive service first (each of its flow should have a packet served first) before client 2 receives service. Why?

If you run the server with -g 4 -f .67 and four flows:

% netimg -q BlueMarble2004-08.tga -m 10240 -r 2286 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 2286 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 2286 -s localhost:<port>
% netimg -q BlueMarble2004-08.tga -m 10240 -r 0 -s localhost:<port>

the FIFO client's flow should finish first, followed by the other three flows at about the same time later. These last two scenarios show that the FIFO flow received its allocated share of the link bandwidth and we have successfully virtualized the link rate across the two clients.

And that's all the programming assignments for EECS 489. Thank you for taking the course!

Submission Instructions

As with PA1, to incorporate publicly available code in your solution or to pass off the implementation of an algorithm as that of another are both considered cheating. If you can not implement a required algorithm, you must inform the teaching staff when turning in your assignment, e.g., by documenting it in your writeup. Your solution must either work with the provided Makefile or you must provide a Makefile that works on CAEN eecs489 hosts. Do NOT use any library or compiler option that is not used in the provided Makefile. Doing so would likely make your code not portable and if we can't compile your code, you will be heavily penalized. Test your compilation on CAEN eecs489 hosts! Your submission must compile and run without errors on CAEN eecs489 hosts.

Your code MUST interoperate with the provided reference implementation.

Create a writeup in text format that discusses:

  1. Your platform and its version - Linux, Mac OS X, or Windows.
  2. Anything about your implementation that is noteworthy.
  3. Feedback on the assignment.
  4. Name the file writeup-uniqname.txt.
    For example, the person with uniqname tarukmakto would create writeup-tarukmakto.txt.
Your "PA4 files" then consists of your writeup-uniqname.txt and your source codes (imgdb.h and imgdb.cpp if you're building off the provided support code).

To turn in your PA4, upload a zipped or gzipped tarball of your PA4 files to the CTools Drop Box. Keep your own backup copy! The timestamp on your uploaded file is your time of submission. If this is past the deadline, your submission will be considered late. You are allowed multiple "submissions" without late-policy implications as long as you respect the deadline. We highly recommend that you use a private third party repository such as github or M+Box or Dropbox or Google Drive to keep the back up copy of your submission. Local timestamps can be easily altered and cannot be used to establish your files' last modification times (-10 points). Be careful to use only third-party repository that allows for private access. To put your code in publicly accessible third-party repository is an Honor Code violation.

Turn in ONLY the files you have modified. Do not turn in support code we provided that you haven't modified (-4 points). Do not turn in any binary files (object, executable, dll, library, or image files) with your assignment (-4 points). Your code must not require other compiler options, additional libraries, or header files other than the ones listed in the Makefile (-10 points).

Do remove all printf()'s or cout's and cerr's and any other logging statements you've added for debugging purposes. You should debug using a debugger, not with printf()'s. If we can't understand the output of your code, you will get zero point.


The General Advice section from PA1 applies. Please review it if you haven't read it or would like to refresh your memory.