EECS 489 PA4: Link-Rate Virtualization
This assignment is due on Monday,
18 April 2016, 5 pm.
Overview
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)
- Link-rate virtualization (60 pts)
- Client 1: Weighted-fair queueing (Lab 8) (25 pts)
- Client 2: FIFO with rate control using token-bucket filter (Lab 7) (15 pts)
- 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.
Assumptions
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:
- Your platform and its version -
Linux, Mac OS X, or Windows.
- Anything about your implementation that is noteworthy.
- Feedback on the assignment.
- 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.
General
The
General Advice section from PA1 applies. Please review it if
you haven't read it or would like to refresh your memory.