Computer Laboratory

Building an Internet Router

Integrating with the Hardware

Overview

In this portion of the project you will be integrating your router with the hardware. Your software router will configure the hardware via reading/writing registers, and send/receive packets through raw sockets bound to the card’s interfaces. You will be responsible for modifying your router to communicate through the hardware registers and adding the necessary CLI support for accessing registers.


Getting Started

For this part of the project you will abandon the VNS framework. Your router server software will run on the machine physically connected to the NetFPGA board and communicate with the board using a driver. In order to make your router run in “cpu” mode, you will have to recompile it using the -D_CPUMODE_ flag (currently commented out in the Makefile). On startup, a router in cpu mode will expect a hardware information file, cpuhw, in the current directory. This file provides the interface information for the router, instead of receiving it from VNS. The provided base code reads cpuhw and calls your sr_integ_add_interface(…) for every interface it finds. An entry in this file should list the interface name, IP address, mask and MAC:

eth0 192.168.0.1 255.255.255.255 00:ba:d0:ca:fe:00
eth1 192.168.1.1 255.255.255.255 00:ba:d0:ca:fe:01
eth2 192.168.2.1 255.255.255.255 00:ba:d0:ca:fe:02
eth3 192.168.3.1 255.255.255.255 00:ba:d0:ca:fe:03

You will want to supply a static routing table file (details below). A connection to the board may look something like:

$ ./sr -r my_rtable

Once connected, you should be able to access the hardware registers and if implemented correctly, send and receive packets as before. In a nutshell, the hardware supports eight packet channels. Four channels for the Ethernet ports (e-ports) and four matching CPU channels (c-ports). An incoming packet on an e-port will be routed to any one of the eight channels, according to the entries in the routing table. If it is routed to a c-port, the software will be able to read it in. To send a packet out from software, write it to the appropriate c-port and it will automatically be forwarded to the matching e-port and sent out.

The static rtable file should either be empty, or contain a single default gateway entry, ie:

$ cat rtable
0.0.0.0 192.168.0.100 0.0.0.0 eth0

Note that in this example, eth0 corresponds to port 0 on the NetFPGA.

Instead of sending and receiving packets through VNS, you will be responsible for reading them from raw sockets. Below is some starter code to help you bind to the sockets. After binding you are responsible for reading and writing packets to the sockets using your choice of methods.

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/netdevice.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>

char iface_name[32] = "nf2c";
int i;
for (i = 0; i < 4; ++i) {
	sprintf(&(iface_name[4]), "%i", base+i);
	int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

	struct ifreq ifr;
	bzero(&ifr, sizeof(struct ifreq));
	strncpy(ifr.ifr_ifrn.ifrn_name, iface_name, IFNAMSIZ);
	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
	        perror("ioctl SIOCGIFINDEX");
	        exit(1);
	}

	struct sockaddr_ll saddr;
	bzero(&saddr, sizeof(struct sockaddr_ll));
	saddr.sll_family = AF_PACKET;
	saddr.sll_protocol = htons(ETH_P_ALL);
	saddr.sll_ifindex = ifr.ifr_ifru.ifru_ivalue;

	if (bind(s, (struct sockaddr*)(&saddr), sizeof(saddr)) < 0) {
        	perror("bind error");
	        exit(1);
	}

	// Do something with s here!!
}

To control the router, ie configure the routing table, etc., you will read and write 32 bit chunks of data to the card through well defined interfaces that will take as parameters: a structure representing the card, an address to read/write from, and a variable to read the data from or write it to. The addresses for these operations are specified in reg_defines.h.

Register reads and writes will be handled by two provided functions, readReg(…) and writeReg(…).


Functionality you must Support

The software portion of the router is responsible for the following:

  • setting the MAC addresses on the card
  • setting the IP address filters on the card
  • responding to ARP requests
  • sending ARP requests
  • updating entries in the hardware ARP cache
  • timing out entries in the hardware ARP cache
  • queuing packets pending ARP replies
  • responding to ICMP echo requests
  • generating ICMP host unreachable packets
  • handling corrupted or otherwise incorrect IP packets
  • building the forwarding table via a dynamic routing protocol
  • handling all packets addressed directly to the router

Your router should already support much of the functionality listed. You will need to extend your implementation to be able to configure the hardware tables to mirror the software data-structures which can be considered the “master copies”.


Implementation Hints

  • You might find it helpful to extend your CLI to be able to read and write the hardware registers. This can be invaluable for debugging, as it enables you to determine the status of all registers at run-time. Similarly you may want to extend show ip route, show ip arp and show ip interface (show cpu ip route?) to dump out the hardware tables.
  • You will likely not be able to telnet directly into your router for this portion of the project. We suggest that you link your CLI code against the socket libraries on your development machine and then bind locally. This way you can telnet to “localhost” on your development machine and drive your router via the CLI.
  • We will provide you with a .bin file of the “golden” hardware solution to test against. In order to use this you will have to configure the interfaces with your allocated MAC and IP addresses.
  • When you first start the software you will want to empty all the hardware tables and registers on the card so you start from a clean slate. You can execute the command:

    writeReg(&your_netfpga_struct, CPCI_REG_CTRL, 0x00010100);

    which will trigger the reset signal on the card. It is also a good idea to sleep for a small period of time after the reset before sending commands to the card (eg. usleep(2000)). CPCI_REG_CTRL is defined in nf2.h.

  • When writing your routing table to hardware, ensure that it is written in longest to shortest prefix order, as (at least in the reference implementation) hardware will assume the first match is the longest prefix and route your packet based on that match.

Deliverables

For this milestone you will again submit your router source and update your design document to cover your approach to handling register read/write and operating with the hardware. Be sure to describe and extra extensions to the CLI you’ve added for debugging/testing. We should be able to configure the hardware reference correctly using your router.