ICS 451 Assignment 10:
IPv6 Router Simulation

Assigned March 31st, to be completed by April 14th.

Turn in this assignment by e-mailing to jmoroney@hawaii.edu your code specified below.

You may do this assignment in groups of up to three.

This assignment asks you to implement two programs, both similar to the two programs in assignment 9. You may re-use and adapt any code anyone on your team created for assignment 9.

The first program creates an IPv6 ping (echo request) packet and sends it to your second program. Your second program forwards packets according to its routing table, either dropping them, or forwarding them to another router (another instance of the same program). Your routing program should also print what happens with each received program, i.e. forwarded or dropped.

As in assignment 9, the routing tables for this assignment are static and specified in the command-line arguments, so you do not need to implement any routing protocol, or indeed, even a routing table.

  1. Creating an ICMPv6 ping packet
  2. Write a C program, pinggen6, to create and send a valid ICMPv6 echo request packet. This packet begins with a valid IPv6 header as in Assignment 9, followed by the byte 128 (echo request), three bytes of zero (this sends the checksum as zero). The next two bytes are an identifier selected by your program (the process ID returned by getpid is suitable). The following two-bytes are a sequence number (increasing from 0). This may optionally be followed by 8 bytes of time obtained from gettimeofday.

    pinggen6 takes four command-line arguments: a local and a remote port number and two IPv6 addresses. It then creates a socket, binds it to the local port number, creates a packet as described above, and sends it to ::1 (localhost) at the remote UDP port number given on the command line. That is, you are sending the IPv6 packet (consisting of an IPv6 header and ICMPv6 content) over IPv6 and UDP to your router6 program described below.

    After sending the packet, pinggen6 reads from the socket and prints any packets it receives.

    For example,

       $ ./pinggen6  9876  12345  1:2:3::4  5:6:7:8:9:a:b:c
    

    creates a packet with an IPv6 header with source address 1:2:3::4 (the same as 1:2:3:0:0:0:0:4) and destination address 5:6:7:8:9:a:b:c, and an ICMP echo request payload as described above. It sends this packet to the IPv6 localhost address (::1) from UDP port 9876 to UDP port 12345, then listens for any incoming messages on UDP port 9876.

    Testing pinggen6

    The pinggen6 program may be tested against itself. For this, you will need two windows, and run the following commands, one in each of the two windows.

       $ ./pinggen6  9876  12345  1:2:3::4  9:8:7::6
    
       $ ./pinggen6  12345  9876  9:8:7::6  1:2:3::4
    

    If your pinggen6 command works correctly, the second call should deliver a packet to the program running in the first window.

  3. Routing and Forwarding
  4. For this assignment, and as in assignment 9, the routing table will be specified as a series of command-line arguments, each of the form:

    destination/gateway/mask/interface
    

    Each such argument is used to build a routing table entry, in the order given on the command line.

    Command-line arguments are also used to specify the router's interfaces and IP addresses:

    +interface/local-IPv6/mask/my-UDP-port/peer-UDP-port
    

    These interface definitions begin with the character "+" and include:

    1. the name of the interface (used when forwarding packets -- must match the interface name specified in the route, and is at most 100 characters)
    2. the IPv6 address configured for this interface
    3. the corresponding netmask, a number between 0 and 128 inclusive
    4. the local UDP port on which this interface will bind and listen for incoming packets
    5. the remote UDP port on ::1 to which this interface will send packets

    The two types of arguments may be provided in any order on the command line. Only the order of the routing table entries is significant.

    To listen on different interfaces (i.e. receive from different sockets bound to different UDP port numbers), your program must have either multiple threads (recommended, but slightly harder), or multiple processes (slightly easier). Multiple threads are created with pthread_create, multiple processes with fork. If you use pthreads, you may need to link your code with -lpthread, e.g.

    cc -o router6 router6.c -lpthread
    

    Example

    I am going to simulate a simple network with two hosts and two routers. Each router has two interfaces, one connected to the host, the other to the other router.

    This simple network needs three IPv6 network numbers. I will use 2001:2:3:4::/64, 2002:3:4:5::/64, and 2003:4:5:6::/64.

    To run these four programs at the same time, I will open 4 different windows, and run one of these commands in each of the windows:

       $ ./router6  +eth0/2001:2:3:4::1/64/12345/9876  2001:2:3:4::/2001:2:3:4::2/64/eth0  +eth1/2002:3:4:5::1/64/12346/12347  2002:3:4:5::/2002:3:4:5::2/64/eth1  2003:4:5:6::/2002:3:4:5::2/64/eth1
    
       $ ./router6  +eth0/2002:3:4:5::2/64/12347/12346  2002:3:4:5::/2002:3:4:5::1/64/eth0  +eth1/2003:4:5:6::1/64/12348/9875  2003:4:5:6::/2003:4:5:6::2/64/eth1  2001:2:3:4::/2002:3:4:5::1/64/eth0
    
       $ ./pinggen6  9876  12345  2001:2:3:4::2  2003:4:5:6::2
    
       $ ./pinggen6  9875  12348  2003:4:5:6::2  2001:2:3:4::2
    

    With these commands, the packet from the first pinggen started should be delivered from the first router to the second, and from the second router to the second host. If the second host is not yet running, the packet is dropped by UDP.

    When the second host is started, the ping travels all the way to the first host, where it is ignored (unless you have extra time and wish to do extra work, in which case you may have your code respond to the echo request with a corresponding echo reply).

    Note that the UDP port number corresponding to each simulated interface must be unique, since at most one socket can be bound to a port.

  5. After it receives each packet, your router must print exactly one line, beginning with either:
       forwarding 2001:2:3:4::2 to next hop 2002:3:4:5::1 on eth0
    
    or
       dropping 2001:2:3:4::5
    

    Either message may be followed by additional detail, such as "no route" or (optional) "Hop Limit zero".

Results

Please follow the examples above in reporting the results of your routing table lookup. This makes it easier for the TA to grade a large number of assignments.

Turn in your source code for pinggen6.c and router6.c (and any other code, e.g. header files).

Getting started on Multithreading/Multiprocessing

fork duplicates the current process, so there are two new processes running. The two processes are nearly identical -- the main difference is in the return value from fork, which is 0 in the child, and the child's process ID in the parent.

Each of your processes can independently read from one interface (a socket bound to the appropriate UDP port) and send the packet to its destination. Each process has its own copy of the command-line arguments. Because your threads/processes do not need to communicate with each other, having them as separate processes may simplify your life -- no process can influence any other process (unless both try to bind a socket to the same port!).

pthread_create creates a new thread within the current process. The thread is a C function which executes concurrently with the main thread. As a practical matter, each thread has its own local variables, but threads share global variables, including any pointers. Because of this, a bug in one thread may affect other threads. However, threads are used more frequently then processes because the shared global variables, if used appropriately, can be used for communication between the threads (communication between processes is also possible, but more cumbersome).

For this assignment, no communication is needed between different threads/processes, so both mechanisms are appropriate. However, because in programming threads are used more often than processes, you may want to gain experience using threads.

Much more information about both fork and pthread_create is available in man pages and online.

Options

If you have extra time, you are welcome to send valid ICMPv6 echo reply packets in response to valid echo request packets. See RFC 4443 for details.

If you include the time (the additional 8 bytes from gettimeofday) in the echo request, then when you receive the echo reply, you can print the resulting round-trip time. For this to work, the echo reply must have the same payload as the echo request, that is, the system generating the echo reply must copy the payload from the echo request.

You are welcome to decrement the hop limit when forwarding a packet, and drop the packet if the hop limit reaches zero. If you do this, you may want to support an optional 5th argument to pinggen6, specifying the initial hop limit (if not specified, use 64).

If you do decrement the hop limit and discard packets, you may also send destination unreachable packets back to the source. This would allow you to implement the functionality of traceroute.

You are welcome to implement checksums. Please see RFC 2460, Section 8.1 for details.



Computer Networks, ICS 451
Instructor: Edo Biagioni