This experiment is obsolete, use this newer version of the Click Example Experiment.

Example Experiment - Click Routers

In this example experiment, you will configure and run a non-IP software routing configuration, using the Click modular router and ProtoGENI hosts. In this example, we'll be running click in user mode. Once you have the prerequisites in place, you should be able to complete this example experiment in under an hour.

Please note that you can't just cut and paste all of the commands. There are additional instructions in the text.


Before beginning this experiment, you should:

  • Have a GENI credential. If you don't, check out SignMeUp.
  • Configure omni (version 1.5.2 or later) on your machine. Be sufficiently comfortable with omni to verify that a listresources command works and to know when your slice is ready using sliverstatus.

Information on obtaining GENI credentials and omni is available at SignMeUp and Omni or by contacting

1. Setup

Create a new directory, click-example, on your machine. You will do the rest of your work from this directory.

mkdir click-example
cd click-example

Download the attached rspec file and save it in your click-example directory, using the name click-example.rspec. Be sure to use raw mode.

If you haven't already, add your omni source and examples directories to your PATH:

export PATH=$PATH:/path/to/gcf-1.x.x/src:/path/to/gcf-1.x.x/examples

If you haven't already, add your omni source directory to your PYTHONPATH:

export PYTHONPATH=$PYTHONPATH:/path/to/gcf-1.x.x/src

(Optional) You'll be making heavy use of your private key to log into your ProtoGENI hosts in the steps below. If your key is encrypted, you might want to take a look at ways for managing your ssh keys to make this easier.

2. Obtain your resources

Create your slice. Please don't use my stupid slice name. This example will use the Utah ProtoGENI site. You can choose a different site by selecting a different aggregate manager with the -a switch. createslice -a StupidSliceName

Create a sliver and add resources. (You changed the slice name, right?) createsliver -a StupidSliceName click-example.rspec

Wait until your sliver is ready, typically a few minutes. (You can monitor your sliver with Flack or use omni's sliverstatus command as shown below.) sliverstatus -a StupidSliceName

When your sliver is ready, run the readyToLogin script to get login information for your nodes. Use the same aggregate manager and slice name that you used for your sliverstatus command above. -a StupidSliceName

You'll get a big chunk of information, but you're interested in the ssh command information near the end.

... <lots of output> ...
Aggregate [] has a ProtoGENI sliver.'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &'s geni_status is: ready
Login using:
	xterm -e ssh -i /Users/mberman/.ssh/id_rsa &


The six lines that start with xterm -e ssh ... contain the information you need to connect to your nodes. There are six nodes in this experiment, and you will want to open a window for each. Copy and paste the commands, adding the -A switch to each ssh command as shown below. You will get six new terminal windows, one on each node of your experiment. (You should say yes if you are prompted to accept the RSA key of the remote host.)

xterm -e ssh -A -i /Users/mberman/.ssh/id_rsa &

The shell prompt in each of your new terminal windows will tell you the host name. The four routers in your experiment are named top, left, right, and bottom. The two end hosts are named hosta and hostb. You may want to rearrange the windows on your screen, putting the router hosts in the locations indicated, with the end hosts off to the side.

Tip: If you want to login to your hosts from a different host than the one you are running Omni on, take a look here for some tips about how to do this.

3. Configure your routers

In each of your four router hosts, run the extractClickConfig script as shown below.

[mberman@top ~]$ /local/click-example/ 

You'll get output something like this:

Your host information:

(If you are prompted for a password, check to make sure that you provided the -A switch in your xterm command above.)

The extractClickConfig script produces router configurations for your experiment. It also creates a diagram of your experiment. Copy it back to the click-example directory on your local host so you can view it. There's a copy on each of your router hosts. I've chosen, which is the top router, but it doesn't matter. You'll need to find the host name in the script output above, and then run this command on your local machine.

scp .

Once you have myslice.png on your local machine, open it in a browser or other viewer program. Your slice will look something like the one below (see myslice.png). The overall configuration should be the same, with two end hosts, named hostA and hostB, and four routers (top, left, right, bottom) in a diamond configuration. The host names, interface names, and MAC addresses will be different, depending on the actual resources assigned to your slice.

Click example experiment diagram

The four routers interconnected by solid lines are your "core network," which will run a non-standard, non-IP protocol. The dashed lines out to the end hosts carry standard IP traffic.

4. Turn off internet protocol

At this point, your network is still running IP. You can check by running a ping. In your hosta terminal window, run this command.

ping -c 3 hostb

The command should succeed, with output like this:

PING hostB-link-B ( 56(84) bytes of data.
64 bytes from hostB-link-B ( icmp_seq=1 ttl=61 time=1.38 ms
64 bytes from hostB-link-B ( icmp_seq=2 ttl=61 time=1.19 ms
64 bytes from hostB-link-B ( icmp_seq=3 ttl=61 time=1.53 ms

--- hostB-link-B ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 1.193/1.370/1.531/0.138 ms

Since our experiment doesn't want IP, let's turn it off. On each of your four router hosts, run this command:

sh ./

You'll get output like this (the interface names may be different):

Disabling IP on interface eth2
Disabling IP on interface eth4

To verify that IP is really off, try another ping. On hosta:

ping -c 3 hostb

The command should take twelve seconds to time out, then fail with output like this:

PING hostB-link-B ( 56(84) bytes of data.

--- hostB-link-B ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 11999ms

5. Start your routers

The extractor script produces a click configuration file for each of your routers. On each of your four router hosts, run this command:

sh ./

You'll get output like this. (Don't worry about the warning messages, Click is just reminding you that you have no IP addresses in your core network.) The shell prompt won't come back, but you'll see the debugging output of the Click router in the terminal window.

Stopping any running Click routers
Starting Click router While initializing ‘FromDevice@18 :: FromDevice’:
  warning: eth2: no IPv4 address assigned While initializing ‘FromDevice@21 :: FromDevice’:
  warning: eth4: no IPv4 address assigned

Congratulations! You are now running a non-IP core network on your four routers, along with a (primitive) non-IP multipath routing algorithm. You're ready to experiment with this configuration.

6. Send some traffic

Now you'll use your two edge hosts, hostA and hostB to send traffic along your network. Since these end hosts are not running your modified protocol, they'll rely on the top and bottom routers to transform their IP packets into your modified protocol on entry to the core network and back into IP packets on exit.

In your terminal window on hostB, instruct nc to listen for a UDP connection on port 24565 (or some other port that catches your fancy).

[mberman@hostb ~]$ nc -ul 24565

Then connect to it from your terminal window on hostA:

[mberman@hosta ~]$ nc -u hostb 24565

You've established a simple text chat connection. Enter a line of text in either window, and it should appear in the other. Of course to do this, the text is travelling through your core network, using your non-standard protocol and routing. So type a message into each window, and make sure it appears in the other.

That's it! Now, let's look inside to see what's going on.

7. Looking under the hood

Please note: the interface names and MAC addresses below are for the sample configuration shown in the figure above. You will want to refer to your network diagram to get the correct interfaces and addresses for your configuration.

Let's take a look at what's happening in the four routers in your configuration. There are two basic router configurations. (You can find all of these files on any of your router hosts.)

Packet transformation

The more interesting configuration appears here, in the configuration file.

// This portion accepts IP packets,
// reformats them, and routes them
// to an internal router.
route :: Classifier(27/01%01,-);

modify :: Unstrip(2) ->
    StoreData(0, "AliceWasHere3546") ->

FromDevice(eth3, PROMISC true) -> 
    Classifier(12/0800) ->

route[0] -> left :: EtherEncap(0x7744, 00:04:23:b7:14:76, 00:04:23:b7:18:fa) ->
    SimpleQueue ->
    Print(outL) ->

route[1] -> right :: EtherEncap(0x7744, 00:04:23:b7:1c:e0, 00:04:23:b7:19:2e) ->
    SimpleQueue ->
    Print(outR) ->

// This portion accepts non-IP packets
// with an ether type of 0x7744
// from an internal router, restores
// them to IP format, and forwards.
restore :: SimpleQueue ->
    Strip(30) ->
    EtherEncap(0x800, 00:04:23:b7:14:77, 00:04:23:b7:20:00) ->

FromDevice(eth2) -> Classifier(12/7744) -> Print(inL) -> restore;
FromDevice(eth4) ->  Classifier(12/7744) -> Print(inR) -> restore;

As indicated in the comments, the top portion of the configuration listens (FromDevice) for IP packets arriving on the interface connected to hostA (that's eth3 in this example). It then creates a new 16-byte field at the head of the packet (two bytes added by the Unstrip operation, plus the existing 14-byte Ethernet header. It fills that field with what could be important routing instructions, but in this case is just graffiti (StoreData). The route operation then routes the packet via either the left or right router toward hostB. In either case, it wraps the packet in a fresh Ethernet header (EtherEncap) with a distinctive ether type code (0x7744), logs the new packet on its way out (Print) and sends it out on the correct interface (ToDevice).

The bottom portion of the configuration is intended for packets coming out of the core network to hostA. It accepts packets from either the left or right router, logs them, strips off thirty bytes (Ethernet header plus your 16-byte new header field), puts on a fresh Ethernet header, and sends them along to hostA.

The configuration for the bottom router is exactly symmetric, routing packets between hostB and the core network, but using different graffiti.

Simple Forwarding

The left router configuration is much simpler. Here's the file:

// Copy packets from top to bottom.
FromDevice(eth2) ->
    StoreEtherAddress(00:04:23:b7:42:b6, dst) ->
    StoreEtherAddress(00:04:23:b7:18:fb, src) ->
    SimpleQueue ->
    Print(top) ->
// Copy packets from bottom to top.
FromDevice(eth3) ->
    StoreEtherAddress(00:04:23:b7:14:76, dst) ->
    StoreEtherAddress(00:04:23:b7:18:fa, src) ->
    SimpleQueue ->
    Print(bottom) ->

This configuration just blindly forwards packets. It picks up any packet from the top router, updates the Ethernet header, and passes it along to the bottom router. The same applies in the reverse direction. Again, the configuration for the right router is exactly analogous.

Monitoring your core network

Let's watch how the packets travel through the network. The terminal windows on your four router hosts show the log output from the Print statements shown above, one line per packet.

Type <enter> a few times in each router window to create a space below the existing log entries, so you can identify new log messages as they appear.

Now go to your window for hostA, where your nc command is still running. Type a message into this window. You should see a log message in three of your four router windows. In this example, you might see:

In the top router log:

outR:   76 | 000423b7 192e0004 23b71ce0 7744416c 69636557 61734865

This log entry says that the top router received a packet from hostA, modified it, and sent it out to the right router. If the entry started with outL, that would indicate that it sent the packet out to the left router. Let's look a bit at the start of the packet (the first 24 bytes are logged). It starts with an Ethernet header. The first six bytes are the MAC address of the destination interface, that's 00:04:23:B7:19:2E, the MAC address of eth4 on right. The next six bytes are the MAC address of the source interface, 00:04:23:B7:1C:E0, or eth4 on top. Next comes your ether type, 0x7744. The remaining bytes, "416c 69636557 61734865" are the start of the first field in your new protocol, "AliceWasHe" in ASCII.

Since this packet was routed to the right, there's an entry in the right router log. This entry indicates that a packet was received from top. The logged contents show the packet sent to bottom, with rewritten MAC addresses, corresponding to eth5 on bottom and eth5 on right.

top:   76 | 000423b7 42590004 23b7192f 7744416c 69636557 61734865

Finally, here's the entry on bottom:

inR:   76 | 000423b7 42590004 23b7192f 7744416c 69636557 61734865

It shows the same packet received from right. After logging, the packet is rewritten into IP and sent to hostB.

Try typing a few different lines to hostA. You should see some packets routed to the left and some to the right. The routing decision is based on the route :: Classifier(27/01%01,-); entry in the top router configuration. Here, the router is looking at the low-order bit of the checksum on the initial IP packet (now at byte position 27 with the addition of the new sixteen byte field at the start of the header). Packets with odd checksums go to the left; those with even checksums go right.

Try typing a few lines to hostB. You should see similar behavior, but starting from bottom and working up. You'll also see the different value inserted in the new header field.

8. Clean up

When you're done, please release your resources so they'll be available to others. deletesliver -a StupidSliceName

Moving forward with your experiment

This sample experiment is just a very simple demonstration of how to run a Click-based routing configuration using ProtoGENI. For a more meaningful experiment, you may want to try some of the variations described below. We'd love to hear what you're doing with Click and GENI, and we're here to help. Please let us know at

Improved routing

Instead of writing "AliceWasHere" in your packets, perhaps include some real routing instructions. Modify the Click configurations to route packets accordingly.

Richer topology

Incorporate additional hosts into a core network topology that's more interesting than a simple diamond.

Improved performance with kernel-level Click

The Click router supports kernel-level operation. The principles are the same, but the setup is a bit more involved. To use kernel-level Click, you will probably want first to develop and debug your setup at the user level. Drop us a line at for help setting up Click in kernel mode.

Wide-area routing

Modify your rspec to include some ProtoGENI hosts on the Internet2 backbone or at multiple ProtoGENI sites. Additional information available at or

Last modified 6 years ago Last modified on 05/26/17 16:13:14

Attachments (3)

Download all attachments as: .zip