TCP for Minet
Project 2
Overview
In this part of the project, you and your partner will build
an implementation of TCP for the Minet TCP/IP stack. You will be provided with all parts of the
stack except for the TCP module. You may
implement the module in any way that you wish so long as it conforms to the
Minet API, and to the reduced TCP standard described here. However, Minet provides a considerable amount
of code, in the form of C++ classes, that you may use in your
implementation. You may also earn extra
credit by implementing additional parts of the TCP standard.
The Minet TCP/IP Stack
The Minet TCP/IP Stack is documented in a separate technical
report. The low-level details of how
Minet works, including the classes it makes available to you, the modules out
of which the stack is constructed, and how the modules interface with each
other is documented there. Of course, it
also doesn’t hurt to look at the code.
You will be given the source code to all of the Minet modules except for
tcp_module. You will find udp_module.cc
quite helpful to begin. You will also receive binaries for ip_module, reader,
and writer.
It is vital that you use the driver2.sh script in
/usr/local/bin. This program, which lets
you send and receive raw Ethernet packets, must be run as root or else it will
not work. Because we don’t want to give
you root access, we are giving you this sudo script, meaning that when you run
it, it runs as root. If you would like
to use driver2.sh on a machine outside the TLAB, you will need root privileges
on that machine.
Your IP Addresses
Each project group was assigned 255 IP addresses to use for
the rest of the quarter. These address
are of the form 10.10.x.y, where x will depend on your group id and y will
range from 1 to 255. These addresses are
special in that packets sent to them will not be forwarded beyond the local
network. In fact, if you are using
machines other than the TLAB machines, you will need to add a route so that
they actually make it to the local network.
Rebuild Minet
Update your code repository by checking out Makefile and
tcp_module.cc. The command is “cvs co
path/to/file”. Both co and checkout are
fine here. But you need to specify the path. Go to the directory where minet-netclass-w04
is listed as a sub-directory, then type:
cvs
–d /home/ychen/CVS_MINET co
minet-netclass-w04/Makefile
cvs –d /home/ychen/CVS_MINET co minet-netclass-w04/tcp_module.cc
Or you can check out the whole repository from scratch by:
cvs
–d /home/ychen/CVS_MINET co minet-netclass-w04
Now you can make the dependencies, clean, and rebuild Minet
and your project:
touch
.dependencies
make
clean
make
depend
make
project2
You’ll typically only run the last command for the remainder
of this part of the project.
Running and Testing the TCP Module
The TCP Module, which you will write in this assignment,
will be compiled as a MINET module and does not run separately. To run and test
the TCP Module, you need to start the MINET stack, which automatically starts
up the TCP Module along with various other modules as documented in the Minet
Technical Report.
To run the Minet Stack, follow the following steps:
0. Make sure you are using bash as the Unix shell. Otherwise
just run “bash”.
1. Edit the setup.sh file to change the path and Minet IP
number:
Example:
# assumes that the project 2 code is in
/home/brian/cs340/project2/minet
export PATH=/home/brian/cs340/project2/minet:$PATH
# use an IP number from the IP range assigned to your group
export MINET_IPADDR=”10.10.5.2”
2. Execute the above script by typing “source
setup.sh”. This sets up various
environmental variables and other files required by MINET to run.
3. Minet uses xterms to display its output. If you are
logged into the TLAB host remotely, make sure an X-server (e.g. xwin32 or exceed) is running on your PC
and set the DISPLAY variable appropriately.
Example:
export DISPLAY=brian.cs.northwestern.edu:0
Note: xwin32 can be downloaded from http://www.it.northwestern.edu/.
Just search for xwin32
4. Type “./go.sh” to run the Minet stack. Some xterm windows
should popup (assuming all the modules including tcp_module are compiled),
which show messages from the corresponding modules in the Minet Stack.
5. To stop the Minet stack after testing your TCP module,
type “./stop.sh”.
Testing tcp_module
To test the tcp_module, you can run the “tcp_server”
provided on your host and then use “nc” (netcat) from another machine to talk
to it. The simple version of “http_server” should also run on top of minet
stack along with “http_client” on another machine.
Example:
Assuming Minet stack is running as described in the previous
section, type
“tcp_server u 5050”. This starts the tcp_server using the
Minet stack for communication.
Now you can talk to the tcp_server from another machine
using nc:
Example:
nc 10.10.5.2 5050
Read the man page on nc for more detail.
Dedicated TLAB Machines
You may use any of the TLAB machines, either from the
console or remotely via ssh. In fact,
you’ll usually want to use two of them simultaneously. We have dedicated TLAB-09 through TLAB-14 to
running Linux for the duration of the quarter.
These machines should always be available for remote or console
login. If they are not, send mail to request@cs.northwestern.edu.
TCP Specification
The core specification for TCP is RFC 793, which you can and
should fetch from www.ietf.org. In general, you will implement TCP as defined
in that document, except for the parts listed below.
- You
only need to implement Go-Back-N
- You do
not have to support outstanding connections (i.e., an incoming connection
queue to support the listen backlog) in a passive open.
- You do
not have to implement congestion control.
- You do
not have to implement support for the URG and PSH flags, the urgent
pointer, or urgent (out-of-band) data.
- You do
not have to support TCP options.
- You do
not have to implement a keep-alive timer
- You do
not have to implement the Nagle algorithm.
- You do
not have to implement delayed acknowledgements.
- You do
not have to generate or handle ICMP errors.
- You
may assume that simultaneous opens and closes do not occur
- You
may assume that sock_module only makes valid requests (that is, you do not
have to worry about application errors)
- You
may assume that exceptional conditions such as aborts do not occur.
- You
should generate IP packets no larger than 576 bytes, and you should set
your MSS (maximum [TCP] segment size) accordingly, to 536 bytes. Notice that this is the default MSS that
TCP uses if there is no MSS option when a connection is negotiated.
Chapter 3 of your textbook also serves as an excellent
introduction to TCP concepts and should be read before the RFC. You will also find the TCP chapters in
Rick Steven’s book, “TCP/IP Illustrated, Volume 1: The Protocols” extremely
helpful. They will show you what a
working stack behaves like, down to the bytes on the wire. Make sure that you read about and understand
the TCP state transition diagram in 18.12.
Recommended
Approach
There are many ways you can approach this project. The only requirements are that you meet the
TCP specification detailed above, that your TCP module interfaces correctly to
the rest of the Minet stack, and that your code builds and works on the TLAB
machines. We recommend, however, that
you use C++ and exploit the various classes and source code available in the
Minet TCP/IP stack. Furthermore, we
recommend you take the roughly the following approach.
Important Reading
- Read
Chapter Three of your textbook
- Read
RFC 793 (Section 3 of the RFC contains
a wealth of information related to implementation) and the Stevens
chapters. The RFC contains a very detailed implementation guide for the
TCP protocol. Understanding and following that can be of great help. In
Stevens, Chapters 17, 18 and 21 (for timeouts) are especially useful. The
State Transition Diagram (Figure 18.12) summarizes the major part of
implementation in this project.
- Read
the “Minet TCP/IP Stack” handout. You will be able to understand the Minet
code and terminology better after that.
- The
code related to this assignment uses a fair bit of C++ STL and C++
templates. So getting an overview of that would be helpful. Learn about
the deque STL data structure.
Initial Phase (Understanding TCP Data
Structures)
- Fetch,
configure, and build Minet if you have not already done so. For this project, build Minet using
“make project2”. It is important
that you use /usr/bin/g++296 (g++ version 2.96).
- Examine
the code in tcp_module.cc and udp_module.cc. The TCP module is simply a stub code
that you need to flesh out. It just
connects itself into the stack at the right place and runs a typical Minet
event loop. UDP module is a bit
more fleshed out. It has almost
exactly the same interface to the IP multiplexor and to the Sock module as
your TCP module will have.
- Extend
the TCP module so that it prints arriving packets and socket
requests. You should be able to run
the stack with this basic module, send traffic to it from another machine
using netcat (nc), and see it arrive at your TCP module. You may find the classes in packet.h,
tcp.h, ip.h, and sockint.h to be useful.
Minet.h: MinetInit(), MinetDeinit(), MinetSend(), MinetReceive() –
for sending and receiving packets to and from Minet handles. Look at
Minet.h for other useful functions
packet.h : useful functions include GetPayloadLoad() – returns the
payload from the packet as a buffer, PushFrontHeader (IP header in this
project), PushBackHeader (TCP
header in this project), PopFrontHeader (retrieves the IP header),
PopBackHeader (retrieves the TCP header ), FindHeader(packettype) –
returns header in packet of packettype, packettype can be
Headers::IPHeader and Headers::TCPHeader..
buffer.h: Buffer is a very useful class. It helps you with text
buffers, like your packet payload, the IP and TCP headers. Some useful
functions are Clear(), GetSize(),
GetData( target buffer,
number of bytes, offset) – useful to retrieve part of or the entire
buffer, ExtractFront(number of
bytes) – removes n bytes from front of buffer and returns that, AddBack(buffer1) – adds contents of
buffer1 to back of caller object. You can also find other useful functions
in buffer.h
ip.h: SetProtocol(), SetSourceIP(), SetDestIP(),GetProtocol(),
GetSourceIP(), GetDestIP(),SetTotalLength(), GetHeaderLength(), GetTotalLength()
tcp.h:
SetSourcePort(),SetDestPort(),SetSeqNum(),SetAckNum(),SetHeaderLen(),SetFlags(),
SetWinSize(),RecomputeChecksum(). Set have their Get counterparts as well.
It also has useful Macros like IS_ACK, IS_FIN, SET_ACK etc.
- Now is
a good time to familiarize yourself with Minet’s various environment
variables. You should check out
what the various MINET_DISPLAY options too.
- Learn
how to use MinetGetNextEvent’s timeout feature. You will be using this to implement
TCP’s timers. There is also a timeout variable in the class
ConnectionToStateMapping (see point 10) which can be used to store the
next timeout.
- tcpstate.h
and tcpstate.cc have code representing the state of a TCP connection. Study this carefully and understand what
it contains. Think of a connection
as being a finite state machine and consider using the states described in
RFC 793. You may find the various classes in constate.h to be helpful
here. In particular, your
connection should have various timers associated with it. Your connection also has input and
output buffers associated with it.
- constate.h
has a class (ConnectionToStateMapping) that maps connection
addresses (the Connection class in sockint.h) to TCP connection
state. Familiarize yourself with that. The Connection class represents
the five tuple = (src_ip,src_port,dest_ip,dest_port, protocol). With this
you can map each new connection with a particular TCP State. There is another class ConnectionList
which can store a list (queue) of ConnectionToStateMappings. This
can be very useful to store the state and mappings of all the connections
you have open presently in one data structure. Useful functions include FindMatching(connection)
– returns the appropriate pointer if the connection is present in the
connection list. Note that ConnectionList
is implemented as the C++ STL data structure deque,
thus all its functions like push_front(), erase(), end()
etc are available as well.
Implementing TCP
Interactive Data Flow
- Add
code to your TCP module to handle incoming IP packets. Begin by adding code to handle passive
opens. Even without the Sock
module, you can test this code by using a hard-coded connection
representing a passive open. Note
that the element of time enters in here.
You will need to use one of your timers to deal with lost
packets. You may find the classes
in tcp.h and ip.h to be useful. (Passive open refers to the situation when
you receive a SYN in LISTEN state. You need to send a SYN-ACK and set a
timeout for the expected ACK from the remote side)
- It is
a good idea to write your own functions for sending and receiving IP
packets that wrap calls to Minet.
These functions can then form a framework for testing if your code
works correctly in the face of packet corruption, drops, and
reordering. You can simulate drops
by just not sending the packet with some probability. You can simulate corruption by randomly
scribbling on a packet you’re about to write with some probability. You can simulate reordering by keeping a
queue of outgoing packets and changing their order in the queue
occasionally. (MinetSend is used to send packets to the IP Layer or
the Socket Layer)
- Add
code to your TCP module to handle active opens. Again, you do not need to use the Sock
module here. You can hard code the
active open for now. (Active open corresponds to the CONNECT socket call.
You need to send a SYN to remote side, initialize your TCP variables like sequence
number and the send window variables and also set a timeout)
- Add
code to your TCP module to handle data transfer. Again, note the element of time and
think of how to implement your timers after MinetGetNextEvent
responds with a timeout event.
Remember that you do not have to implement congestion control, only
flow control. A good approach to
data transfer is first to implement a Stop-And-Wait protocol and get it
working, and then extend it to do Go-Back-N. RFC 793 has important details
on this.
- Add
code to your TCP module to handle closes.
(You receive a FIN from the remote site or a CLOSE from the socket
layer). The closing phase of TCP involves various states. See the TCP
State Transition Diagram in Stevens and RFC 793 Section 3 for details on
how to implement this part.
- At
this point, your TCP module should be able to carry on conversation with a
hard-coded partner.
Congratulations! You are
finished with the most difficult part!
Implementing
TCP-Socket Layer interface
- Re-read
the discussion of the interface between the Sock module and the TCP module
in the Minet TCP/IP Stack handout.
- Make
sure you understand the SockRequestResponse class. SockRequestResponses will advance your
connections’ state machines just like IP packets do. They will also affect the set of
outstanding connections (item 9).
- Add
code that keeps track of outstanding requests that your TCP module has
passed up to the Sock module.
Recall that the interface is asynchronous. When you send a request to Sock module,
the response may arrive at any time later.
The only guarantee is that responses will arrive in the same order
that requests were sent.
- Add
code to support the CONNECT request.
This should simply create a connection address to state mapping and
initiate an active open.
- Add
code to support the ACCEPT request.
This should simply create a connection address (with an unbound
remote side) to state mapping and initiate a passive open.
- Add
code to pass incoming connections on a passively open connection address
(one for which you have received an ACCEPT) up to the Sock module as zero
byte WRITE requests.
- Add
code to support the CLOSE request.
This should shut down the connection gracefully, and then remove
the connection
- Add
code to support the WRITE request.
This should push data into the connection’s output queue.
- Add
code to send new data up to the Sock module as WRITE requests. Note that the Sock module may refuse
such a WRITE. In such cases, the
TCP module should wait and try to resend the data later. We are currently working on a better
flow control protocol between the Sock module and the TCP module.
- Verify
that you are generating and handling STATUS requests correctly.
Testing
your tcp_module
- Now
try to use your stack with an application.
tcp_server and tcp_client should work.
- Now
you ought to be able to use your http_client and http_server1 from the
project A, simply by running it with “U” instead of “K”. The more advanced http_servers will
probably not work since the socket module’s implementation of select is
buggy. Note that while a Minet
stack currently supports only a single application, you can run multiple
Minet stacks on the same machine or on different TLAB machines to test
your code.
Extra Credit: Flow and congestion
control
For extra credit, you may implement the flow control and
congestion control parts of TCP as they are described in your textbook and in
the other sources. Please note that
while this is not much code, it does take considerable effort to get right.
Caveat Emptor
The Minet TCP/IP Stack is a work in progress. You can and will find bugs in it. There are three bugs that we are currently
aware of
- The
first IP packet sent to a new address is dropped. This is not actually a bug, but rather
an implementation decision. What’s
going on is that ip_module will drop an outgoing packet if arp_module has
no ARP entry for the destination IP address. However, arp_module will arp for the
address and so the next packet sent to the destination address will
probably find an ARP entry waiting for it.
One way to “populate” arp_module so that you don’t have to worry
about this is to ping your stack from the destination IP address.
- In
some situations, reusing connections is difficult due to a bug in the Sock
module. The work-around is to rerun
the stack on every connection. We will fix this eventually.
- The
socket module’s support for minet_select() is quite buggy, so it is highly
likely that select-based applications will not work.
We also appreciate constructive feedback and
suggestions. We plan to use Minet
extensively for teaching in the future.
Your ideas, which we will credit accordingly, can therefore have a lot
of impact.
Mechanics
·
Your code must function as a tcp_module within
the Minet TCP/IP Stack, as described in a separate, eponymous handout.
·
Your code should be written in C or C++ and must
compile and run uon the machines in the TLAB.
·
Try to confine your changes to tcp_module.cc and
new files.
·
Project 2 will be due 2/18 (Wed.) midnight
(12am). Please email your project to the
grader (not TA!) at csnetworking@isp.northwestern.edu.
You will be expected to provide tcp_module.cc and a README. If you modify our Makefile for some reason,
you should hand that in too. The README should include the names of the
project team, a brief specification of work undertaken by each member, and
anything specific about your submission that you want to inform the grader.
·
We will check the receiving timestamps of
submission emails.
·
We will expect that running “make project2” will
generate the executable tcp_module
and that this module will meet the specification described in this document and
in the “Minet TCP/IP Stack” handout.
Hints
·
In your TCP Module code, output enough DEBUG
messages, so that you can know what your TCP module is doing at each stage.
Print information about each outgoing and incoming packet.
Things That May Help You
·
RFC 793 is essential. RFC 1122 Section 4.2 has
some important errata for RFC 793.
·
Chapter 3 of your book. Section 3.5 is a good introduction to
TCP. Sections 3.6 and 3.7 are about
congestion control. You should read them,
but you do not have to implement congestion control.
·
Rick Stevens, “TCP/IP Illustrated, Volume1:
The Protocols”
·
Doug Comer, “Internetworking With TCP/IP Volume
I: Principles, Protocols, and Architecture”
·
Rick Stevens, “Advanced Programming in the Unix Environment”
·
The handout “Unix Systems Programming in a
Nutshell”
·
The handout “Make in a Nutshell”
·
The handout “The TLAB Cluster”
·
The C++ Standard Template Library. Herb Schildt’s “STL Programming From the
Ground Up” appears to be a good introduction
·
GDB, Xemacs, etc.
·
CVS (http://www.loria.fr/~molli/cvs-index.html)
is a powerful tool for managing versions of your code and helping you and your
partner avoid stepping on each other’s toes.