| 8 | |
| 9 | This tutorial assumes that a 4 nodes topology has been already established in one of the Orbit sandboxes: |
| 10 | |
| 11 | {{{ |
| 12 | #!sh |
| 13 | Host (GUID 101) ---- MFR1 (GUID 1) ---- MFR2 (GUID 2) ---- Host2 (GUID 102) |
| 14 | }}} |
| 15 | |
| 16 | [[CollapsibleStart(If not coming from the previous experiment follow these instructions to setup your network)]] |
| 17 | |
| 18 | Once logged into the grid console: |
| 19 | |
| 20 | {{{ |
| 21 | #!sh |
| 22 | |
| 23 | Command to access??? |
| 24 | }}} |
| 25 | |
| 26 | From the console we will start by loading the Mobilityfirst image into the four nodes that have been assigned to you: |
| 27 | |
| 28 | {{{ |
| 29 | #!sh |
| 30 | |
| 31 | omf load -i 'mf-release-latest.ndz' -t system:topo:mf-groupX |
| 32 | }}} |
| 33 | |
| 34 | '''system:topo:mf-groupX''' represents the group of 4 nodes and '''mf-groupX''' has to be replaced by the group id assigned to you. |
| 35 | |
| 36 | For example, '''mf-group1''' will load the image on nodes 'node1-1,node1-2,node2-1,node2-2' |
| 37 | |
| 38 | If the output of your console looks similar to: |
| 39 | |
| 40 | {{{ |
| 41 | #!sh |
| 42 | |
| 43 | INFO exp: ----------------------------- |
| 44 | INFO exp: Imaging Process Done |
| 45 | INFO exp: 4 nodes successfully imaged - Topology saved in '/tmp/pxe_slice-2014-10-15t02.10.16.594-04.00-topo-success.rb' |
| 46 | INFO exp: ----------------------------- |
| 47 | INFO EXPERIMENT_DONE: Event triggered. Starting the associated tasks. |
| 48 | INFO NodeHandler: |
| 49 | INFO NodeHandler: Shutting down experiment, please wait... |
| 50 | INFO NodeHandler: |
| 51 | INFO NodeHandler: Shutdown flag is set - Turning Off the resources |
| 52 | INFO run: Experiment pxe_slice-2014-10-15t02.10.16.594-04.00 finished after 1:50 |
| 53 | }}} |
| 54 | |
| 55 | your nodes have been imaged correctly. |
| 56 | |
| 57 | === Deploy Network === |
| 58 | |
| 59 | Software and experiment control in the ORBIT testbed can be automated greatly using the OMF framework. An OMF control script is written in Ruby and allows the experimenter to specify the set of nodes, their network configuration, to specify software components and arguments, and to control their execution on one or more nodes. We will use an OMF script to bring up 4 ORBIT nodes to host our topology, with corresponding software components. |
| 60 | |
| 61 | We will first introduce the main details of the scripts that will be run and then will step to the execution itself. |
| 62 | |
| 63 | ==== Software Component Specification ==== |
| 64 | |
| 65 | The following snippet shows the specification of the MobilityFirst router along with the required arguments: |
| 66 | |
| 67 | {{{ |
| 68 | #!ruby |
| 69 | |
| 70 | defApplication('MF-Router', 'router') {|app| |
| 71 | app.shortDescription = "Click-based MobilityFirst Access Router" |
| 72 | app.path = "/usr/local/src/mobilityfirst/eval/orbit/tutorial/scripts/ARWrapper.sh" |
| 73 | # click options |
| 74 | app.defProperty('num_threads', 'number of threads', "-t",{:type => :integer, :mandatory => true, :default => 4, :order => 1}) |
| 75 | app.defProperty('ctrl_port', 'port for Click control socket', "-c",{:type => :integer, :order => 2}) |
| 76 | # click config file |
| 77 | app.defProperty('config_file', 'Click configuration file', "-C",{:type => :string,:mandatory=> true}) |
| 78 | # keyword parameters used in click config file |
| 79 | app.defProperty('my_GUID', 'router GUID', "-m",{:type => :string, :mandatory => true}) |
| 80 | app.defProperty('topo_file', 'path to topology file', "-f",{:type => :string, :mandatory => true}) |
| 81 | app.defProperty('core_dev', 'core network interface', "-d",{:type => :string,:mandatory => true}) |
| 82 | app.defProperty('GNRS_server_ip', 'IP of local GNRS server', "-s",{:type => :string,:mandatory => true}) |
| 83 | app.defProperty('GNRS_server_port', 'Port of GNRS server', "-p",{:type => :string,:mandatory => true}) |
| 84 | app.defProperty('GNRS_listen_ip', 'IP to listen for GNRS response', "-i",{:type => :string,:default => "0.0.0.0"}) |
| 85 | app.defProperty('GNRS_listen_port', 'port to listen for GNRS response', "-P",{:type => :string,:default => "10001"}) |
| 86 | app.defProperty('edge_dev', 'edge network interface', "-D",{:type => :string,:mandatory => true}) |
| 87 | app.defProperty('edge_dev_ip', 'IP assigned to edge interface', "-I",{:type => :string,:mandatory => true}) |
| 88 | } |
| 89 | |
| 90 | defApplication('MF-GNRS', 'gnrs') {|app| |
| 91 | app.shortDescription = "GNRS Server" |
| 92 | app.path = "/usr/local/src/mobilityfirst/eval/orbit/tutorial/scripts/GNRSWrapper.sh" |
| 93 | app.defProperty('log4j_config_file', 'log 4j configuration file', "-d",{:type => :string, :order => 1}) |
| 94 | app.defProperty('jar_file', 'server jar file with all dependencies', "-j" ,{:type => :string, :mandatory=> true, :default => "/usr/local/src/mobilityfirst/gnrs/jserver/target/gnrs-server-1.0.0-SNAPSHOT-jar-with-dependencies.jar", :order => 2}) |
| 95 | app.defProperty('config_file', 'server configuration file', "-c",{:type => :string, :mandatory=> true, :order => 3}) |
| 96 | } |
| 97 | |
| 98 | #Enable OML reporting by default |
| 99 | defApplication('MF-HostStack', 'hoststack') {|app| |
| 100 | app.shortDescription = "MF host network stack" |
| 101 | app.path = "/usr/local/bin/mfstack" |
| 102 | app.defProperty('log_level', 'log level', nil,{:type => :string, :mandatory => true, :order => 1, :default => "-e"}) # default is 'error' |
| 103 | app.defProperty('config_file', 'stack configuration file', nil,{:type => :string, :mandatory => true, :order => 2}) |
| 104 | } |
| 105 | }}} |
| 106 | |
| 107 | As seen above, the router is configured with both 'core' and 'edge' interfaces. The core interfaces connect routers towards the core of the network, while the edge interface enables hosts to connect and access the MobilityFirst network. |
| 108 | |
| 109 | Also seen above is the GNRS service related arguments that specify which server (IP and port) the router should use for in-network name resolution purpose, both for sending requests and to receive responses. By default it will listen on all interfaces and port 10001. |
| 110 | |
| 111 | ==== Setting up the Software Node Groups ==== |
| 112 | |
| 113 | The following shows how the node groups for the routers are setup in the OMF control scripts. Node groups allows experimenters to use single statements to set configuration and execute commands across all nodes in the group. |
| 114 | |
| 115 | {{{ |
| 116 | #!ruby |
| 117 | |
| 118 | for i in 1..num_routers |
| 119 | defTopology("topo:router_#{i}") { |t| |
| 120 | aNode = routersTopo.getNodeByIndex(i-1) |
| 121 | t.addNode(aNode) |
| 122 | info aNode, " assigned role of router with GUID: #{i}" |
| 123 | } |
| 124 | |
| 125 | defGroup("router_#{i}", "topo:router_#{i}") {|node| |
| 126 | node.addApplication('MF-Router') {|app| |
| 127 | app.setProperty('num_threads', router_threads) |
| 128 | app.setProperty('config_file', click_conf) |
| 129 | app.setProperty('my_GUID', router_guid[i-1]) |
| 130 | app.setProperty('topo_file', rtr_topo_file) |
| 131 | app.setProperty('core_dev', core_dev) |
| 132 | app.setProperty('GNRS_server_ip', GNRS_server_ip) |
| 133 | app.setProperty('GNRS_server_port', GNRS_server_port) |
| 134 | app.setProperty('GNRS_listen_ip', "192.168.100.#{i}") |
| 135 | app.setProperty('GNRS_listen_port', GNRS_listen_port) |
| 136 | app.setProperty('edge_dev', edge_dev) |
| 137 | app.setProperty('edge_dev_ip', router_ether_if_ip[i-1]) |
| 138 | } |
| 139 | |
| 140 | #If is the first router add the GNRS |
| 141 | if i == 1 |
| 142 | aNode = routersTopo.getNodeByIndex(i-1) |
| 143 | info aNode, " will also host the GNRS server" |
| 144 | node.addApplication('MF-GNRS') {|app| |
| 145 | app.setProperty('log4j_config_file', GNRS_log_file) |
| 146 | app.setProperty('jar_file', GNRS_jar_file) |
| 147 | app.setProperty('config_file', GNRS_conf_file) |
| 148 | } |
| 149 | end |
| 150 | |
| 151 | node.net.e0.ip = "192.168.100.#{i}" |
| 152 | node.net.e0.netmask = '255.255.255.0' |
| 153 | |
| 154 | node.net.w0.mode = "adhoc" |
| 155 | node.net.w0.type = 'g' |
| 156 | node.net.w0.channel = "11" |
| 157 | node.net.w0.essid = "SSID_group_#{i}" |
| 158 | node.net.w0.ip = "192.168.#{i}.1" |
| 159 | } |
| 160 | end |
| 161 | |
| 162 | #Create host groups |
| 163 | for i in 1..num_hosts |
| 164 | defTopology("topo:host_#{i}") { |t| |
| 165 | aNode = hostsTopo.getNodeByIndex(i-1) |
| 166 | t.addNode(aNode) |
| 167 | info aNode, " assigned role of client with GUID: #{100 + i}" |
| 168 | } |
| 169 | |
| 170 | defGroup("host_#{i}", "topo:host_#{i}") {|node| |
| 171 | node.addApplication('MF-HostStack') {|app| |
| 172 | app.setProperty('config_file', hoststack_conf_file[i-1]) |
| 173 | app.setProperty('log_level', log_level) |
| 174 | } |
| 175 | |
| 176 | #node.net.e0.ip = "192.168.#{i}.#{i+100}" |
| 177 | #node.net.e0.netmask = '255.255.255.0' |
| 178 | |
| 179 | node.net.w0.mode = "adhoc" |
| 180 | node.net.w0.type = 'g' |
| 181 | node.net.w0.channel = "11" |
| 182 | node.net.w0.essid = "SSID_group_#{i}" |
| 183 | node.net.w0.ip = "192.168.#{i}.2" |
| 184 | } |
| 185 | end |
| 186 | }}} |
| 187 | |
| 188 | [[CollapsibleEnd]] |
| 189 | |
| 190 | Here is where I have to place snippets from the previous part |