Try   HackMD

Β« Back to the main CSCI1680 website

Project 2: IP 🐦

Due October 24, 2022 at 11:59PM EST

Introduction

In this assignment you will be constructing a Virtual IP Network by using UDP to simulate a link layer, IP forwarding, and dynamic routing. Each node will be configured with its (virtual) links at startup and enable you to enable/disable those links at run time. From there, you will build a routing protocol to dynamically update the nodes' forwarding tables by exchanging information about available routes across your virtual network.

Beyond just teaching you about IP and routing, this project is designed to teach you how to build and work at different layers of abstraction –- both in terms of networking and in software design. On the networking side, you will deal with encapsulating data inside IP packets (and, in our next project, TCP packets). On the softare side, you will build abstractions to realize the components of the virtual network and define interfaces to interact with them. In your next project, you will build on these interfaces to implement TCP –- essentially building your own networking stack!

Warning: Do not leave this project until the last minute. This project can be tricky and a lot of it is about design. The best way to stay on top of it is to start working on your design early so that you have opportunities to ask questions. At the start of the project, you will have a milestone design meeting with a TA to encourage you to plan your design. You should ask questions now if in doubt about anything. Start talking with your partner right away, and get ready to get connected!

Teamwork

This is a 2-person assignment. To form a group, you should fill out the group assignment form, located here.

If you prefer to work with a specific person, you can indicate it on the form –- both students on a team should fill out the form, and only mutual requests will be honored. Otherwise, we will match each student to a partner based on their language preferences, in-person/remote status, time zones, and so on.

Once the groups are set, you'll be assigned a mentor TA to help you through this project and the next, TCP. TCP will build on this project, so your effort on your IP design will pay off twice.

Capstone students: If you are using this class to fulfill your capstone requirement, you will need to complete either of two extra components. If both students are taking the class as a capstone, both capstone components must be completed.

Development Environment

You can continue to use the course container for development, which you can also use to run Wireshark. Wireshark will be incredibly helpful in both IP and TCP, as it allows you to observe network traffic in real-time to debug your work.

If you had issues using the course container environment during Snowcast, either for developing code or running Wireshark, please let us know on Edstem. We are happy to help debug any issues you may encounter –- we want you to have a good workflow for development and testing!

Overview

Core Requirements

There are two main parts to this assignment:

  • The first is IP-in-UDP encapsulation, and the design of forwarding –- this includes receiving packets, delivering them locally if appropriate, or looking up a next hop destination and forwarding them.
  • The second is routing, the process of exchanging information to populate the routing tables you need for forwarding. We will do this using RIP, the Routing Information Protocol (v2), a relatively simple distance-vector routing protocol described in RFC2453. Our version of the protocol will be modified slightly from the RFC version, as described in the Routing with RIP section.

Your network will be structured as a set of cooperating processes, which we will call "nodes." Each node will essentially act like an IP router by receiving and forwarding packets between virtual "links" in our overlay network, and coordinating with other routers using RIP to exchange routing table information.

Capstone Requirements

In addition to the Core Requirements above, there is a small additional requirement for students taking this course for their capstone requirement.

The list below describes extra features to implement for this requirement. Each capstone student is required to implement one of these features. Thus, if both students in a pair are taking this course for capstone credit, then both features should to be implemented. If only one student in a pair is taking the course for capstone, only one extra feature is required.

  1. Traceroute: You will implement a subset of ICMP within your IP layer in order to build traceroute functionality. The requirements are that you should be able to report the nodes in shortest path from the current node to any other endpoint in the network. This functionality requires you to implement the ICMP Time Exceeded Message from RFC 792.
  2. Route Aggregation and Longest Prefix Match: In large networks it is necessary to aggregate the networks known to a router in order to keep the size of the routing tables reasonably small. You will be implementing a mechanism that automatically aggregates the networks a router learns from its neighbours. As a result of network aggregation, in order for your routers to route correctly you will also need to implement Longest Prefix Matching. See the implementation section for more details.

Implementation

Your implementation will consist of a program called node, which will serve as a kind of router and host in our virtual network. The core of your implementation will be a virtual "link layer" and "network layer", which together make up a framework to send IP packets over the virtual network. To do this, you will create a representation for a node's virtual "links" and an interface for how the rest of your code will send IP packets across the links. When your nodes start up, you will exchange RIP messages with your neighbors to populate your node's forwarding table. Conversely, you will also implement functionality for receiving packets destined for your node and directing them "upstream" to higher layers of your node.

Each node must also support a simple command line interface, described below, to bring links up and down, and send packets. Finally, when IP packets arrive at their destination, you will implement an interface to deliver them to an upper layer. In the next assignment, you will deliver them to your TCP implementation when appropriate. In this current assignment, you will simply print the packets out in a useful way.

Since we're building a virtual network in softare, we will implement our link layer using UDP sockets. You will then implement a virtual IP layer over these interfaces, and then build RIP as a client protocol that uses your virtual IP layer.

The following figure shows an overall architecture for the major components in a node:

The following sections describe each of the components and how they should work.

When we refer to a "link", we refer to the connection on the physical layer between two nodes. In a network using an actual physical layer, a "link" would be an Ethernet cable connecting a host to a switch, or it could be a WiFi connection. In our project, we will be using a virtual link layer to simulate these physical links between nodes.

IP-in-UDP encapsulation

You will use UDP as your link layer for this project. Each node will create an interface for every line in its links file - those interfaces will be implemented by a UDP socket. All of the virtual link layer frames it sends should be directly encapsulated as payloads of UDP packets that will be sent over these sockets. You must observe an Maximum Transfer Unit (MTU) of 1400 bytes; this means you must never send a UDP packet (link layer frame) larger than 1400 bytes.

Wait, what? Why are we putting IP packets inside UDP packets?

Normally, IP packets are wrapped in an Ethernet (link layer) frame before being sent across a physical medium. However, this requires a network driver and its functionality is implemented on the kernel level, which is not the purpose of this assignment.

Instead, we will use IP packets wrapped in UDP packets, which provides a virtual link layer abstraction that emulates link layer functionality without delving into specifics of Ethernet and the physical medium. On reliable networks (i.e. localhost), the connectionless/unreliability aspect of UDP is not a concern; thus, as an implementer, (de-)serializing packets to/from a UDP packet is the same interface as (de-)serializing to/from an Ethernet frame.

To reiterate: for this project, instead of encapsulating IP packets within Ethernet frames (which is what would actually happen in the real world, when using Ethernet as a link layer), you will encapsulate your IP packets within UDP packets. Sending these IP-in-UDP packets back and forth between the nodes in your test networks will simulate a link layer for this project and the next one (TCP).

Consider the following network topology as an example (which you will later use to test your implementation):

  • The red squares represent each node (A, B, and C)
  • The number in each red box (after the colon) is the UDP port for that host
  • The purple squares represent the interfaces for each node
  • The black lines represent the links between the interfaces on each node
  • Below each node is a table mapping each interface on that node to a virtual IP address

Similar to a real networking stack in an OS, and to keep your code clean, we require you to provide an abstract interface to your link layer rather than directly making calls on socket file descriptors from your forwarding code. For example, you could define a network interface structure containing information about a link's UDP socket and the physical IP addresses/ports associated with it, and pass these to functions which wrap around your socket calls.

We also require that you provide the functionality to activate/deactivate a link layer interface; this would be equivalent to ifconfig eth0 up/down or disabling your Ethernet/wireless card. We will use this functionality to test how your nodes exchange routing information when the topology of the network changes. See the Driver section for more information.

Forwarding

In addition, you will design a network layer that sends and receives IP packets using your link layer. Overall, your network layer will read packets from your link layer, then decide what to do with the packet: deliver it locally delivery or forward it to the next hop destination.

Definition: Next hop destination –- An adjacent node in the network through which you should send a packet so that the packet travels through the minimum number of "hops" required to reach its destination IP address.

In general, your IP forwarding process should follow the IPv4 protocol, as described in RFC791, but you are not required to implement all features of this standard (see the below description). When you receive a packet, your node must validate its checksum, inspect the destination address to determine how it should be processed, and (if necessary) forward it to the appropriate next hop.

Your IP packets must use the standard IPv4 header format, described in Section 3.1 of RFC791. When forwarding, you must decrement the packet's TTL value and recompute its checksum. You can use a starting TTL value of 16, which is more than sufficient for all the networks we will test in this assignment.

Some utilities exist in each language for working with IP headers:

  • In Go, the supplemental net package contains an IP packet header struct.
  • In C/C++, a struct for the IP packet header is available in /usr/include/netinet/ip.h as struct ip.
  • In Rust, the etherparse crate provides an IP packet header struct.

Your node is NOT required to support advanced IP features such as fragmentation or IP options. In addition, all other IP advanced header fields (IP Identification, Type of Service, flags) may be set to zero when you generate packets, as we will do not use any of these features. However, even though your node does not support these features, your design should be able to receive these packets and act on them in a sensible way. For example, you are not required to send packets with IP options, but you must be able to accept packets with options (since you can simply ignore the options). Similarly, you are not required to send fragmented packets, or implement reassembly of fragmented packets that you receive. Instead, just forward/deliver these packets normally.

Overall, your IP node must be able to interoperate with the reference node when forwarding packets. Make sure you test your node in networks that contain the reference node. As you work to implement forwarding, remember that you have Wireshark to help you! You can use Wireshark to view the contents of your IP packets (and those sent by the reference node) to make sure they are formatted properly.

Lab 1 and the class lecture videos has more information on how to use Wireshark to inspect your IP packets. In addition, we provide a custom RIP dissector for our custom protocol. As always, feel free to post Wireshark related questions on EdStem.

Interface to higher layers

You will need an interface between your network layer and the "upper layers" of your program that will process the packets. Thus, you must design and implement an interface that allows an upper layer to register a handler for a given protocol number, determined by a packet's IP protocol field. In this project, we will require support for two IP protocols:

  • Routing Information Protocol (RIP): some of your packets need to be handed off to a RIP handler, which will take care of maintaining a routing table. RIP's IP protocol value is 200.
  • Test Protocol: other packets, which we will call "test packets", will be sent using the send command. Your test protocol hanlder simply needs to print out the packet's content; see the Driver section for more details. The test protocol's IP protocol value is 0.

In the next project, we will add support for TCP.

An example of how you might go about doing this in each language:

in C/C++

For some some_data_t,

typedef void (*handler_t)(some_data_t *, struct ip *);

void net_register_handler(uint8_t protocol_num, handler_t handler);
in Go

One potential type definition could be

type HandlerFunc = func(*Packet, []interface{})

where []interface{} contains data that a handler could need.

in Rust

This one is a little trickier; one potential type might be

type Handler = Arc<Mutex<dyn FnMut(IPPacket) -> Result<()> + Send>>;

Alternatively, you could create a trait with a corresponding register function:

pub trait Handler: Send {
    fn handle_packet(&self, packet: IpPacket);
}

pub fn register<H: Handler + 'static>(table: &mut HandlerTable, protocol: u8, handler: H) {...}

For example, for RIP packets, the RIP packet should be the payload for the IP packet. As a protocol, an RIP handler should be able to be registered with the following in order to receive incoming packets with an IP protocol field of 200:

RegisterHandler(200, RIPHandler) RegisterHandler(0, TestPacketHandler)

Likewise, RIP as a protocol should be able to send packets over a particular interface through IP. Keep in mind that this will require a clean abstraction of your link layer interfaces.

Even without a working RIP implementation, you should be able to run and test simple forwarding, and local packet delivery. Try creating a static network (hard code it, read from a route table, etc.) and make sure that your code works. Send data from one node to another one that requires some amount of forwarding. Integration will go much smoother this way.

Routing with RIP

One part of this assignment is to implement routing using a modified version of RIP protocol, which is defined by RFC2453. We will discuss the RIP protocol in detail during class within the first week of the assignment's release. You can also read more about the RIP protocol in Sections 13.1–13.2 of the Dordal textbook or in Section 4.2.2 of the Peterson textbook.

RIP message format

Our version of RIP uses a slightly modified packet structure. You must adhere to the following packet format for exchanging RIP information:

uint16 command;
uint16 num_entries;
struct {
    uint32 cost;
    uint32 address;
    uint32 mask;
} entries[num_entries];
If you are using C or C++

If you are writing in C or C++, consider using flexible array members to allocate space within your packet data.

The RIP message fields must adhere to the following:

  • command will be 1 for a request of routing information, and 2 for a response
  • num_entries will not exceed 64 (and must be 0 for a request command)
  • cost will not exceed 16; here, we define INFINITY to be 16
  • address will be an IPv4 address
  • mask is a bitmask to denote the size of the network

Note: In the standard version of the assignment, all routing entries will refer to single IP addresses and thus will use a mask of 255.255.255.255 (ie. all 1's) to denote a /32. If you are implementing link aggregation (a capstone only requirement), you will adjust the mask based on how you decide to represent each network.

As with all network protocols, all fields must be sent on the wire in network byte order.

In the standard version of RIP, packets are typically sent to routers via UDP. In our version, RIP messages are sent directly inside our (virtual) IP packets, using IP protocol 200.

RIP operation

Once a node comes online, it must send a request on each of its interfaces. Each node must send periodic updates to all of its interfaces every 5 seconds.

Definition: Periodic update –- This is an update sent out regularly by each node in the network to all of its adjacent nodes. The update should contain the entries in the node's routing table.

Note that each node should include itself in its routing table –- what do you think the number of hops would be for this entry?

A routing entry should expire if it has not been refreshed in 12 seconds (though when testing your project, feel free to make these times longer if it assists with using a debugger). If a link goes down, then the network should be able to recover by finding different routes to nodes that went through that link.

You must implement split horizon with poisoned reverse, as well as triggered updates.

Definition: Split Horizon with Poisoned Reverse –- Split horizon enforces that a node does not send any new routing information to nodes from which they got the information; this prevents route instability and infinite loops. For example, if a node A receives a route to node C from node B, in the RIP response, A does not advertise the route to C through B.

Split horizon with poisoned reverse is a variant wherein a router advertises "unreachability" (i.e. a cost of INFINITY) instead of not responding. In the above example, A would advertise a route to C with a cost of INFINITY, rather than not sending the route back to B.

More information can be found in the RIP RFC.

Definition: Triggered updates –- The content that your nodes must send out on these updates is similar to the content for periodic updates (i.e. it should contain entries in your routing table). However, these updates should only be sent when the node's routing table is updated, and should only include the updated entries, not the entire table.

Driver

Your driver program, node, will be used to demonstrate all features of the system. You must support the following commands within a command line interface.

Command Description
interfaces, li Prints information about each interface, one per line.
interfaces <file>, li <file> Print information about each interface, one per line, to the destination file. Overrides the file if it exists.
routes, lr Print information about the route to each known destination, one per line.
routes <file>, lr <file> Print information about the route to each known destination, one per line, to the destination file. Overwrites the file if it exists.
down <integer> Bring an interface with ID <integer> "down".
up <integer> Bring an interface with ID <integer> "up" (it must be an existing interface, probably one you brought down).
send <vip> <proto> <string>                                                                                                       Send an IP packet with protocol <proto> (an integer) to the virtual IP address <vip> (dotted quad notation). The payload is simply the characters of <string> (as in Snowcast, do not null-terminate this).
q Quit the node by cleaning up used resources.

Output formats: To be compatible with the autograder, we require that your interfaces/li, routes/lr (and the corresponding print to file commands), and receiving send values print to stdout and adhere to the following format:

interfaces/li

The printed interfaces must be the following format, sorted by increasing order by id:

id    state        local        remote        port
<id0> <state>   <local VIP>   <remote VIP>   <port>

For example, node B from ABC.net must have the following result from li at startup:

id  state    local       remote      port
0    up    192.168.0.2  192.168.0.1  5000
1    up    192.168.0.3  192.168.0.4  5002

Note: The specific amount of whitespace between columns does not matter, but please ensure that there is at least one space between each column, and that each entry has no extraneous spaces.

routes/lr

The printed routes must be the following format:

dest            next        cost
<dest VIP>  <next hop VIP> <cost>

For example, upon stabilizing routes in the ABC.net, node A should have the following routes (not necessarily in order):

dest               next       cost
192.168.0.1     192.168.0.1    0
192.168.0.2     192.168.0.2    1
192.168.0.3     192.168.0.2    1
192.168.0.4     192.168.0.2    2  

As with interfaces/li, the specific whitespace does not matter, but please ensure that each column is separated by at least one space.

Receiving send <VIP> 0 <STRING>

Upon receiving a packet for the test protocol (0), your node must print the result in the following format:

---Node received packet!---
        source IP      : <source VIP>
        destination IP : <destination VIP>
        protocol       : 0
        payload length : <len>
        payload        : <msg>
---------------------------

For example, on ABC.net, a call to send 192.168.0.2 0 Vim is better than Emacs from node A should result in the following printed message from node B:

---Node received packet!---
        source IP      : 192.168.0.1
        destination IP : 192.168.0.2
        protocol       : 0
        payload length : 24
        payload        : Vim is better than Emacs
---------------------------

For compatibility, a colon (:) is required between the field name and the value of the field. The amount whitespace between field name and the colon, or the value and the colon, does not matter.


You should feel free to add any additional commands to help you debug or demo your system, but the above the commands are required. It would be to your advantage to add bandwidth-intensive test commands to help prepare your implementation for TCP.

Traceroute (Capstone Only)

Your driver should include the following command for demonstrating traceroute:

traceroute <vip>

Which should print out the sequence of hops in the following format: <hop num> <vip>. So an example output would be:

Traceroute from 192.168.0.2 to 192.168.0.5
    1 192.168.0.2
    2 192.168.0.8
    3 192.168.0.5
    Traceroute finished in 3 hops

From the driver command, we should be able to see changes in the path when any node in the network is brought up or down. If a host is not in the network, or is unreachable, you should print that information.

Route Aggregation and Longest Prefix Match (Capstone Only)

Every router you create in this project represents a single local IP address. In contrast, real world routers represent networks that are attached directly to them. Therefore in this project you will implement a relaxed version of route aggregation:

  • All the networks (a single address is a network with mask 255.255.255.255) learned from a specific neighboring router can be aggregated to the smallest network which contains all the learned networks. You can safely assume that networks this will be tested on will have IP addresses allocated in a manner that conforms to the topology.
  • The distance metric of the aggregated network will be equal to the shortest distance from the aggregated routes.

These relaxations will lead to cases where the routers behaviour will diverge from what is otherwise considered correct behaviour: a router may forward a packet whose destination is a "hole" in the network (a target address that is part of the network, but does not exist in any node), and the distance metric may be incorrect for some of the nodes in the network (when aggregating we use the shortest distance, leading to some nodes to appear closer than they are).

Apart from these cases, a driver implemeting route aggregation MUST behave correctly, therefore Longest Prefix Matching is necessary.

Note: The reference node does not implement route aggregation. Do not run the reference node while testing your own implementation for this step, as it will not propagate your messages correctly.

Getting Started

Once teams are defined, you will be assigned a Github classroom link to create a repository for your team. In the meantime, you can view the template repo here.

Don't try to fork this repository yet –- we will send you a personalized link to create your repository once teams are defined. You can use this if you want to play with the reference node in the meantime, though.

Once your teams are made, it's time to design and code!

The files you will need to start up your network are available in your GitHub repository, and are described in detail below. We have defined serveral virtual topologies to test your implementation, which are called <network>.net. You are welcome to use these topologies, or write new ones –- see the Sample Networks section below for information on the topologies we provide.

We also include a script net2lnx, which reads a topology file (.net) and creates a "links file" for each node, called <node>.lnx, that specifies the virtual links and IPs for only that node.

Once you have links files for each node, you can run your process –- which must be called node –- for each virtual node, which must accept a .lnx file as its first argument on the command line. An example invocation would be:

node <linksfile>

If you wanted to start up nodes A and B, for example, you would run in a first terminal:

node A.lnx

And then in another terminal:

node B.lnx

Once all nodes in your network are running, you can list routes and send packets!

Note: A good way to test your implementation is by running it against the reference nodes. Additionally, you can run the reference nodes against each other to figure out expected behaviour, which can be useful for both planning and debugging. To run a reference node on a particular .lnx file, simply run:

./ref_node <lnx file>

Makefile

Similar to Snowcast, please include a Makefile such that make builds your project and places the node binary in the top-level directory of your repository.

Support Executables

  • tools/ref_node –- The reference node that your implementation should be able to communicate with.
  • tools/net2lnx –- A tool to convert a .net file into a series of .lnx files that each node can read separately.

Note: If you are using an M1 Mac, you should use the versions of these binaries in the tools/arm64 directory –- these binaries are compiled for your CPU architecture.

Utilities

For C/C++

If you are using C, we have provided several utility files with useful functions in utils directory:

  • Debugging: dbg.c, dbg.h. Print colored debugging messages. You can enable and disable categories of messages based on the environment variable DBG_MODES. See node.c for an example of how to use them in your code. By default, node enables only error messages. If you want to enable only, say, net layer and routing messages, then you can run:
    ​​​​DBG_MODES=net,route ./node file.lnx
    
    See dbg_modes.h for a full list of debugging modes –- feel free to add your own!
  • parseLinks: parseLinks.c, parseLinks.c; implementation of parsing the lnx file. Feel free to use this directly, or modify it if you like.
  • A linked list and hash table implementation are available here. You can find examples for how to use each of these in this repo in the examples directory.

In addition, you can find a C code example that outlines a structure for the driver's command-line parsing using readline here. The readline library provides some helpful features for implementing a command line (like pressing the up key to get your last command).

For Go

For logging, Go's log package is a pretty standard logging package you could use. For more structured logging, zap and zerolog are handy.

The experimental net package (specifically, the Header struct within the ipv4 subpackage) may be a good starting point for IP parsing.

For Rust

The rustyline crate provides a Rust implementation of GNU readline; you may find it useful in creating a REPL.

etherparse provides a bunch of utilities for working with IP packet headers (e.g. serde, checksum computation, etc).

If you are using Go or Rust, feel free to use other external packages that provide similar features for logging, command line parsing, etc. If you have questions about whether a library is acceptable, just ask!

Sample Networks

These are found in the nets/ subdirectory.

  1. ABC.net - Simple network with three nodes, connected as follows:

    ​​​​A ---- B ---- C
    ​​​​node A localhost
    ​​​​node B localhost
    ​​​​node C localhost
    ​​​​A <-> B
    ​​​​B <-> C
    

    This tells you the physical location of each node and how they are connected. After running net2lnx on it, you will have something that looks like:

    ​​​​A.lnx:
    ​​​​localhost 5000
    ​​​​localhost 5001 192.168.0.1 192.168.0.2
    ​​​​
    ​​​​B.lnx:
    ​​​​localhost 5001
    ​​​​localhost 5000 192.168.0.2 192.168.0.1
    ​​​​localhost 5002 192.168.0.3 192.168.0.4
    ​​​​
    ​​​​C.lnx:
    ​​​​localhost 5002
    ​​​​localhost 5001 192.168.0.4 192.168.0.3
    

    You can feed this to each node as its link information. For instance, A.lnx indicates that A listens on localhost port 5000 and has one link to B, which listens on localhost and port 5001. A's IP on this interface is 192.168.0.1. It is connected to another interface with virtual IP 192.168.0.2 (which is provided by B).

  2. loop.net - More complicated network with the following shape:

    ​​​​src -- srcR --  short  -- dstR -- dst
    ​​​​        |                   |
    ​​​​        \-- long1 -- long2 -/
    

    A useful test for routing is to start up this network and make sure packets sent from src to dst go through short. Then, bring the short node down and see what happens.

    If routing is working correctly, you should see that packets sent from src are now delivered to dst through long1 and long2.

Getting Help

This project has a large scope, but we don't intend for it to be painful –- we have provided a number of resources to help you, and we are always happy to answer questions. To start, make sure you have read this handout and really understand what we mean about using UDP to simulate your link layer. Edstem is always a good place to get help on general topics, and the TAs will, of course, be holding TA hours and scheduling appointments.

Collaboration

Make sure that you work together with your group partner to share the workload. It will not be possible for you to go off into separate rooms, implement your half, and "just hook them up." We recommend designing the core components of your work as a team, such as the layer interfaces and the forwarding table. After you have defined your interfaces and tested some of the low-level components, you might divide up additional work on the link layer interface and RIP, but you can do whatever you feel is appropriate.

We request you use Git well so that you can update each other periodically (commit often, but only when the build succeeds!).

Here are a couple of lectures from cs0060 (offered in 2019) on using Git:

However, please note that your Git repos should be private, and you are not allowed to share code with other groups. You are welcome to talk to other groups about concepts, algorithms, etc., but each group's code must be their own.

Mentor TAs

Each group will have a member of the course staff (TA or instructor) assigned as their mentor. You'll need to set up a milestone appointment to meet with your mentor TA during the first week of the project to discuss your project's design. Once you have approval, you should stay in contact with your mentor, who will ultimately grade your work. Your mentor also will do their best to help answer questions about, debugging, discussing design, etc., but you should feel free to ask questions of any member of the course staff - just because your mentor is helping you out, however, does not mean that they are at your beck and call. Understand that the we (the course staff) are busy too!

Grading

Milestone - 20%

You will schedule a milestone design meeting with your mentor TA by Tuesday, October 11th at the latest. An announcement will be made on EdStem with instructions on how to schedule –- we will be creating meeting slots in the week leading up to the milestone deadline. At this milestone, you should have a design for your program and be ready to ask about any areas where you have questions.

For this meeting, you should commit something to your repo to demonstrate your design to us –- this could be some data structure definitions, interface designs for the different layers, diagrams, etc. We aren't going to constrain you with requirements here, but we urge you to use the time before your meeting wisely and plan what you want to show us, and have questions. The feedback you receive will pay off for your implementation.

More concretely, as you think about your design and prepare for the meeting, be ready to answer specific questions about your design, for instance:

  • What objects will you use to abstract link layers, and what interface will it have?
  • What fields in the IP packet are read to determine when to forward a packet?
  • What will you do with a packet destined for local delivery (ie, destination IP == your node's IP)?
  • What structures will you use to store routing information?
  • What happens on your node when the topology changes? In other words, when links go up down, how are forwarding and routing affected?

Functionality - 65%

Most of your grade will be based on how well your program conforms to our specification. As in the Snowcast project, you will be expected to interoperate with the reference implementation. Among other details, your program will be expected to maintain forwarding tables, handle packet forwarding, network loops, and maintain interfaces that may go up or down at any time without causing the network to crash. We will release further specifics on the functionality grade breakdown as we finalize the IP autograder.

Note that as with Snowcast, your grade will always be determined by a human. We will read both your code and your test output (and, if necessary, test manually) to verify that your work meets the requirements for each test, and apply partial credit as necessary. We will do most of our grading interactively by meeting with you and talking about your work (see below). Automated testing is designed to help you test your code out before the deadline and check for common issues, in addition to reducing some of the grading workload.

Code Quality - 10%

Because part of the specification prescribes the programming interfaces for the link layer and for the upper layer handlers to IP, we will be evaluating the design of those interfaces as well as general code quality.

README - 5%

Please include a README that describes your design decisions, including:

  • How you abstract your link layer and its interfaces
  • The thread model for your RIP implementation
  • The steps you will need to process IP packets

You should also list any known bugs or notable design decisions in your README. If you identify known bugs and include a description of how you have attempted to fix the bug/where you think the bug originates from in your code, we will take off fewer points than if we have to find them ourselves.

In your README, please also note whether you developed your work using the container environment or on the department machines, and any instructions necessary to build your project.

Handing In and Interactive Grading

Once you have completed the project you should commit and push your work to the main branch of your Git repo to deliver your code. On the grading server, add your repository URL under the "Project 2: IP" section. Click on the β€œProject 2: IP” button to initiate a fetch of your repository from GitHub.

Note: If your GitHub account is not linked to your Brown email address, the grading server will give you a command to run to verify your repository.

Once you see your repo, enter your partner's email or GitHub username in the "Partner" field.

We will primarily grade your projects interactively –- after the deadline, your team will meet with your mentor to demonstrate the functionality of your program and grade the majority of it. Between the time you've handed in and the demo meeting, you can continue to make minor tweaks and bug fixes. However, you shouldn't be making any major changes; the version you've handed in should be nearly complete since it could be referenced for portions of the grading.