Due date: Tuesday, Feb 21st, 2012
In this project you will develop a link-state routing algorithm to run over several nodes. Routers typically run several routing algorithms, with link-state being one type of algorithm. In a link-state algorithm, all nodes know all other nodes and know the state (or cost) of each link between nodes. Dijkstra's algorithm is then executed with this information so that optimal paths can be calculated.
Note that link-state algorithms tend to require global knowledge--all nodes and links must be known before we can calculate the cost and paths to each node. Since all nodes know the same information, they all end up with similar routing tables and route along the same paths. In order to get this information to other nodes, we must send link-state packets to each node. If node A sends link-state packets to its neighbors, then these would consist of all the link costs from A to its neighbors and each of its neighbors. To broadcast the packet to all nodes, we use a broadcast algorithm, described below and on page 409 of the textbook under Controlled Flooding.
In this project you will use C++ since, for the most part, only smaller projects are still written purely in C.
This project will consist of a single piece: the router. The router will act as both a client and a server. All networking will be done via UDP.
When you start your program, it must read two arguments from the command line:
The routing file will consist of lines of text, each representing a neighbor and link cost as follows:
[ip address of neighbor] [port of neighbor] [link cost to neighbor]
For example:
130.253.191.26 2000 10 130.253.191.26 2001 20 130.253.191.26 2002 5 130.253.191.28 2000 30
You will obviously have to a data structure with this information in it.
Once it's configured, it will begin broadcasting link-state messages every 2 seconds. A link-state message will consist of:
[packet type]: 8 bits [ip address of source]: 32 bits [port of source]: 16 bits [sequence number]: 32 bits [ip address of neighbor]:32 bits [port of neighbor]: 16 bits [link cost to neighbor]: 16 bits ... (repeated n times for n neighbors)Note that after the first field, the source fields are of the node sending the neighbor list packet (its ip address and port number). This will allow you to simply copy the data portion of the UDP packet and send it to its neighbors.
This must be sent in binary format (i.e., you must use htons and htonl to convert properly). The first field is the packet type. For the undergraduates, this will always be set to the decimal value 1, indicating a link-state packet. You should check this value to make sure it's valid before handling the rest of the packet. Note that IPv4 addresses are 32-bit integers and ports are 16-bit integers. The link costs are also 16-bit integers. While TCP would likely require you to specify how many neighbors a node has in this link-state packet, UDP does not because we're guaranteed to get the whole message, so we know that after the first 11 bytes (for the packet type, source IP address, source port number, and sequence number), a UDP packet will increment by 8 byte chunks (which represent a neighbor). In other words, our link-state packets will be at least 19, 27, 35, ..., 11+8n bytes in size.
Sometimes the hardest part of writing socket code for the first time is simply getting started. To start in this project, you will want to:
For this project, you should use only one socket. The system is, in essence,
a peer-to-peer system, and as such, the same socket will be used for sending a receiving. In addition,
controlled-flooding will not work because when a node receives a packet, it will
not be able to tell which neighbor it came from (because all processes, and hence neighbors, are
identified by an IP address and a port number. Using additional sockets will bind
random port numbers to the sockets, and so one cannot tell which 'neighbor' the packet came from
when you call recvfrom()
.
Once you have done this, you will implement the controlled flooding algorithm. Recall as I said in class, that controlled flooding works as follows. Node A sends its link-state packet to all of its neighbors (configured by the file when the program starts). Each time it sends a link-state packet, it increments a flooding sequence number. Every node that receives the packet will either forward the packet on all other links, if the sequence number is higher than the last one it saw, or drop the packet. Again, use your computer science knowledge of data structures and store this information so that lookups are as fast as possible. You should be able to perform an O(1) lookup of the sequence number per router.
To test your implementation, you are required to log (to standard out) the output of packets being received and sent. When you send a link-state packet, you will log the following:
[local time on node] [ip address of socket] [port of socket] sent a link-state packet to [ip address of destination] [port of destination] with sequence number [seq. no.] [local time on node] contents of link-state packet: [local time on node] neighbor [ip address] [port number] [cost] (repeat for each neighbor in packet)
When you receive a link-state packet, you will log the following:
[local time on node] [ip address of socket] [port of socket] recieved a link-state packet from [ip address of destination] [port of destination] with sequence number [seq. no.] [local time on node] contents of link-state packet: [local time on node] neighbor [ip address] [port number] [cost] (repeat for each neighbor in packet)
Obviously fill in the stuff in brackets with appropriate information! At this point, you should test your flooding algorithm on several nodes, especially in a setup where there's a loop and not everyone is directly connected to each other. Note that since you're logging to standard output, if you run several processes on the same machine, this output will become intermixed. Instead either run your program in multiple windows or redirect standard output to individual files for each process.
Once you're sure that controlled flooding is working, you will need to implement Dijkstra's algorithm from the textbook. Using your computer science knowledge of data structures and algorithms, implement this algorithm as efficiently as possible. We will check your implementation to make sure you are actually implementing Dijkstra's!
Again, log each time that you complete Dijkstra's algorithm (you only need to log the final result, not each step). You will execute Dijkstra's each time new information is added to what you know about the network--this includes the addition of new nodes you didn't know about previously. You should log your routing table after the algorithm runs. The format should be as follows:
[local time on node] Dijkstra's complete, routing table: [local time on node] [destination ip address] [destination port] [cost] [forwarding address] [forwarding port] (repeat for each known node)
Follow the advice given to the undergraduates to begin. In addition, you will have one more feature to implement: packet forwarding. To implement this, you will create a new packet type:
[packet type]: 8 bits (set to 2 for the forwarding packet) [destination ip address]: 32 bits [destination ip port]: 16 bits
If your router receives one of these packets, it will look at the destination ip address and port to determine if it is local. If so, it will log:
[local time on node] forwarding packet destination [destination ip address] [destination port] received and kept!
If the packet does not belong locally, you will forward it according to your routing table. When this happens, you will log:
[local time on node] forwarding packet destination [destination ip address] [destination port] received forwarded to [next hop ip address] [next hop port number]
Note that to test this, we will write a simple program that sends forwarding packets to any of your routers and then check the logs to make sure the packet was forwarded properly. It's imperative that you use the correct format for your UDP packets so that you read these correctly and we encourage you to test this functionality out!
You will submit your source under your repository with a new directory for your project called p2. You must include a makefile or an Eclipse project to compile your source into an executable called 'router'. The naming is important because we try to automate as much as possible!