Changes between Initial Version and Version 1 of GENIExperimenter/Tutorials/ClickExample


Ignore:
Timestamp:
03/17/13 02:36:02 (11 years ago)
Author:
nriga@bbn.com
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • GENIExperimenter/Tutorials/ClickExample

    v1 v1  
     1[[PageOutline]]
     2
     3= Example Experiment - Click Routers =
     4
     5In this example experiment, you will configure and run a non-IP software routing configuration, using the [http://read.cs.ucla.edu/click/click Click] modular router and [http://protogeni.net ProtoGENI] hosts. In this example, we'll be running click in user mode.
     6
     7Please note that you can't just cut and paste all of the commands. There are additional instructions in the text.
     8
     9== 1. Add another user to your experiment ==
     10Omni gives you the capability of giving access  to other users on your compute resources. Depending on which AM you are using to get resources from,  this is done in a different way.  Ask the team next to you about their username and do the following:
     11  i. While in a terminal, download their public key under `~/.ssh/` :
     12  {{{
     13    cd ~/.ssh
     14    wget http://www.gpolab.bbn.com/experiment-support/gec15/adv-omni/pub-keys/<username>_key.pub
     15  }}}
     16
     17  i. Follow the instructions [http://trac.gpolab.bbn.com/gcf/wiki/OmniConfigure/Manual#B1.MultipleusersinProtoGENIAMs these instructions] and add another user for ProtoGENI AMs
     18
     19== 1. Create your experiment ==
     20In this step, we are going to setup the experiment. In this tutorial we assume that you are sufficiently comfortable with omni to verify that a '''listresources''' command works and to know when your slice is ready using '''sliverstatus'''.
     21  i. '''Create a slice''', use the slicename given to you in the paper slip:
     22  {{{
     23omni.py createslice <slicename>
     24}}}
     25  i. '''Create a sliver''' using the rspec from the URL given in your paper slip:
     26  {{{
     27omni.py createsliver -a pg-utah <slicename> <rspec_url>
     28}}}
     29  i. '''Check the status of your sliver'''
     30  {{{
     31omni.py sliverstatus -a pg-utah <slicename>
     32}}}
     33
     34== 2. Install scripts ==
     35While you wait for your sliver to become ready, we will see how we can automate the installation of our experiment with install scripts.
     36In this experiment we are going to use software routers in order to write our own forwarding scheme. This means that in any experiment we are going to run we want the basic installation of the software router to always be present. The configuration might change from run to run, but the software should always be installed. The software to be installed, and the scripts to be executed at boot time, are defined in the rspecs. Follow these steps to locate your install script and identify the different parts.
     37  i. Download your rspec
     38  {{{
     39   cd /tmp
     40   wget <rspec_url>
     41}}}
     42  i. Open your rspec and look for the `install` tag and copy the value of the URL attribute.
     43  i. Download and untar the software
     44  {{{
     45  cd /tmp
     46  wget <software_url>
     47  tar xvfz <software_name>
     48}}}
     49  i. Look in your rspec and locate the `execute` tag. Note what script is being executed at boot time.
     50  i. Locate the script and open it. Can you identify the different parts?
     51
     52== 3. Configure your routers ==
     53Once our sliver is ready we will go ahead and configure our click routers. In this example we have 4 routers, so instead of logging into each one of them and configuring it, we are going to use remote execution and configure them from our VM.
     54
     55First lets reset our environment:
     56{{{
     57cd
     58rm .ssh/config
     59touch .ssh/config
     60}}}
     61
     62=== 3a. Login and remote execution ===
     63Run the `readyToLogin.py` script to get information about logging in to nodes. The script has a lot of output so lets put that in a file so that we can easily search for the information we want.
     64
     65{{{
     66readyToLogin.py -a pg-utah <slicename> > login.out 2>&1
     67}}}
     68
     69You'll get a big chunk of information, but you're interested in the '''ssh configuration info''' information near the end.
     70
     71{{{
     72... <lots of output> ...
     73================================================================================
     74SSH CONFIGURATION INFO for User inki
     75================================================================================
     76 
     77Host left
     78  Port 30778
     79  HostName pc403.emulab.net
     80  User inki
     81  IdentityFile /home/geni/.ssh/geni_key
     82
     83Host hostB
     84  Port 30779
     85  HostName pc490.emulab.net
     86  User inki
     87  IdentityFile /home/geni/.ssh/geni_key
     88
     89Host hostA
     90  Port 30778
     91  HostName pc545.emulab.net
     92  User inki
     93  IdentityFile /home/geni/.ssh/geni_key
     94
     95Host bottom
     96  Port 30778
     97  HostName pc490.emulab.net
     98  User inki
     99  IdentityFile /home/geni/.ssh/geni_key
     100 
     101Host right
     102  Port 30778
     103  HostName pc411.emulab.net
     104  User inki
     105  IdentityFile /home/geni/.ssh/geni_key
     106 
     107Host top
     108  Port 30779
     109  HostName pc545.emulab.net
     110  User inki
     111  IdentityFile /home/geni/.ssh/geni_key
     112
     113...<more output>...
     114}}}
     115
     116Copy all the above information and paste it into your `.ssh/config` file, then you can very easily login into your nodes, just by using the nickname (client_id) of the nodes.
     117
     118Your `~/.ssh/config` file should look like
     119{{{
     120IdentityFile /home/geni/.ssh/geni_key
     121Host left
     122  Port 30778
     123  HostName pc403.emulab.net
     124  User inki
     125  IdentityFile /home/geni/.ssh/geni_key
     126 
     127Host hostB
     128  Port 30779
     129  HostName pc490.emulab.net
     130  User inki
     131  IdentityFile /home/geni/.ssh/geni_key
     132
     133Host hostA
     134  Port 30778
     135  HostName pc545.emulab.net
     136  User inki
     137  IdentityFile /home/geni/.ssh/geni_key
     138
     139Host bottom
     140  Port 30778
     141  HostName pc490.emulab.net
     142  User inki
     143  IdentityFile /home/geni/.ssh/geni_key
     144
     145Host right
     146  Port 30778
     147  HostName pc411.emulab.net
     148  User inki
     149  IdentityFile /home/geni/.ssh/geni_key
     150
     151Host top
     152  Port 30779
     153  HostName pc545.emulab.net
     154  User inki
     155  IdentityFile /home/geni/.ssh/geni_key
     156
     157}}}
     158
     159Let's login to our two hosts, the nicknames are `hostA` and `hostB`
     160  i. Open two new terminals
     161  i. In one terminal type
     162  {{{
     163  ssh -A hostA
     164  }}}
     165  and in the other
     166  {{{
     167  ssh -A hostB
     168  }}}
     169==== Test remote execution ====
     170You can execute commands in a remote host using `ssh`. To do this just follow your ssh command with the command you want to execute in quotes.
     171  i. In your local terminal type :
     172  {{{
     173  ssh -A top "ls -a"
     174  }}}
     175  This will list all the files under the home directory on host `top`. The output should look like:
     176  {{{
     177geni@geni-VirtualBox:~$ ssh -A top "ls -a"
     178.
     179..
     180.bash_logout
     181.bash_profile
     182.bashrc
     183.forward
     184.kshrc
     185.ssh
     186.zshrc
     187  }}}
     188
     189If you get something similar you are all set for controlling your nodes from your computer.
     190
     191=== 3b. Configure your routers ===
     192We are going to use remote execution to configure our routers.
     193  i. On a local terminal run the following command four times, each time substituting the <router_nickname> with one of the top, bottom, left, right:
     194  {{{
     195  geni@geni-VirtualBox:~$ ssh -A <router_nickname> "/local/click-example/extractClickConfig.py "
     196  }}}
     197  You'll get output something like this:
     198  {{{
     199Your host information:
     200        hostA: hostA.StupidSliceName.emulab-net.emulab.net pc347.emulab.net
     201        top: top.StupidSliceName.emulab-net.emulab.net pc336.emulab.net
     202        left: left.StupidSliceName.emulab-net.emulab.net pc358.emulab.net
     203        right: right.StupidSliceName.emulab-net.emulab.net pc278.emulab.net
     204        bottom: bottom.StupidSliceName.emulab-net.emulab.net pc348.emulab.net
     205        hostB: hostB.StupidSliceName.emulab-net.emulab.net pc353.emulab.net
     206Done.
     207}}}
     208  (If you are prompted for a password, check to make sure that you provided the -A switch in your ssh command above.)
     209
     210  i. The extractClickConfig script produces router configurations for your experiment. It also creates a diagram of your experiment. Get a copy locally from one of the routers, by typing in a local terminal:
     211  {{{
     212 scp top:myslice.png ./
     213}}}
     214  i. View the diagram by typing :
     215  {{{
     216  eog myslice.png &
     217}}}
     218  Your slice will look something like the one below (see [attachment: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.
     219
     220[[Image(myslice.png, 25%)]]
     221
     222The 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.
     223
     224== 4. Turn off internet protocol ==
     225
     226At this point, your network is still running IP. You can check by running a ping. In your '''hosta''' terminal window, run this command.
     227
     228{{{
     229ping -c 3 hostb
     230}}}
     231
     232The command should succeed, with output like this:
     233
     234{{{
     235PING hostB-link-B (10.10.6.2) 56(84) bytes of data.
     23664 bytes from hostB-link-B (10.10.6.2): icmp_seq=1 ttl=61 time=1.38 ms
     23764 bytes from hostB-link-B (10.10.6.2): icmp_seq=2 ttl=61 time=1.19 ms
     23864 bytes from hostB-link-B (10.10.6.2): icmp_seq=3 ttl=61 time=1.53 ms
     239
     240--- hostB-link-B ping statistics ---
     2413 packets transmitted, 3 received, 0% packet loss, time 2004ms
     242rtt min/avg/max/mdev = 1.193/1.370/1.531/0.138 ms
     243}}}
     244
     245Since our experiment doesn't want IP, let's turn it off :
     246  i. On a local terminal run the following command four times, each time substituting the <router_nickname> with one of the top, bottom, left, right:
     247  {{{
     248  ssh -A <router_nickname> "sh ./stopIP.sh"
     249}}}
     250
     251  You'll get output like this (the interface names may be different):
     252  {{{
     253Disabling IP on interface mv10.9
     254Disabling IP on interface mv10.10
     255}}}
     256
     257  i. Verify that IP is really off, try another ping. On '''hosta''':
     258  {{{
     259  ping -c 3 hostb
     260}}}
     261  The command should take twelve seconds to time out, then fail with output like this:
     262  {{{
     263PING hostB-link-B (10.10.6.2) 56(84) bytes of data.
     264
     265--- hostB-link-B ping statistics ---
     2663 packets transmitted, 0 received, 100% packet loss, time 11999ms
     267}}}
     268
     269== 5. Start your routers ==
     270
     271The extractor script produces a click configuration file for each of your routers. 
     272  i. On a local terminal run the following command four times, each time substituting the <router_nickname> with one of the top, bottom, left, right:
     273  {{{
     274  ssh -A <router_nickname> "sh ./startClick.sh"
     275}}}
     276  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 output of the click router is redirected to `/tmp/click.out` on each host.
     277
     278  {{{
     279Stopping any running Click routers
     280Starting Click router
     281top.click:34: While initializing ‘FromDevice@18 :: FromDevice’:
     282  warning: eth2: no IPv4 address assigned
     283top.click:35: While initializing ‘FromDevice@21 :: FromDevice’:
     284  warning: eth4: no IPv4 address assigned
     285}}}
     286
     287Congratulations! 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.
     288
     289== 6. Send some traffic ==
     290
     291Now 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.
     292  i. 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).
     293  {{{
     294[mberman@hostb ~]$ nc -ul 24565
     295}}}
     296  i. Connect to it from your terminal window on '''hostA''':
     297  {{{
     298[mberman@hosta ~]$ nc -u hostb 24565
     299}}}
     300
     301You'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.
     302
     303That's it!  Now, let's look inside to see what's going on.
     304
     305== 7. Looking under the hood ==
     306
     307Please 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.
     308
     309Let'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.)
     310
     311=== 7b. Packet transformation ===
     312
     313  i. The more interesting configuration appears here, in the '''top.click''' configuration file. In a local terminal type:
     314  {{{
     315 ssh -A top "cat top.click"
     316}}}
     317  The output will look like :
     318  {{{
     319// This portion accepts IP packets,
     320// reformats them, and routes them
     321// to an internal router.
     322route :: Classifier(27/01%01,-);
     323
     324modify :: Unstrip(2) ->
     325    StoreData(0, "AliceWasHere3546") ->
     326    route;
     327
     328FromDevice(eth3, PROMISC true) ->
     329    Classifier(12/0800) ->
     330    modify;
     331
     332route[0] -> left :: EtherEncap(0x7744, 00:04:23:b7:14:76, 00:04:23:b7:18:fa) ->
     333    SimpleQueue ->
     334    Print(outL) ->
     335    ToDevice(eth2);
     336
     337route[1] -> right :: EtherEncap(0x7744, 00:04:23:b7:1c:e0, 00:04:23:b7:19:2e) ->
     338    SimpleQueue ->
     339    Print(outR) ->
     340    ToDevice(eth4);
     341
     342// This portion accepts non-IP packets
     343// with an ether type of 0x7744
     344// from an internal router, restores
     345// them to IP format, and forwards.
     346restore :: SimpleQueue ->
     347    Strip(30) ->
     348    EtherEncap(0x800, 00:04:23:b7:14:77, 00:04:23:b7:20:00) ->
     349    ToDevice(eth3);
     350
     351FromDevice(eth2) -> Classifier(12/7744) -> Print(inL) -> restore;
     352FromDevice(eth4) ->  Classifier(12/7744) -> Print(inR) -> restore;
     353}}}
     354
     355  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''').
     356
     357  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'''.
     358
     359  The configuration for the '''bottom''' router is exactly symmetric, routing packets between '''hostB''' and the core network, but using different graffiti.
     360
     361=== 7b. Simple Forwarding ===
     362
     363The '''left''' router configuration is much simpler.  In a local terminal type:
     364{{{
     365 ssh -A left "cat left.click"
     366}}}
     367  The output will look like :
     368
     369{{{
     370// Copy packets from top to bottom.
     371FromDevice(eth2) ->
     372    StoreEtherAddress(00:04:23:b7:42:b6, dst) ->
     373    StoreEtherAddress(00:04:23:b7:18:fb, src) ->
     374    SimpleQueue ->
     375    Print(top) ->
     376    ToDevice(eth3);
     377// Copy packets from bottom to top.
     378FromDevice(eth3) ->
     379    StoreEtherAddress(00:04:23:b7:14:76, dst) ->
     380    StoreEtherAddress(00:04:23:b7:18:fa, src) ->
     381    SimpleQueue ->
     382    Print(bottom) ->
     383    ToDevice(eth2);
     384}}}
     385
     386This 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.
     387
     388=== 7c. Monitoring your core network ===
     389
     390Let's watch how the packets travel through the network.
     391  i. In a local terminal type:
     392  {{{
     393  ssh -A top "tail -f /tmp/click.log"
     394}}}
     395  i. 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:
     396  i. In the local terminal you will see:
     397  {{{
     398outR:   76 | 000423b7 192e0004 23b71ce0 7744416c 69636557 61734865
     399}}}
     400  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.
     401  i. 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.
     402
     403== 9. Clean up ==
     404
     405When you're done, please release your resources so they'll be available to others.
     406
     407{{{
     408omni.py deletesliver -a pg-utah <slicename>
     409}}}
     410
     411Now go [wiki:GEC15Agenda/AdvancedGENITopoOmni/Instructions#Wrapup back to the first page] and wrap up:-)